1、击穿
(1)场景描述
缓存中的某个key由于过期了,并且前端数据出现高并发(一定要有高并发)请求该key(实际上概率很低),导致瞬间都打在数据库上。
(2)解决方案
使用redis的setnx(表示只有不存在时候才会设置值)命令,此时该命令相当于锁,如果设置成功则去DB查询,否则后续的请求都等待直到第一个请求设置成功直接缓存中get值。
解决步骤:
场景:10000个请求同时发生并请求Redis中不存在的key。
步骤一:10000个请求全部去Redis中查询数据,发现都没有值;
步骤二:10000个请求都去使用setnx方法去设置key,由于setnx特性(只有不存在才能设置成功),一定只要一个请求才会设置成功, 该请求去数据查询数据;
步骤三:其他请求setnx都会set失败,失败后睡眠一会,再重复步骤一。
(3)问题
1)如果第一个请求setnx去查数据时候恰巧挂了,那么后面的请求永远也等不到正确的设置值
解决:设置过期时间,如果第一个请求的应用挂了,后面的请求等待超时释放锁后,后面的请求去查库。
2)如果第一个应用没有挂,只是请求超时了?场景描述:此时第一个请求的锁已经释放,其他请求已经可以正常查询数据库获取数据,此时第一个请求成功了设置成功了,此时的效果是第一个已经取回来了数据,但是后面的请求还在等待查询数据库数据。
解决:使用多线程,一个线程去数据库查询数据,一个线程监控Redis中是否数据已经取回来了(也就是第一个请求查库是否正常查回数据)。
2、雪崩
(1)场景描述
缓存中由于大量的key同时过期(与击穿有点类似)导致大量访问数据库
(2)解决方案
两种情况:
a)针对时点性要求不高的数据,可直接讲redis的过期时间设置随机即可
b)针对有些数据必须在某个时点才能失效(比如有些数据必须在零点更新,数据再晚点就是脏数据)。
第一种简单方案:随机设置过期时间。
第二种方案:
- 可在业务层可零点延时判断,减少业务打在零点同时访问这个时间点,形成高并发;
- 击穿的解决方案。
3、穿透
(1)场景描述
查询的数据在预期范围之外(比如恶意攻击),则redis和数据库都没有数据,但是高并发下会影响数据库性能
(2)解决方案
(1)布隆过滤器;
使用方式:
- 客户端自己编写布隆算法自己设计位图;
- 客户端提供算法,Redis提供位图;
- 客户端什么都不实现,布隆算法与位图都放在Redis
(2)缺点,只能新增数据,不能删除数据,布谷鸟过滤器,或者直接维护一个空key集合,在空key里则直接返回。