缓存雪崩问题
使用缓存的优势:
- 查询速度快,查询内存中的数据比磁盘快
- 提高并发能力,缓存分担一部分请求,支持更高的并发
缓存雪崩:
同一时刻有大量缓存消失,会使数据库任务加重,甚至宕机
造成缓存雪崩的两种情况
- redis宕机,所有请求都会走数据库
- 同一时刻有大量缓存过期,导致一段时间内缓存失效,大量请求走数据库
解决办法
- 对于redis宕机,可以采用redis高可用
- 对于同一时刻大量缓存过期,可以采用定期删除+惰性删除(即在缓存的时候给过期时间加上一个随机值,就会大幅度减少缓存在同一时间过期)
缓存穿透问题
缓存穿透:
查询一个一定不存在的数据。由于缓存不命中,并且出于容错的考虑,从数据库查询不到数据则不写入缓存,导致不存在的数据每次都要走数据库查询,缓存无意义。
解决方法:
- 使用布隆过滤器或压缩提前拦截那些请求不存在的参数,不合法不让请求到数据库中去
- 当数据库中找不到的时候,将这个空对象设置到缓存中去,下次请求直接在缓存中获取
缓存与数据库双写一致问题
更新时,各种情况导致数据库数据和缓存数据不一致
对于缓存的操作有两种:
- 更新缓存,在高并发情况下容易出错
- 删除缓存,直接删除,当再次读取时,缓存中没有,到数据库中找并写到缓存中
更新数据又分为两种方案,每种方案的两个操作我们都希望同时成功同时失败。
-
先更新数据库,在删除缓存
原子性被破坏
-
先删除缓存,在更新数据库
原子性被破坏
- 第一步成功(删除缓存),第二步失败(更新数据库),数据库和缓存的数据还是一致的。
- 如果第一步(删除缓存)就失败了,我们可以直接返回错误(Exception),数据库和缓存的数据还是一致的。
高并发
-
线程A删除缓存
-
线程B查询数据库,得到旧值
-
线程A更新数据库
-
线程B把旧值写到数据库中
针对这种情况,我们把删除缓存、修改数据库、查询等操作顺序积压到队列中,实现串行化
两种策略的对比
先删除缓存,后修改数据库
在高并发时表现不如意、但是原子性被破坏时表现优异
先修改数据库,后删除缓存
在高并发时表现不如意,但是原子性被破坏时表现优异