如何保证redis和数据库的一致性

2022年9月29日10:14:23

在项目中难免会使用到redis作为缓存,去减轻数据库的访问压力,但是涉及到数据更新时,如果redis和数据库的操作设计出现问题,就会导致redis缓存中和数据库中的数据不一致的情况。那么我们如何去保证缓存与数据库中数据一直呢?

四种同步策略

想要保证缓存与数据库的双写一致,一共有四种方式,即四种同步策略
1、先更新缓存,再更新数据库
2、先更新数据库,再更新缓存
3、先删除缓存,在更新数据库
4、先更新数据库,再删除缓存
更新缓存和删除缓存的选择
更新缓存

优点:
如果每次数据变化都能被及时更新,那么查询数据时不容易出现不命中的情况,
缺点:
1、如果数据的计算复杂,频繁的更新会造成服务器性能的消耗比较大
2、如果数据并不是被频繁使用,那么频繁更新也只是浪费服务器性能,对业务没有多大的帮助
适用于数据使用较为频繁,且数据的计算不那么复杂的场景

删除缓存

优点:不需要顾忌数据的复杂性,直接删除即可
缺点:查询数据时,增大未命中的几率,从而增大数据库的访问压力
适用于数据使用频率不高的场景

在上面四种同步策略中,都存在导致数据不一致的风险

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

如何保证redis和数据库的一致性

操作步骤:
a、线程A删除缓存中的数据,
b、线程A更新数据库中的数据,但是更新失败
c、此时线程B去获取缓存中的数据,但是未命中
d、线程B,去数据库中获取数据,但此时的数据因为更新失败为旧数据
e、线程B将数据库中查到的数据同步到缓存中去
f、线程A此时更新数据到数据库成功
最后数据库和redis缓存中的数据不一致

如果在更新数据库时没有出现失败,也同样存在会造成数据不一致的情况
如何保证redis和数据库的一致性
操作步骤:
a、线程A删除缓存中的数据,
b、此时线程B去获取缓存中的数据,但是未命中
c、线程B,去数据库中获取数据,但此时的数据因为更新失败为旧数据
d、线程B将数据库中查到的数据同步到缓存中去
e、线程A此时更新数据到数据库成功
最后数据库和redis缓存中的数据不一致,这里造成的数据不一致的原因是线程B在数据库还未更新时就已经获取到了旧的数据。

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

如何保证redis和数据库的一致性
操作步骤:
1、线程A更新数据库中的数据
2、线程A删除缓存中的数据,删除失败
3、线程B查询缓存中的数据,查询到旧数据
4、线程A异步重试删除缓存
这里,删除缓存中数据失败后就会造成线程B获取到缓存中的旧数据,从而导致数据不一致的情况

如果缓存没有删除失败的情况也可能导致数据不一致
如何保证redis和数据库的一致性
操作步骤:
1、线程A更新数据库中的数据
2、线程B查询缓存中的数据,查询到旧数据
3、线程A删除缓存
如果线程B在缓存删除前获取到了缓存中的数据,那么线程B获取到的还是旧数据,也会导致数据不一致的情况

延时双删

上面中先删除缓存,在更新数据库在不出现失败时也会出现数据不一致的情况,那么我们要有什么解决方案呢。我们就采用延时双删的策略来保证缓存中的数据时更新后的数据
操作步骤
1、先删除缓存
2、更新数据库
3、线程等待 N秒(等待时间根据具体业务来判断)
4、再删除缓存
这样就保证了缓存中的数据最终会和数据库中的数据保持一致

数据库读写分离

先删除缓存,在更新数据库,如果数据库采用读写分离架构会有什么影响呢?
如何保证redis和数据库的一致性

操作步骤:
1、线程A删除缓存
2、线程A更新从数据库
3、线程B查询缓存,未命中
4、线程B去从数据库查询数据,还未同步,所以从数据库为旧数据
5、线程B将数据更新到缓存中
6、主数据库同步数据到从数据中
这样还是会出现数据不一致的情况,那么我们要怎么解决呢?
如果只是为了更新redis的数据的数据库查询,让线程同步数据时强行指定到主数据库执行

  • 作者:可乐丿不加冰
  • 原文链接:https://blog.csdn.net/weixin_44740485/article/details/124846964
    更新时间:2022年9月29日10:14:23 ,共 1435 字。