Redis应用——缓存一致性问题的解决方式

为什么产生缓存一致性问题

在使用Redis等缓存中间件的时候,一定会遇到一个问题就是缓存一致性的问题(面试只要提到缓存也是必问的)。所谓缓存一致性问题就是,当某一个线程在做缓存与数据库的更新操作时,这两步操作一定是分开进行的,所以就会出现缓存与数据库的数据出现短暂的不一致,进而可能会造成其他线程读取数据不一致的问题。

更新缓存与数据库的可能策略

1)先修改缓存,再修改数据库:这种方式乍一看,好像没啥问题,修改了缓存就可以保证其他线程也能够读取到最新数据,但是最重要的问题是,如果在第二步更新数据时,出现异常导致数据更新失败的话,缓存与数据库会出现严重的不一致,而且错误数据是在数据库上的,这是不可接受的,因为数据库数据是最后的底线,绝对不能让数据库数据出现脏数据(redis可没有事务回滚机制,数据库数据更新失败会事务回滚,但redis只要执行成功,就不会回滚,再加上假如该缓存数据设置有过期时间,一旦缓存过期或者由于某种原因数据丢失了,再去数据库中查询得到的一定是错误的旧数据了,所以这种方案一定排除)。

(2)先修改数据库,再修改缓存:这种方式的缺点就比较明显了,先修改数据库,就会导致从开始更新数据库到缓存更新成功之前这段时间内(或者缓存更新失败了),其他线程从缓存中读取到的都是旧数据,也即是脏数据。

(3)先删除缓存,再更新数据库:先删除缓存,然后更新数据库,其他线程读取的时候也会感知到缓存数据不存在了,就去数据库中查询,然后更新到缓存中。这种方式同样有个问题,在删除缓存后,到更新数据库成功之前这段时间,其他线程如果查询并重新将数据库中的数据加载到了缓存中,那么缓存中的数据还是旧数据,仅仅只是更新了数据库中的数据而已。

(4)先更新数据库,再删除缓存:很明显的,在更新数据库成功到删除缓存成功这段时间内,其他线程仍然只能读取到旧数据。而且还有另一个比较极端情况下的并发问题:假设这会有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生

  • 缓存刚好失效
  • 请求A查询数据库,得一个旧值
  • 请求B将新值写入数据库
  • 请求B删除缓存
  • 请求A将查到的旧值写入缓存

但是,这种情况太极端,所以大多数都会采用第4种策略进行缓存更新。

缓存一致性问题解决方案(个人思考)

上面的第4种方案虽然可行,但是高并发下肯定还是会出现问题的,所以在第四种方案的基础上还可以稍加改进。首先想到的就是分布式锁,遇事不决先上锁,并发问题统一解决方案。当然,纯属开玩笑,如果加上分布式锁,就变成了串行执行,那还要缓存有何意义,串行执行数据库都顶得住了,这样搞完全不考虑系统吞吐量的。

但改进一下,分布式锁采用读写锁模式,只有读请求可以并发,单对于写请求独占,这个可以有,系统吞吐量倒也大大提升,毕竟读请求远多于写请求,尤其以电商网站的商品信息这块为例,而且实现起来代码难度不大。可以使用通过Zookeeper实现的分布式锁方案,对于读写锁有着良好的实现,可以直接使用。第四种方案搭配分布式读写锁的方式,也得考虑一些东西,比如第二步缓存删除失败怎么办?是重试还是记录日志,还是采用异步执行,这些则是要结合具体业务对于数据的要求有多高来决定。

当然,加锁肯定是会影响性能和系统吞吐量的的,但数据一致性得到了保证,所以,如果业务对于数据一致性和实时性要求不高的话,实现的方案其实还是蛮多的,比如直接使用第四种方案即可,只需要可以保证数据最终一致性即可。

 

在网上还看到另一种方法是通过队列来序列化所有读写操作,方案如下:

比如说对于某一个商品信息的读写操作,为这个商品创建一个队列,凡是遇到写请求,则将写请求放入队列中,由队列对写请求统一管理,写请求处理成功,则从队列中删除。当有一个读请求过来时,到队列查询,是否有对应的写请求,如果有则放入队列中,等待写请求执行完之后再执行读请求。为防止某个请求阻塞情况,为其设置超时机制或者过期机制。

实际上这种方式也就是串行化操作,但这种方式我上面已经说了,系统吞吐量不想要了才这么干。而且都思考到这一步了,为什么想不到采用分布式锁的读写模式呢?这种方案虽可行,但是倘若访问量大,处理器来不及处理,队列内的请求数量越来越高,则会影响查询效率。出现这种情况,就要加机器集群执行,帮忙分担压力。更重要的是代码实现难度高且复杂。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值