本文已参与「新人创作礼」活动,一起开启掘金创作之路。
如何避免缓存雪崩
缓存雪崩,是缓存击穿的升级版,同一时间大量的redis没有但数据库中有的数据被并发访问,请求到了数据库,造成数据库短时间内承受大量请求而崩掉。
解决方式:
(1)事前:缓存预热,key随机过期,主从复制+哨兵模式提高可用性,分布式锁防止大量缓存击穿。
(2)事中:本地缓存(缓存一些核心数据) 、削峰限流(限制并发请求量)、服务降级(关闭无关服务,返回空值)
(3)事后:利用 Redis 持久化机制尽快恢复缓存。
分布式锁的使用:使用set命令将redis未命中的数据作为key存入缓存作为锁,只有锁设置成功时才能访问数据库。(注意设置key的过期时间,value设置为唯一标志防止锁被误删,“UUID+ThreadID”,使用LUA脚本原子性删除锁)【set key value ex 100 nx】
value: 通常存储加锁方的唯一标记,如 “UUID+ThreadID”
对于不需要超时时间的情况,可以设置不断刷新锁超时时间的线程;
在使用分布式锁时:
若发生穿透、击穿,因为无效请求的key较少,存在于少部分服务器中,请求这些key可能会使同服务器慢一点,但不会影响其他服务器的请求,稳定性得到保障。
若发生雪崩,因为无效请求的key较多,一般会比较均匀的遍布多个服务器(因此对于整个架构来说,性能的影响不会太大),sleep的线程影响不大。
架构追求的是稳定性,即使一两台服务器出现了问题,但其他服务器可以正常使用,而不是追求O(n)的速度,不是因为技术而技术。
如何进行缓存预热
1、缓存刷新页面,上线时手工操作;
2、使用程序定时刷新缓存;
3、数据量不大时,提前把数据存入redis;
其他:开发逻辑上也要规避差集(尽量避开没缓存的数据),否则可能会造成穿透(数据库和redis都没有数据),击穿(redis没有数据,数据库中有数据),雪崩(大量的击穿),实施4,5,6中的锁方案