Redis 之缓存和DB一致性解决

缓存一致性问题

在日常开发中,为了提高数据响应速度,可能会将一些热点数据保存在缓存中,这样就不用每次都去数据库中查询了,可以有效提高服务端的响应速度,那么目前我们最常使用的缓存就是 Redis 了。

考虑一个问题,如果数据库修改了一个数据,而这个数据缓存中也有,这时再从缓存中拿数据,就是一条旧数据。

缓存数据一致性模式

双写模式

先更新数据库,再更新缓存。
1、A 线程更新数据库值为 1。
2、B 线程更新数据库值为 2。
3、由于卡顿,B 线程先更新了缓存值为 2。
4、最后 A 线程更新了缓存值为 1。
此时,缓存中保存的数据就是一个旧的脏数据了。
在这里插入图片描述
解决方案一:
加锁,产生并发写的时候,因为要更新数据库,同时要更新缓存,那么就可以对整个操作加一个锁,保证更新数据库和更新缓存是一个原子性。
这样就可以避免脏数据了。

解决方案二:
对缓存设置一个过期时间,过期时间一到,就会得到最新的数据,只是会出现暂时的数据不一致,最终会一致性的。
就要看业务是否允许这种情况,允许的情况下,容忍是多大。

失效模式

先更新数据库,再淘汰缓存。
A、B 线程更新数据库,再删除缓存。
C 线程读取数据库,在更新缓存。

1、A 线程更新数据库值为 1,删除缓存,A 执行完。
2、B 线程更新数据库值为 2,但是由于机器慢,花的的时间比较长。
3、这时 C 线程读取数据,从缓存读取不到,再从 DB 读取数据,这时读取到值为 1。
4、这时 B 线程执行完了,将数据值更新为 2,并且删除缓存。
5、最后 C 线程更新缓存值,因为 C 读取到的是 A 线程更新的数据,将旧数据更新到了缓存了。
此时,缓存中保存的数据就是一个旧的脏数据了。
在这里插入图片描述
解决方案:
上面的问题,其实就是写和读的并发问题,可以通过加读写锁进行解决问题。
对更新数据加写锁,对读数据加读锁。写读、读写、写写互斥,读读不互斥。
但是不管怎么样,只要用了锁,系统性能肯定会变低,但保证了数据的一致性,需要进行取舍。

对于经常修改的数据,与其进行加锁用缓存,还不如直接读数据库。
对于经常读,偶尔写的情况下,其实用缓存也就基本不会出现脏数据,因为并发写的情况基本不会出现,如果怕以防万一,可以用读写锁。因为读写锁适用于经常读的情况。

缓存数据一致性-解决方案

无论是双写模式还是失效模式,都会导致缓存的不一致问题。即多个实例同时更新会出事。怎么办?

  • 1、如果是用户纬度数据(订单数据、用户数据),这种并发几率非常小,不用考虑这个问题,缓存数据加 上过期时间,每隔一段时间触发读的主动更新即可。
  • 2、如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式。
  • 3、缓存数据+过期时间也足够解决大部分业务对于缓存的要求。
  • 4、通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。(业务不关心 脏数据,允许临时脏数据可忽略);

总结:

  • 我们能放入缓存的数据本就不应该是实时性、一致性要求超高的。所以缓存数据的时候加上过期时间,保 证每天拿到当前最新数据即可。
  • 我们不应该过度设计,增加系统的复杂性。
  • 遇到实时性、一致性要求高的数据,就应该查数据库,即使慢点。

在这里插入图片描述

总结系统的一致性解决方案

1、缓存的所有数据都有过期时间,数据过期下一次查询触发主动更新。
2、读写数据的时候,加上分布式的读写锁。 经常写(会有影响)。很少写,经常读(不会有影响)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值