阅读 93

Redis缓存不一致的问题(七)

缓存不一致的情况有两种:

  • Redis缓存中是旧值;

  • 数据库中值是旧值;

缓存一致性需要保证的是,当缓存中有值的时候,数据库的值必须与缓存一致。

根据是否接收写请求,可以将缓存分为读写缓存和只读缓存。两种发生缓存不一致的情况不同,需要分开来应对。

在只读缓存中,新增数据会直接写到数据库中,不会操作缓存,所以不会出现缓存不一致。删改数据时,需要删除数据库和缓存中的数据,在删改数据库和缓存时,无论哪个先后,中间出现故障都会产生旧值,即缓存不一致的情况。

不同情况潜在问题
先删除缓存值,后更新数据库值数据库更新失败,导致请求再次访问缓存时,发现缓存缺失,再读数据库时,从数据库中读到旧值
先更新数据库值,后删除缓存值缓存删除失败,导致请求再次访问缓存时,发现缓存命中,并从缓存中读取到旧值

如何解决数据不一致

重试机制

可以将要删除的缓存值或者要更新的数据库值暂存在消息队列中。当应用没有能够成功删除缓存或者更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。

如果能够成功地删除或更新,就需要将这些值从消息队列中去除,以免重复操作。如果重试超过一定次数,还是没有成功,就需要向业务层发送报错信息了。

但重试机制在并发量大时,依旧会有问题。要分先删缓存还是先更新数据库两种情况说说。

情况一:先删缓存,后更新数据库。

在并发的情况下,假设线程A先删除缓存,后更新数据库;那么在这期间线程b读取数据,发现缓存缺失,就会去数据库读取数据,那么就会产生两个问题:

  • 线程b读取到的旧数据;

  • 线程b读到旧数据后发现缓存缺失,那么就会去更新缓存,将缓存更新为了旧值,这样后面读取的线程访问的就是旧值,产生了数据不一致;

这样的情况可以采用延时双删的策略,即在线程A更新完数据库后,sleep一段时间,再删除缓存。这样做的目的是为了当线程b发现缓存缺失后将缓存更新了旧值,然后将这个旧值缓存给删除掉。

个人觉得这个策略并不是很好的做法。首先延时的时间不好确定,无法得知下一个读线程会更新缓存的时间。其二在并发量大的情况下,当线程a还没做延时双删时,会有大量的线程读取到缓存中的旧值。所以觉得这种方案只是会降低缓存不一致的概率,并非是"银弹。

情况二:先更新数据库值,再删除缓存值。

在并发的情况下,假设线程a先更新数据库,再删除缓存值。那么在更新数据库后删除缓存值前,会也线程读取到缓存中的旧值。不过由于删除缓存操作是内存操作,所以可以认为这一步是很快的,影响量不会很大。

不过对于正常业务来说,这种短时间内的数据不一致并不会影响很大。如果对于数据一致性要强要求的,要么不使用缓存,要么是利用分布式锁将请求变为串行。具体的做法得分场景选择了。


作者:易科
链接:https://juejin.cn/post/7027742696466808868

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐