缓存雪崩

相关场景

假如系统高峰期QPS是5000(每秒5000个请求),本来缓存在高峰期可以每秒扛住4000请求,但是缓存机器以外发生了全盘宕机,就会导致高峰期的1秒5000个请求都落在了数据库,数据库扛不住就挂了。如果系统本身没有对此做好必要的措施(比如缓存持久化等),那么数据库重启之后,还是会被新的流量打死。

缓存雪崩的解决方案

  • 事前:redis高可用,主从架构+哨兵集群,redis cluster,避免全盘崩溃。
  • 事中:本地ehcache缓存+hystrix限流&降级,避免MySQL被打死。
  • 事后:redis持久化,一旦重启,可以自动从磁盘中加载数据,快速回复缓存数据。

用户发送一个请求,系统A收到请求后,先查本地ehcache缓存,如果没查到,再查redis。如果ehcache和redis都没有,再去查MySQL。
对于大量的请求,系统可以设置每秒的请求数,超过这个请求数的请求,就可以做降级操作(拒绝请求,返回默认值,返回提示信息或者返回空值)。

好处:
(1)可以避免大量请求访问数据库,导致数据库被打死。因为限流组件能确保每秒只有多少个请求能通过。
(2)只要数据库不死,对于用户来说,40%的请求是可以被处理的。
(3)只要40%的请求可以被处理,就意味着系统没死。对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就能刷出来一次。

缓存穿透

相关场景

对于系统A,假设每秒有5000个请求,但其中有4000个请求是黑客发出的恶意攻击请求。恶意请求在缓存里面查不到结果数据,就会去数据库查,数据库也查不到。
比如,数据库id是从1开始的,结果黑客发过来的请求id全部都是负数,这样的话,缓存中不会有,请求每次都会“视缓存为无物”,直接查询数据库。这种恶意攻击场景的缓存穿透就会直接把数据库给打死。

缓存穿透的解决方案

(1)缓存无效的key
每次系统A从数据库中只要没查到数据,就写一个空值到缓存里去,比如 set -999 UNKNOWN ,然后设置一个过期时间,这样的话,下次有相同的key来访问的时候,在缓存失效之前,都可以直接从缓存中取出数据。
(2)制定过滤规则,过滤不可能存在的数据。
比如订单id或者用户id明显在一个范围内,如果不是这个范围内的数据可以直接过滤掉。
(3)布隆过滤器

缓存击穿

相关场景

热点数据对应的缓存失效。
比如某个key非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个key失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像在一道屏障上凿开一个洞。

缓存击穿的解决方案

可以设置热点数据为永不过期。
基于redis或者zookeeper实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其他请求才能通过该key访问数据。