缓存穿透、击穿、数据一致性解决方案

一、缓存雪崩

大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
解决方案:
1.缓存时间设置随机值,尽量让失效时间点均匀分布
2.在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,也就是说对查询数据库这个操作加分布式锁,防止对数据库压力过大,其它线程来查库,由于拿不到锁,可以sleep一会儿,然后重试
3.做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

二、缓存穿透

查询一定不存在的数据,这样不能命中缓存,直接查询数据库
解决方案:
1.接口限流与熔断、降级,封掉恶意访问的IP
2.在接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return
3.使用互斥锁排队
4.使用布隆过滤器,不存在直接返回
5.缓存空值,设置短暂过期时间

三、缓存与数据库双写情况:

A. 先更新数据库,再删除缓存
B. 先删缓存,再更新数据库
C. 先更新数据库,再更新缓存
D. 先更新缓存,再更新数据库
E. 先删除缓存,再更新数据库,再删除缓存

四、分析

4.1 A情况,相比较而言最好的方案

存在的问题:

问题1: 更新数据库成功,更新缓存失败 数据不一致
这时候需要根据业务是否需要保持强一致性进行处理,要么该次请求报错,要么等下次缓存重新刷新

问题2:线程1是读请求,线程2是写请求,在线程1读缓存时,缓存失效,查询数据库,线程2进行写数据库,并且写提交后删除缓存,这时线程1将读取的数据设置缓存,这时的缓存就是原始旧数据
这种情况不常见,需要满足两个条件:

  1. 读数据时缓存恰好失效
  2. 写操作比读操作先完成(一般数据库的写比读更耗时)
4.2 B情况

存在的问题:

问题1:删除缓存成功,更新数据库,并发高的情况对数据库压力巨大

问题2:线程1是写请求,删除缓存,线程2读请求,发现无缓存,查库,设置缓存,线程1更新数据库,出现数据不一致
缓存中依然保留老数据
可以使用延时删除缓存策略:先删缓存,更新数据库后,休眠1秒(根据业务时间确定)再删除缓存

问题3: 存在和A情况一样删除缓存失败场景

4.3 C,D情况

存在的问题:

线程安全角度

存在两个写请求,本来执行顺序是A,B,但是由于网络或者业务处理耗时不同,造成B,A,数据一致性被破坏

这种情况,可以加分布式锁来解决,但是锁会牺牲性能,根据业务情况选择合适锁粒度,或者更新操作在业务上不区分先后,上面因为并发问题都可以通过锁解决。 同时更新数据库和缓存都可能存在失败情况,需要考虑。

场景业务角度

更新缓存有时候是需要代价的。对于一个缓存,有可能需要从数据库多张表读出来,然后进行相应的复杂计算才能得到对应的缓存结果,如果你每次都去更新缓存,这岂不是浪费性能,尤其是在更新比较频繁,读缓存的频率较低的情况下,浪费性能更加明显。

4.4 E情况

存在的问题:
A存在的问题,E都存在,没有必要删两次缓存,多一次删缓存还会让读请求查询缓存旧值概率变大。

4.5 保持强一致性

更新数据库后,异步删除缓存,失败可以重试。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值