Redis - 缓存的双写一致性

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 什么是数据一致性,为什么会有不一致性,需要怎么解决?

概念: 当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致

那为什么会有不一致的情况呢?

如果不追求一致性,正常有两种做法

  1. 先修改数据库 后删除旧的缓存
  2. 先删除旧的缓存 再修改数据库

我们以先删除旧的缓存,再修改数据库为例:

  1. 当 线程1 要对数据库做更新操作的时候,先将Redis中旧的缓存删掉
  2. 不巧此时线程之间发生切换,线程2读取缓存,因为被线程1删掉了,所以缓存未命中
  3. 线程2就直接查询数据库,并重建缓存(将此时的数据库数据写回Redis)
  4. 接着又切换回线程1,线程1将数据库中的数据修改为新的值

此时就出现了数据库和缓存中的数据不一致的问题

因此我们不能只进行一次缓存删除操作,要使用双删的方法

  1. 比如先删除旧的缓存,修改完数据库后,再删除一次缓存

但是单纯双删不能解决问题,比如

  1. 当 线程1 要对数据库做更新操作的时候,先将Redis中旧的缓存删掉
  2. 不巧此时线程之间发生切换,线程2读取缓存,因为被线程1删掉了,所以缓存未命中
  3. 线程2就直接查询数据库,获取当前数据库的值,但未重建缓存
  4. 接着又切换回线程1,线程1将数据库中的数据修改为新的值,并再次删除缓存
  5. 此时又切换为线程2,线程2将当时读取到的值写回Redis,又造成了数据不一致

因此我们可以采取 延迟双删策略

还是上面那个例子:

  1. 当 线程1 要对数据库做更新操作的时候,先将Redis中旧的缓存删掉
  2. 不巧此时线程之间发生切换,线程2读取缓存,因为被线程1删掉了,所以缓存未命中
  3. 线程2就直接查询数据库,获取当前数据库的值,但未重建缓存
  4. 接着又切换回线程1,线程1将数据库中的数据修改为新的值,但不马上删除缓存,而是等待一段时间
  5. 切换为线程2,线程2将当时读取到的值写回Redis
  6. 最后切换回线程1,线程1再将Redis中的数据删除

可以看到 延迟双删策略 确实能解决数据一致性的问题,但延迟的时间很难确定,短了怕上面的例子中,第6步先于第5步执行,长了怕在第5步和第6步之间的数据不一致状态持续时间太长

因此我们需要另外的解决方案

针对双写一致性有两种场景: 一致性要求高允许短暂不一致

这两种场景的解决方案不同

一致性要求高

可以使用如下的分布式锁方案

但是我们可以看到该方案让并发变为了串行,极大降低了性能

因此我们可以使用读写锁

读锁 readLock: 加了读锁之后,其他线程还能继续加读锁和读数据,但是不能写,也不能加写锁

写锁 writeLock:写锁是排他锁,加锁之后,其他线程阻塞,不能进行读写操作

Redission 以及实现了读写锁

代码实例

读锁

写锁

其中 redissonClient.getReadWriteLock()中传入的值必须是一样的

允许短暂不一致

实际上的开发过程中,这种场景才是主流

这种场景的解决方法很多,比较常用的方法是 异步通知保持数据的最终一致性

流程图如下:

修改数据库时,需要发送修改记录给MQ,缓存服务需要监听MQ,根据MQ中的修改记录更新缓存

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
6月前
|
canal 缓存 NoSQL
【Redis系列笔记】双写一致性
本文讨论了缓存不一致问题及其后果,如价格显示错误和订单计算错误。问题主要源于并发和双写操作的异常。解决方案包括使用分布式锁(但可能导致性能下降和复杂性增加)、延迟双删策略(通过延迟删除缓存来等待数据同步)以及异步同步方法,如通过Canal和MQ实现数据的最终一致性。面试中,可以提及这些策略来确保数据库和缓存数据的一致性。
497 1
【Redis系列笔记】双写一致性
|
4月前
|
canal 缓存 NoSQL
Redis常见面试题(一):Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;先删除缓存还是先修改数据库,双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
Redis常见面试题(一):Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
|
4月前
|
缓存 NoSQL 数据库
Redis问题之在高并发场景下,保证Redis缓存和数据库的一致性如何解决
Redis问题之在高并发场景下,保证Redis缓存和数据库的一致性如何解决
149 3
|
6月前
|
缓存 NoSQL 关系型数据库
Redis系列-6.Redis缓存双写一致性问题(上)
Redis系列-6.Redis缓存双写一致性问题
137 0
|
6月前
|
缓存 NoSQL Redis
深度解析Redis的缓存双写一致性
【4月更文挑战第20天】
322 1
|
6月前
|
缓存 NoSQL 关系型数据库
Redis 缓存 一致性
Redis 缓存 一致性
52 0
|
6月前
|
缓存 NoSQL 关系型数据库
【中间件】Redis与MySQL双写一致性如何保证?--缓存和数据库在双写场景下一致性是如何保证的
【中间件】Redis与MySQL双写一致性如何保证?--缓存和数据库在双写场景下一致性是如何保证的
328 0
【中间件】Redis与MySQL双写一致性如何保证?--缓存和数据库在双写场景下一致性是如何保证的
|
6月前
|
canal 缓存 NoSQL
Redis系列-6.Redis缓存双写一致性问题(下)
Redis系列-6.Redis缓存双写一致性问题
86 0
|
缓存 NoSQL 数据库
Redis - 缓存的双写一致性
什么是数据一致性,为什么会有不一致性,需要怎么解决?
81 0
|
消息中间件 缓存 NoSQL
redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)
redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)
701 0