所有栏目 | 云社区 美国云服务器[国内云主机商]
你的位置:首页 > 云社区 » 正文

项目中用到了Redis做缓存,如何保证数据库和缓存的数据一致性?

发布时间:2020-04-15 16:13:17

资讯分类:redis  一致性  中用  数据库  缓存  数据  更新
项目中用到了Redis做缓存,如何保证数据库和缓存的数据一致性?

先举两个例子,都是我做过的项目,应用场景都非常简单:

  • 曾经做过的一个保费试算的项目,业务场景是根据用户基本信息+费率做计算,得到一个保费值,如果不了解这个业务场景的话,可以看做【用户输入】+【数据库数据】+【一定的计算】=【结果】;这些数据复杂而且多,使用频繁,但是每个产品的费率数据,几乎是不会改变的(新增修改删除都不会有):这些数据被我们放在Redis中,而且设置成永不失效;因为数据不会修改,那么数据库和缓存中的数据肯定是一样的。

  • 现在做的项目中的一个功能,简单描述业务场景:系统从N个业务系统中抽取数据,并做加工整合,加工完成后更新到数据库中;这个场景也比较有特点,数据时效性要求很低(数据加工到数据库已经晚了一天),数据变化的时间固定且唯一(批处理每天固定时间进行,只有一个批处理线程在跑);于是我们采用了一个比较保守的策略,就是设置数据在Redis中的过期时间;等数据过期后,当查询的时候发现数据不在缓存中,再从数据库中查询出来后放入缓存。

现在想一想Redis中数据的更新策略有哪些(或者说缓存更新策略)?

  • 给缓存设置过期时间,是我认为比较好的方式(这里不讨论缓存雪崩的问题),这个【比较好】是在实现难度和数据一致性之间找到了一个平衡点;实现起来非常简单,但是可能在数据变化后,缓存失效前的这段时间,数据库和缓存之间的数据是不一致的(但最终会一致)。
  • 先更新数据库,再更新缓存:有两个比较大的问题,一是多线程的时候,可能会造成数据库和缓存数据的不一致,而且这个不一致可能会是长期的。二是如果更新操作比较多的话,会频繁地更新缓存。

  1. A线程:set 数据库 key=1;
  2. B线程:set 数据库 key=100;
  3. B线程:set 缓存 key=100;
  4. A线程:set 缓存 key=1;(实际上,应该等于100,这样就造成了缓存和数据库中的数据不一致,并且如果数据不再更新,那么会使长期不一致)
  • 先删缓存,再更新数据库:这个会出现问题,还是A/B两个线程,如果A删除了缓存之后,在更新数据库之前,B过来查询不到缓存,于是就查询了数据库(A还没更新),把数据写入缓存,这时候A才把数据库更新掉,这可能就会造成永久性的不一致。

  • 先更新数据库,再删缓存:一样的道理,大家可以自己想一想这个过程。

有些人可能觉得这个概率很小,怎么可能有这么巧的事情,恰好都是A做到一半,B插进来把全部的事情做完,A再去做后一半的操作;但是概率小,也是可能发生的,不得不考虑。

还有很多复杂的实现方案,比如更新完数据库之后,把更新操作发给有序的消息队列(不过过程越复杂,不一致的时间会越长),由另外的线程从队列里面顺序执行更新或删除缓存的操作;

不过我认为,架构越复杂也越容易出错,还不如根据实际的场景和团队的开发水平,合理选择缓存的使用,并给缓存设置合理的过期时间。

我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。

项目中用到了Redis做缓存,如何保证数据库和缓存的数据一致性?

1 不建议缓存和数据库强一致

(1) 在缓存作为提升系统性能手段的背景下,不需要保证数据库和缓存的强一致性。如果非要保证二者的强一致性,会增大系统的复杂度

(2) 如果更新数据库成功,再更新缓存。此时存在两种情况:更新缓存成功则万事大吉。更新缓存失败,没有关系,等待缓存失效,此处要合理设置失效时间

(3) 如果更新数据库失败,则操作失败,重试或者等待用户重新发起

(4) 数据库是持久化数据,是操作成功还是失败的判断依据。缓存是提升性能的手段,允许短时间和数据库的不一致

(5) 在互联网架构中,很少追求强一致性,一般都是追求最终一致性


2 问题本质

如果非要保证缓存和数据库的一致性,本质上是在解决分布式一致性问题。

分布式一致性问题解决方案有很多,可以选择比如两阶段提交,TCC,本地消息表,MQ事务性消息等方案。

本回答摘自我的头条文章《到底是先更新缓存,还是先更新数据库》请您参考


敬请关注

请点击关注按钮【IT徐胖子】会持续为大家奉献互联网和技术干货内容,感谢支持

项目中用到了Redis做缓存,如何保证数据库和缓存的数据一致性?

这个开发实际开发中还是常见的

方案一:添加过期时间,不过还是有延迟的,有校时间内还会读取,无法一致性。

方案二:定时的Task把数据查询结果,提前写入缓存,但是即使这样还是有延迟。

方案三:在任何数据操作,增删改查前,清理缓存,同时重新缓存最新的副本。

最终方案:方案出二和方案三组合使用。

希望的回答有所帮助?

留言与评论(共有 0 条评论)
   
验证码:
Top