redis 缓存一致性问题

在高并发的情况下,如果当删除完缓存的时候,这时去更新数据库,但还没有更新完,另外一个请求来查询数据,发现缓存里没有,就去数据库里查,以商品库存为例,如果数据库中产品的库存是100,那么查询到的库存是100,然后插入缓存,插入完缓存后,原来那个更新数据库的线程把数据库更新为了99,导致数据库与缓存不一致的情况。

这种情况如何解决比较好呢?

本文从以下三个部分进行浅谈:

1、讲解缓存更新策略

2、对每种策略进行缺点分析

3、针对缺点给出改进方案

对于缓存和数据库的操作,主要有以下两种方式:

1.先删缓存,再更新数据库

先删除缓存,数据库还没有更新成功,此时如果读取缓存,缓存不存在,去数据库中读取到的是旧值,缓存不一致发生。

img

该方案看似没毛病。使用先操作缓存(delete),再操作数据库。假如删除缓存成功,更新数据库失败了。缓存里没有数据,数据库里是之前的数据,数据没有不一致,对业务无影响。只是下一次读取,会多一次cache miss。

但是如果放在并发场景下,一个写请求过来,删除了缓存,准备更新数据库(还没更新完成)。然后一个读请求过来,缓存未命中,从数据库读取旧数据,再次放到缓存中,这时候,数据库更新完成了。此时的情况是,缓存中是旧数据,数据库里面是新数据,数据不一致的问题便会凸显出来。

img

对于该场景下的问题,可以采用延时双删策略进行解决。

延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从缓存中读取不到数据,就在更新完数据库之后,再sleep一段时间,然后再次删除缓存。sleep的时间要对业务读写缓存的时间做出评估,sleep时间大于读写缓存的时间即可。

流程如下:

  • 线程1删除缓存,然后去更新数据库

  • 线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存

  • 线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除

  • 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值。

img

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

既然上述先删缓存不行,那如果反过来操作,先更新数据库,再删除缓存呢?

这个就更明显的问题了,更新数据库成功,如果删除缓存失败或者还没有来得及删除,那么,其他线程从缓存中读取到的就是旧值,还是会发生不一致。

img

那么这种情况下该怎么处理呢?

基于binlog日志和消息队列:

  1. 应用直接写数据到数据库中。

  2. 数据库更新binlog日志。

  3. 利用Canal中间件读取binlog日志。

  4. Canal借助于限流组件按频率将数据发到MQ中。

  5. 应用监控MQ通道,将MQ的数据更新到Redis缓存中。

可以看到这种方案对开发来说比较轻量,不用太关心缓存层面,而且这个方案虽然比较重,但是却容易形成统一的解决方案。

img

3.总结

首先,我们要明确一点,缓存不是更新,而应该是删除。

删除缓存有两种方式:

  • 先删除缓存,再更新数据库。解决方案是使用延迟双删。

  • 先更新数据库,再删除缓存。解决方案是消息队列或者其他binlog同步,引入消息队列会带来更多的问题,并不推荐直接使用。

为什么是删除而不是更新呢?

我们以先更新数据库,再删除缓存来举例。

如果是更新的话,那就是先更新数据库,再更新缓存。

举个例子:如果数据库1小时内更新了1000次,那么缓存也要更新1000次,但是这个缓存可能在1小时内只被读取了1次,那么这1000次的更新有必要吗?

反过来,如果是删除的话,就算数据库更新了1000次,那么也只是做了1次缓存删除,只有当缓存真正被读取的时候才去数据库加载。

针对缓存一致性要求不是很高的场景,那么只通过设置超时时间就可以了。其实,如果不是很高的并发,无论你选择先删缓存还是后删缓存的方式,都几乎很少能产生这种问题,但是在高并发下,你应该知道怎么解决问题。

最后,个人认为哈,没有十全十美的解决方案,总是需要牺牲一点东西滴。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值