一.面试题的引入
问:
什么是 Redis 的雪崩、穿透和击穿?应该怎么应对?
分析:
这是缓存的必问问题,因为缓存的雪崩和穿透是最大的两个问题,要么不出现,出现就是致命问题
二.Redis 的雪崩、穿透和击穿
雪崩
1. 什么是 Redis 的雪崩
假设服务的高峰期每秒接收 5000 次请求,其中 Redis 的能力是每秒处理 4000 次,原本超出的范围不大,落到数据库身上也可以扛得住,但是如果 Redis 突然挂掉,请求全都落到数据库身上,数据库会告警一下然后就会被压垮,这时候重启数据库也会被瞬间打死,这就是 Redis 的雪崩。
2. 如何应对 Redis 雪崩
应对 Redis 的雪崩分为事前、事中、事后三种处理方法
事前:
redis 高可用,使用主从+哨兵的集群模式,避免全盘崩溃
事中:
使用本地缓存(例如ehcache)+hystrix 限流&降级,避免数据库被打死(这种模式下也必须提前设计好,确定实行限流或降级操作后的请求量不至于将数据库打死)
事后:
redis 持久化,redis 发生故障重启后,自动从磁盘加载数据,快速恢复缓存能力
穿透
1. 什么是 Redis 穿透
缓存穿透是个顾名思义的场景,就是查询一定不存在的数据的请求到来时,在缓存中没有命中而需要去数据库查询,但是数据库依然查询不到,这样也就不会将这条请求的相关内容写入到缓存中去,如果有大量的这种请求同事发生,那么数据库就很可能会挂掉,这点很容易被别有用心的人利用。
2. 如何应对 Redis 穿透
简单粗暴的办法,就是将返回为空的数据缓存到 Redis 中,但是配合 Redis 过期时间策略,这种数据的存在时间可能会很短。
将所有可能的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。
击穿
1. 什么是 Redis 击穿
如果某个 key 非常热点,访问非常频繁,在这个 key 失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,这就是 Redis 击穿。
2. Redis 击穿的解决方法
如果这条热点数据的内容是几乎不会发生改变的,那么可以尝试将该数据设置为永不过期
如果该数据更新不频繁,且缓存刷新的整个流程耗时较少的情况下,可以采用与 redis、zookeeper 等分布式中间件的分布式互斥锁或者本地互斥锁来保证仅有少量的请求可以请求数据库并重建缓存,其余线程则只有等到锁被释放后才能够访问到新缓存。
如果该数据更新频繁或者缓存刷新流程较长,可以利用定时线程在缓存期前主动地重构缓存或者延后缓存的过期时间,以保证所有的请求都能一直访问到对应的缓存。
三.降级、熔断及限流
降级
降级也就是服务降级,当我们的服务器压力骤增时,为了保证核心功能的可用性,而选择性的降低一些功能的可用性,甚至直接关闭该功能。例如论坛之类的服务,在服务器吃不消的时候,选择把注册、改头像、发帖等功能关闭,只保留登录和阅读帖子的核心功能。
一般而言都会建立一个独立的降级系统,可以灵活且批量的配置服务器的降级功能。当然也有用代码自动降级的,例如接口超时降级、失败重试多次降级等。具体失败几次,超时设置多久,由业务等其他因素决定。开个会,定个值,扔线上去看看情况。根据情况再调优。
熔断
一般而言指依赖的外部接口出现故障的情况断绝和外部接口的关系。
例如服务 A 中的一个功能以来服务 B,但是服务 B 出问题了,返回很慢或者超时,这时候可能会拖慢所有服务 A 中的其他功能,这时候就需要熔断,也就是直接不去请求 B 了。如果不熔断,很可能会引发雪崩。
熔断也需要设定阈值,达到阈值就进行熔断,比如 5分钟内 50% 的请求都超过 1秒等。
限流
限流就是,系统规定了能承受多少请求就只放这些请求进来,其他一律阻断掉。
一般限制的指标为请求总量或者某段时间内请求总量
请求总量为指标典型的场景就是秒杀,比如秒杀 10 件商品,只允许进来100个请求,其他直接拒绝。
时段内请求总量的场景,比如规定服务器每秒请求峰值为 10000 次,一秒内超过 10000 次就直接拒绝。