12.Redis缓存双写一致性

一、背景

只要用缓存,就可能涉及到Redis缓存和数据库存储双写,只要是双写,就一定会有数据一致性的问题,如何解决双写一致性是重要的问题。

双写不可能做到强一致性,即不可能做到两边同时被更新,所以我们的目标是为了保障最终一致性。

二、双写一致性的方法讨论

重要的写在前面:双检加锁

多线程情况下发生查询时,如果缓存里没数,这些请求都会打到数据库上,为了防止数据库承受太大的压力,需要有一种机制保障同时只有一个线程去查数据库,如果能查出来数,就写入到缓存里,其他线程查询缓存即可。这种机制就是双检加锁机制,即先检查缓存,缓存没数的话再加锁,进入锁后再检查一遍缓存。

image-20250108083209174

2.1 先更新数据库,再更新缓存

异常问题1

1 先更新mysql的某商品的库存,当前商品的库存是100,更新为99个。
2 先更新mysql修改为99成功,然后更新redis。
3 此时假设异常出现,更新redis失败了,这导致mysql里面的库存是99而redis里面的还是100。
4 上述发生,会让数据库里面和缓存redis里面数据不一致,读到redis脏数据

异常问题2

【先更新数据库,再更新缓存】﹐A、B两个线程发起调用
【正常逻辑】
1 A update mysql 100
2 A update redis 100
3 B update mysql 80
4 B update redis 80
=============================
【异常逻辑】
多线程环境下,A、B两个线程有快有慢,有前有后有并行
1 A update mysql 100
3 B update mysql 80
4 B update redis 80
2 A update redis 100
=============================
最终结果,mysql和lredis数据不一致,o(T_T)o,
mysql80,redis100

2.2 先更新缓存,再更新数据库

不推荐,业务上一般把MySQL作为底单数据库,保证最后解释

异常问题

[先更新缓存,再更新数据库],A、B两个线程发起调用
[正常逻辑]
1 A update redis 100
2 A update mysql 100
3 B update redis 80
4 B update mysql 80
====================================
[异常逻辑]多线程环境下,A. B两个线程有快有慢有并行
A update redis 100
B update redis 80
B update mysq| 80
A update mysql 100
mysql100,redis80

2.3 先删除缓存,再更新数据库

异常问题

1 请求A进行写操作,删除redis缓存后,工作正在进行中,更新mysql.....
  A还么有彻底更新完mysql,还没commit
2 请求B开工查询,查询redis发现缓存不存在(被A从redis中删除了)
3 请求B继续,去数据库查询得到了mysq中的旧值(A还没有更新完)
4 请求B将旧值写回redis缓存
5 请求A将新值写入mysql数据库

2.4 先更新数据库,再删除缓存

目前业界用的比较多的是这种方法

这种方法存在的异常就是数据库更新完后,缓存还没来得及删除,另一个线程过来读缓存时会读到老的数据。但是下次来读时就会拿到新数据了,可以保障最终一致性。

2.5 监听binlog来删除缓存

上述策略是在写数据库和更新缓存发生在同一程序中的,但很多时候我们缓存在redis里的数据并不是由我们自己写入到mysql的,此时我们为了感知到mysql中数据变化,需要监听mysql的binlog。流程如下

image-20250108083931855

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值