1.缓存穿透
缓存穿透是指查询一个一定不存在的数据,导致请求穿过redis缓存到达DB,DB做无效的查询,当流量大时,可能导致DB挂掉。
1.1 解决方案
- 非法请求的限制:当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此在 API 入口处我们要判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进一步访问缓存和数据库
- 采用布隆过滤器+
set key null
。布隆过滤器过滤掉绝大部分不存在的数据,可能还有很少的数据到达数据库,在数据库查询没有对应的数据的时候,更新redis,设置对应的key为null ,再来请求的时候通过key null 过滤掉。
2. 缓存雪崩
大量热点的key过期,导致大量的请求打到了数据库;Redis宕机
2.1 大量key过期解决方案
- 给热点数据设置随机过期时间,避免同时过期,某些热点key过期。回到了缓存击穿的问题,继续使用缓存击穿的方案。
- 不设置过期时间,有更新的话,需要更新缓存;
2.2 Redis 故障宕机而引发的缓存雪崩问题
- 构建 Redis 缓存高可靠集群
- 服务降级:指服务针对不同的数据采用不同的处理方式
- 业务访问的是非核心数据,直接返回预定义信息、空值或者报错;
- 业务访问核心数据,则允许访问缓存,如果缓存缺失,可以读取数据库。
等Redis恢复正常了,再恢复。
3. 缓存击穿
缓存击穿和缓存雪崩有点像,但是也有一点区别。
缓存雪崩是因为大面积的缓存失效,打崩了数据库。而缓存击穿是指某个访问非常频繁的热点数据,大量并发请求集中在这一个点访问,在这个Key失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿了一个洞
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库
2.1 解决方案
- 采用互斥锁、分布式锁,保证每个key只有一个线程去查询后端服务,而其他线程为等待状态,查询的线程拿到结果更新Redis,其它的访问就能通过Redis拿到数据了。核心思想是阻止并发到数据库。
- 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;比如我们可以将某个 key 的缓存时间设置为 25 小时,然后后台有个 JOB 每隔 24 小时就去批量刷新一下热点数据。
2.1.1 setNx 互斥锁问题
- 去数据库请求的线程挂掉了,锁得不到释放,死锁
-》可以给setNx设置过期时间解决。- 又引出新的问题去数据库请求的线程没有挂掉,但是由于各种原因超时了,再来请求,再超时,不断新的请求堆积,不好控制超时的时长。怎么解决呢?可以启动一个线程监控请求数据的线程是否拿到数据等状态。
- 推荐使用
zookeeper
或者Redission
实现锁。自己通过setNx 在分布式环境太复杂了。