这里是目录标题
一. 缓存击穿
1. 概念:
- 场景:在高并发的场景下,客户端请求通过LB负载均衡、nginx反向代理、Client Service过滤掉一些无用请求之后,访问Redis缓存时。
- 概念:当Redis中的某个key因为expired、LRU/LFU淘汰时 (数据存在于后端数据库),恰巧这时一个高并发请求到了这个key,那么IO压力会给到后端的数据库上,导致缓存击穿。
2. 解决方案:
1. 方案一
当ClientService发现Redis中没有key,那么通过setnx去设置另一个lockkey来完成加锁,后续的所有关于该key的请求都阻塞在这里,只有第一个获得锁的ClientService线程去访问后端数据库,拿到value并设置给缓存。
问题:
- 为什么setnx可以加锁?
Redis实例是单进程单线程的,所以可以通过setnx一个key来完成加锁
- 该方案有什么问题?
- 如果获得锁的线程挂了怎么办(导致死锁)?
2. 方案二
在方案一的基础上,增加锁的超时时间
问题 :
- 如果获得锁的线程没挂,但是访问超时了怎么办?
开启一个守护线程,关注获得锁的线程时候从后端数据库拿到了数据,如果没有就延长锁的时间
二. 缓存穿透
1. 概念
-
场景:
在高并发的场景下,客户端请求通过LB负载均衡、nginx反向代理到达Client Service时。 -
概念:
Client Service访问Redis,发现请求的key不存在,就会访问数据库,如果数据库中也不存在该值,造成了对数据库的额外IO压力。
2. 解决方案
发生缓存穿透后,client service要增加redis中的key value标记,当在数据库增加新元素后,要完成元素对bloom的添加
方案一
使用Bloom过滤器,Bloom算法和bitmap可以分别在ClientService和Redis中架设,或者在其中一个里完成所有实现
缺点:Bloom过滤器只能增加key,不能删除
方案二
使用布谷鸟过滤器替换布隆过滤器
方案三
发生穿透后,在Redis层设置空的key,阻止后续请求访问数据库
三. 缓存雪崩
1. 概念
Redis缓存的所有key在同一时间集体失效(维护时间),这时高并发请求到达,导致DB的压力瞬间增大
2. 解决方案
方案一(解决零点更新缓存!)
到了缓存换血时间,依赖于缓存击穿的解决方案,并在ClientService做随机sleep,这样当高并发请求过来时,请求会延迟响应,Redis有充分的时间将数据重新缓存,而且避免了脏读(读到旧的数据)
方案二(通用解决方案)
随机过期时间,使每个key的过期时间分不开来,不会集中在一个时间,但方案一中的场景不适合这种解决方案
四. 分布式锁
缓存击穿的解决方案是一种用Redis做分布式锁的解决方案