缓存更新策略
# 先删除缓存再更新数据库
# 问题:
线程 A 先删除了缓存,此时线程 B 去查询缓存中的数据,发现缓存失效,就去查询数据库,线程 A 的数据尚未落库,线程 B 查到了旧数据,并把旧数据重新写入了缓存,导致数据不一致
# 先更新数据库再更新缓存
# 问题:
线程 A 先往数据库中写入数据 1,然后去更新缓存,由于网络出现延迟,在此时线程 B 写入了数据 2,并完成了更新缓存的操作,线程 A 此时刚完成写入缓存的动作,把线程 2 的缓存给覆盖了,导致数据 1 (旧值)写入了缓存,导致了数据不一致
# 先更新数据库再删除缓存
# 问题:
线程 A 是读操作,先去查缓存,发现缓存失效了,再去读数据库,读到了数据 1 。此时线程 B 写操作,来更新数据库写入了数据 2 ,同时删除了缓存,线程 A 此时刚完成更新缓存的操作,把旧值 1 写入了缓存,导致了数据不一致。
要出现以上场景,需满足以下条件:
- 读操作 和 写操作是并发执行的
- 读操作查询时缓存是失效的
- 写操作的更新数据库提交事务要晚于读操作的查询数据库
- 写操作删除缓存要早于读操作的更新缓存
理论上可能出现这种场景,但一般读操作远快于写操作,此场景比较难出现,在非强一致性的场景下,此操作比较实用。
# 以上策略都是基于高可用下讨论的
# 缓存雪崩
# 原因:
- 可能是 redis 宕机
- 可能是大量 key 同时过期
# 解决方案:
- 搭建 redis 集群
- key 的过期时间增加随机值
- 双缓存的方式,缓存 A 设置过期时间,缓存 B 不设置过期时间,更新时要同时更新这两个 key
- 服务降级或熔断
# 缓存击穿
# 原因:
某个 key 过期时,大量访问同时涌入,导致击穿缓存直接访问了数据库
# 解决方案:
- 锁更新,当 key 过期时,请求数据库要先获取互斥锁,获得锁之后才可以查询数据库,查询完数据之后更新到缓存中,其他未获取到锁的进程可以设置 sleep 几毫秒再去获取一下缓存数据
- 异步更新,key 设置为不过期,单独的进程去刷新数据加载到缓存中,例如某些场景下的计算排名操作,对实时更新要求不是很严格,查询请求大于写请求,可以采用单独线程定时主动更新缓存的策略
# 缓存穿透
# 原因:
数据库未查询到指定条件的数据,没法把数据加载到缓存中,如果有人恶意模拟大量异常请求导致缓存穿透直接访问到数据库
# 解决方案:
- 未查询到数据时,设置一个空值标记到缓存中,这个空值的过期时间可以设的短一些。
- 布隆过滤器
- 过滤异常请求
上次更新: 2024/11/05, 03:15:29
锁→