缓存击穿、穿透、雪崩及解决方案
缓存击穿
有一个高并发key突然过期失效,大量请求可能压垮数据库。
解决方案
①加分布式锁
拿到锁的请求才能访问数据库更新缓存,加双重锁检测机制,拿到锁后先检查缓存中有没有数据,有数据直接返回。
优点是数据一致性比较强,但是因为可能阻塞等待,性能较差。
②逻辑过期
设置缓存永不过期,数据内部维护过期时间,过期了再去拿锁,拿到锁的线程开启新线程异步更新,其他请求直接返回旧数据。
优点是不用阻塞性能比较好,缺点是数据一致性较差。
③中间件或框架
某手Cache Setter:通过一致性哈希将相同key路由到同一个Cashe Setter,Cashe Setter中维护ConcurrentHashMap<String, CountDownLatch>如果出现key miss的请求就从中拿出CountDownLatch,如果拿不到就put(key, new CountDownLatch(1)),然后更新缓存,后续请求拿到CountDownLatch被await()阻塞住,等第一个请求更新缓存后调用countDown(),其他请求解除阻塞然后从缓存中取数据即可
jd hot key:通过检测出hot key,将hot key放到本地缓存中
缓存穿透
请求的数据在缓存和数据库中都不存在,请求就会直接访问数据库
解决方案
①对非法请求处理
做好参数校验,拦截非法请求,拦截非法用户非法ID,设置黑名单,尽量在网关或者请求检查这一步把非法请求拦截。
②缓存空值
对于数据库查不到的key缓存空数据,设置比较短的过期时间,如果每个请求的key都不一样就用布隆过滤器,写数据库同时写布隆过滤器,请求来的时候通过布隆过滤器快速判断数据是否存在。
布隆过滤器原理:将数据进行多个哈希函数计算,计算处多个哈希值,将哈希值映射到bitmap里,请求来的时候对这些数据用多个哈希函数做计算,判断哈希值对应bitmap位置上是否为1。
但是布隆过滤器可能会误判,也无法进行数据删除,可能存在问题
缓存雪崩
同一时间有大量key同时失效了,或者redis宕机导致数据库宕机
解决方案
①在固定过期时间上加随机数
让数据不会在同一时间同时过期
②针对不太变化的数据不设置过期时间
如果需要修改这些数据异步删除或者更新缓存
③针对可预知的热点数据进行预热
保证业务高峰期这些数据不会过期
④不可控的意外情况
针对redis宕机要做好redis的高可用,主从、集群、多机房容灾,同层双活,异地多活
对意外情况做兜底措施,做好服务的降级、限流、熔断这种服务保护措施,避免因缓存雪崩把服务打垮了