Redis 缓存更新一致性
当执行写操作后,需要保证从缓存读取到的数据与数据库中持久化的数据是一致的,因此需要对缓存进行更新。
因为涉及到数据库和缓存两步操作,难以保证更新的原子性。
在设计更新策略时,我们需要考虑多个方面的问题:
- 对系统吞吐量的影响:比如更新缓存策略产生的数据库负载小于删除缓存策略的负载
- 并发安全性:并发读写时某些异常操作顺序可能造成数据不一致,如缓存中长期保存过时数据
- 更新失败的影响:若某个操作失败,如何对业务影响降到最小
- 检测和修复故障的难度: 操作失败导致的错误会在日志留下详细的记录容易检测和修复。并发问题导致的数据错误没有明显的痕迹难以发现,且在流量高峰期更容易产生并发错误产生的业务风险较大。
更新缓存有两种方式:
- 删除失效缓存: 读取时会因为未命中缓存而从数据库中读取新的数据并更新到缓存中
- 更新缓存: 直接将新的数据写入缓存覆盖过期数据
更新缓存和更新数据库有两种顺序:
- 先数据库后缓存
- 先缓存后数据库
两两组合共有四种更新策略,现在我们逐一进行分析。
并发问题通常由于后开始的线程却先完成操作导致,我们把这种现象称为“抢跑”。 下面我们逐一分析四种策略中“抢跑”带来的错误。
先更新数据库,再删除缓存
若数据库更新成功,删除缓存操作失败,则此后读到的都是缓存中过期的数据,造成不一致问题。
可能发生的并发错误:
| 时间 | 线程A | 线程B | 数据库 | 缓存 |
|---|---|---|---|---|
| 1 | 缓存失效 | v1 | null | |
| 2 | 从数据库读取v1 | v1 | null | |
| 3 | 更新数据库 | v2 | null | |
| 4 | 删除缓存 | v2 | null | |
| 5 | 写入缓存 | v2 | v1 |
先更新数据库,再更新缓存
同删除缓存策略一样,若数据库更新成功缓存更新失败则会造成数据不一致问题。
可能发生的并发错误:
| 时间 | 线程A | 线程B | 数据库 | 缓存 |
|---|---|---|---|---|
| 0 | v0 | v0 | ||
| 1 | 更新数据库为 v1 | v1 | v0 | |
| 2 | 更新数据库为 v2 | v2 | v0 | |
| 3 | 更新缓存为 v2 | v2 | v2 | |
| 4 | 更新缓存为 v1 | v2 | v1 |
当两个写线程发生冲突时,可以通过比较数据版本方式避免线程A写入旧的数据。
先删除缓存,再更新数据库
可能发生的并发错误:
| 时间 | 线程A | 线程B | 数据库 | 缓存 |
|---|---|---|---|---|
| 1 | 删除缓存 | v1 | null | |
| 2 | 缓存失效 | v1 | null | |
| 3 | 从数据库读取v1 | v1 | null | |
| 4 | 更新数据库为v2 | v2 | null | |
| 5 | 将v1写入缓存 | v2 | v1 |
先更新缓存,再更新数据库
若缓存更新成功数据库更新失败, 则此后读到的都是未持久化的数据。因为缓存中的数据是易失的,这种状态非常危险。
因为数据库因为键约束导致写入失败的可能性较高,所以这种策略风险较大。
可能发生的并发错误:
| 时间 | 线程A | 线程B | 数据库 | 缓存 |
|---|---|---|---|---|
| 0 | v0 | v0 | ||
| 1 | 更新缓存为 v1 | v0 | v1 | |
| 2 | 更新缓存为 v2 | v0 | v2 | |
| 3 | 更新数据库为 v2 | v2 | v2 | |
| 4 | 更新数据库为 v1 | v1 | v2 |
异步更新
双写更新的逻辑复杂,一致性问题较多。现在我们可以采用订阅数据库更新的方式来更新缓存。
阿里巴巴开源了mysql数据库binlog的增量订阅和消费组件 - canal。
我们可以采用API服务器只写入数据库,而另一个线程订阅数据库 binlog 增量进行缓存更新的策略。
这种策略存在和先更新数据库后删除缓存类似的并发问题:
| 时间 | 读线程 | 写线程 | 异步线程 | 数据库 | 缓存 |
|---|---|---|---|---|---|
| 1 | 缓存失效 | v1 | null | ||
| 2 | 从数据库读取v1 | v1 | null | ||
| 3 | 更新数据库为v2 | v2 | null | ||
| 4 | 删除缓存/更新缓存 | v2 | null | ||
| 5 | 写入缓存 | v2 | v1 |
这个问题同样可以采用异步线程更新缓存,且写入缓存时比较数据版本的方法来解决。
Redis 缓存更新一致性的更多相关文章
- (redis缓存更新策略)postgres 9.4.1 && redis 3.7.0 && redis_fdw_REL9_4_STABLE
首先下载redis_fdw,这里要注意下载的版本.(https://github.com/pg-redis-fdw/redis_fdw) 一开始,我下载了REL9_4_STABLE_pre2.8版本, ...
- SpringBoot缓存管理(二) 整合Redis缓存实现
SpringBoot支持的缓存组件 在SpringBoot中,数据的缓存管理存储依赖于Spring框架中cache相关的org.springframework.cache.Cache和org.spri ...
- Redis双写一致性与缓存更新策略
一.双写一致性 双写一致性,也就是说 Redis 和 mysql 数据同步 双写一致性数据同步的方案有: 1.先更新数据库,再更新缓存 这个方案一般不用: 因为当有两个请求AB先后更新数据库后,A应该 ...
- Redis缓存和数据库一致性问题
工作中,经常会遇到缓存和数据库数据一致性问题.从理论上设置过期时间,是保证最终一致性的解决方案.这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可 ...
- Redis缓存如何保证一致性
为什么使用Redis做缓存 MySQL缺点 单机连接数目有限 对数据进行写速度慢 Redis优点 内存操作数据速度快 IO复用,速度快 单线程模型,避免线程切换带来的开销,速度快 一致性问题 读数据的 ...
- Redis缓存穿透、击穿、雪崩,数据库与缓存一致性
Redis作为高性能非关系型(NoSQL)的键值对数据库,受到了广大用户的喜爱和使用,大家在项目中都用到了Redis来做数据缓存,但有些问题我们在使用中不得不考虑,其中典型的问题就是:缓存穿透.缓存雪 ...
- Redis系列十:缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
一.缓存雪崩 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而 ...
- redis缓存与数据库一致性问题
一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去. ...
- Redis缓存雪崩、缓存穿透、缓存击穿、缓存降级、缓存预热、缓存更新
Redis缓存能够有效地加速应用的读写速度,就DB来说,Redis成绩已经很惊人了,且不说memcachedb和Tokyo Cabinet之流,就说原版的memcached,速度似乎也只能达到这个级别 ...
随机推荐
- AJAX学习小结
12345678910 $.ajax({ "url":"", //访问路径 "data":"", // 需要传输的数据 ...
- 【C#】WechatPay-API-v3 使用平台证书加密内容与应答|通知验签(SHA256 with RSA)
官方暂时没有维护应答与通知签名的验证C#示例,找了些资料被困扰了一天终于调试通了,贴出来下 . 此类提供两个方法: 1.敏感信息加密,如身份证.银行卡号.(特约商户进件接口需要): 2.应答与通知签验 ...
- Spring Boot从入门到精通(五)多数据源配置实现及源码分析
多数据源配置在项目软件中是比较常见的开发需求,Spring和Spring Boot中对此都有相应的解决方案可供大家参考.在Spring Boot中,如MyBatis.JdbcTemplate以及Jpa ...
- CSS过渡、动画及变形的基本属性与运用
[逆战班] 动画可以让一个元素具有动态的效果,这个过程是使元素从一种样式变成另一个样式的过程.我们可以通过设置关键帧的方法来控制动画在某个时间节点的运动方式.通常设置多个节点来实现复杂的动画效果.0% ...
- Java入门教程九(封装继承多态)
封装 封装就是将对象的属性和方法相结合,通过方法将对象的属性和实现细节保护起来,实现对象的属性隐藏.做法就是:修改属性的可见性来限制对属性的访问,并为每个属性创建一对取值(getter)方法和赋值(s ...
- 第二章 表与指针Pro SQL Server Internal (Dmitri Korotkev)
聚集索引 聚集索引就是表中数据的物理顺序,它是按照聚集索引分类的.表只能定义一个聚集索引. 如果你要在一个有数据的堆表中创建一个聚集索引,如2-5所示,第一步要做的就是SQL服务器创建另一个根据聚集索 ...
- [Cts-Verifier]waiver-Camera-ITS-Test
[问题描述] 工具:Cts-Verifier-9.0-R11.apk 测试Camera ITS Test时,点击该测试项后verifier apk闪退.重新打开后该项未pass变绿. [问题结论] A ...
- 用canvas实现简单的下雪效果
首先新建一个html文件,将body的背景设置为天空的那种深蓝色,并创建一个canvas,canvas的操作逻辑都放在snow.js中: <!DOCTYPE html> <head& ...
- Java锁的理解
目录: 1.为什么要使用锁? 2.锁的类型? 1.为什么要使用锁? 通俗的说就是多个线程,也可以说多个方法同时对一个资源进行访问时,如果不加锁会造成线程安全问题.举例:比如有两张票,但是有5个人进来买 ...
- 实验一 Linux系统与应用准备(嵌入式Linux工程师的“修真之路”)
作业格式 项目 内容 这个作业属于哪个课程 这里是链接[https://edu.cnblogs.com/campus/nchu/2020SpringSystemAndApplication] 这个作业 ...