缓存雪崩、穿透、击穿应对情况
问题
了解什么是 Redis 的雪崩、穿透和击穿?崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?
雪崩、穿透,是缓存最大的两个问题,要么不出现,出现就是致命问题。
雪崩
什么叫雪崩?
Redis 的缓存
机器意外发生了全盘宕机挂了,所有请求全部落在 DB上,超出DB的最大承受能力,导致DB 直接被大量流量干死。
缓存雪崩的事前事中事后的解决方案如下:
- 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
- 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。
- 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
用户发送一个请求,系统 A 收到请求后,先查本地 ehcache 缓存,如果没查到再查 Redis。如果 ehcache 和 Redis 都没有,再查数据库,将数据库中的结果,写入 ehcache 和 Redis 中。
限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空值。
好处:
- 数据库不死,就有机会,限流确保了每秒只有多少个请求能通过。
- 对用户来说,意味着你的系统没死,可能就是多点击几次刷页面
穿透
假设系统 A,一秒 5000 个请求,结果其中 4000 个请求是黑客发出的
恶意攻击。缓存中查不到,每次去数据库里查,也查不到,这种恶意攻击场景的缓存穿透就会直接把数据库给打死。
解决(n)方式:
方式1:很简单的操作,就是去db查询的时候,发现也不存在,那就写入一个空值到缓存中去,设置一个过期时间,这样下次有相同的key过来,就从缓存中取,只要缓存没过期。
方式2: 利用布隆过滤器,在缓存之前增加布隆过滤器,将数据库中所有可能的数据哈希映射到布隆过滤器中。对每个请求进行判断是否存在布隆过滤器中,如果不存在,数据库中一定没有,如果存在,再去redis缓存中查询,
布隆过滤器特点:过滤器中不存的hashkey,数据库中必定不存在,但是,hashkey存在时,数据库不一定存在,因为这个hashkey值可能上其他数据计算出的二进制位,布隆过滤器本质上是一个二进制的数组,每一位初始值都是0,计算一次hashkey某位上值就是1,但是这个1,不一定就是你的。
击穿
就是说 某个 key 非常热点,访问非常频繁, 集中式高并发访问, 当这个key在失效的瞬间,持续性的大量请求,直接到了DB,就像凿穿了墙一样。
不同场景下的解决方式可如下:
- 若缓存的数据是基本不会发生更新的,则可尝试将该热点数据设置为永不过期。
- 采用二级缓存caffeine+redis
- 若缓存的数据更新不频繁且缓存刷新耗时较少的情况下,则可以采用基于 Redis、zookeeper 等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存。
- 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存。