十八缓存和数据库一致性问题

缓存和数据库一致性问题

目标

使用缓存的目标是:提升系统吞吐量(A Availability高可用),如果方案为了达到了强一致性(C Consistency一致性),但是强烈影响了吞吐量,那就相当于没有用缓存。(ps:数据存在redis和db已经满足分区容错性P Partition tolerance, CAP只能同时满足其中两者)。

几种方案

操作缓存、更新数据库

操作缓存

  1. 先操作缓存,再更新数据库
  2. 先更新数据库, 再操作缓存

操作数据库有两种方式:

  1. 更新缓存
  2. 删除缓存

什么是更新缓存: 数据不仅要写入数据库还要写入缓存。 核心关键词:简单。
什么是删除缓存: 数据只会写入数据库,删除缓存,写入缓存的操作等待数据查询的时候来做。核心关键词:复杂

如果更新数据库的值,不需要经过复杂计算,并且写少读多那么可以直接写入缓存,如果写入缓存的数据需要经过复杂计算,
那么如果每次写入数据库,都要更新缓存,在写多读少的场景下会增大缓存层的压力。

四种方案

先来看看更新缓存的两种方案。

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

现在有两个线程A,B:
A:开始更新缓存,更新完成
B:读数据,缓存中有数据,读到了数据
A:更新数据库的值,更新失败

这里B从缓存读到数据是无效的,所以这方案弃用,缓存层的数据应该依赖数据库。这种方案不考虑。

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

现在有两个线程A,B:
A:更新数据库
B:更新数据库
B:写入缓存
A:写入缓存

这里缓存最终的数据应该是B线程写入的值,但是这里由于A线程所在的实例由于网络抖动,导致A更新缓存晚于B线程,这就导致了
脏数据。上面也说了如果是读少写多的场景,会非常耗费性能。

所以更新缓存这种方案一般不予考虑。下面我们来看看删除缓存的两种方案。

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

现在有两个线程A,B:

  1. A:删除缓存,成功
  2. B:读缓存的数据
  3. A:更新数据库
  4. B:读缓存

这里可以看到,后续操作读到的缓存业务上是已经过期的。如果不设置key的过期策略,则数据永远都是脏数据。这里我们可以引入延时双删策略来保证4之后的步骤能
读到正确的值。

延时双删策略:第3步完成后,可以延时睡眠后直接删除key,之后再次读,可以从数据库拿到最新的值,也可以直接设置key的过期时间。

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

现在有两个线程A,B:

  1. A:更新数据库
  2. B:读缓存
  3. A:删除缓存
  4. B:读缓存,从数据库加载

这里可以看到只有第2步读到数据是脏数据,并且这个时间不会太长。所以这种方案来说缓存数据及时性比较高。
可能有同学有疑问,如果第3步失败了呢?这里可以做一种补偿方案,当删除缓存失败了,则发条消息或者维护一个内存队列(list),来做重试。

方案对比

缓存淘汰也不是万全之策,这种方案有一个缺点,就是如果在删除缓存成功的时候,如果有大量请求请求这个key,则会发生缓存击穿(不存在于缓存,存在于db),进而可能会导致缓存雪崩。

更新缓存可能会导致,脏数据的出现以及在读少写多的场景下降低性能。

怎么来选择方案呢?

问题本质是在分布式环境下(对db和redis的操作不是原子的)要求数据一致性。

  • 强一致性
  • 最终一致性

方案1,2,如果要达到最终一致性,key需要设置过期时间,就可以保证数据最终一致性。
方案3,4,本身就满足最终一致性。所以我们只讨论方案3,4。如果选择方案3,4呢?3,4的区别在于先删除缓存,还是先更数据库。

方案3: 先删除缓存,在更新数据库,如果更新数据库失败。再次读从数据库加载数据就好了。
方案4: 先更新数据库,在删除缓存,如果删除缓存失败了。缓存数据业务上已经过期,数据不一致。最终只能通过key的过期来保证数据一致性。

所以选择方案的原则是: 谁先执行对业务影响最小,就先执行谁。

上面说了方案3,4会导致缓存雪崩,那么如果在方案3,4和2中如何选择呢:热点数据采用更新缓存, 冷数据使用淘汰(删除)缓存

上面也只是说了如何保证最终一致性,那么如何保证强一致性呢?

在写db和缓存中加锁,不过这就会导致redis的性能依赖db,会导致DB+缓存这种方案性能直线下降,牺牲了高可用。

参考

https://www.zhihu.com/question/54105974

http://www.blogjava.net/hello-yun/archive/2012/04/27/376744.html
https://www.cnblogs.com/duanxz/p/3740595.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值