面试中,只要聊到缓存,基本都会问到缓存雪崩以及缓存穿透怎么解决。
其实这两个问题不难,是使用缓存过程中可能会出现的最大的问题。
1、缓存雪崩
缓存雪崩是指缓存机器故障或宕机,导致全部请求走数据库,引起数据库压力过大甚至宕机。
解决方案:
缓存雪崩式是解决不了的,只能说降低发生的可能性。
应对缓存雪崩,一般分3步走:
-
事前:redis高可用部署,避免全盘崩溃;
-
事中:本地缓存 + 限流降级,避免数据库被打死;
-
事后:redis持久化,快速恢复缓存数据;
缓存使用高可用部署方式,redis可以部署哨兵模式,也可以部署集群模式。
图1 redis高可用
只是redis高可用部署是不够的,还需要在系统内部再做一个二级缓存,具体实现方式有很多,可以用map、ehcache、guava cache等等。
图2 本地缓存
系统内部使用本地缓存,当请求到达系统后,能拦截部分请求。如果redis集群挂掉,本地缓存也能稍微抗一下流量。但本地缓存有限,只能缓存部分数据,不能起到决定性的作用,所以我们还要给系统加上限流和降级。
常用的限流降级框架可以用hystrix和sentinel。
假如每秒有5000个请求,限流框架限制了每秒只能有2000个请求通过,那只有2000个请求通过系统到达数据库,其余的3000个请求就会被拦截走降级措施。
降级可以返回一个固定的网页,比如系统繁忙,稍后重试。这样即使系统扛不住所有的流量,也不至于崩溃,用户请求失败了多试几次还可能成功。
图3 限流降级
事后靠的是redis持久化机制,生产环境可以开启RDB和AOF功能,这样缓存系统如果挂了,重启后能从磁盘上加载数据恢复数据。
缓存穿透
假如系统每秒有5000个请求,系统会根据数据库主键id查出数据,放到缓存里,其中4000个请求是有人恶意攻击发起的,id值小于0,每次缓存里都查不到,直接达到数据库了。大量请求可能就把数据库打死了,然后整个系统就挂了。
图4 缓存穿透
缓存穿透解决方案比较简单,4000个请求id是负数,每次到数据库里查不到,这时候每次数据库里查不到,就写一个空值到缓存里。比如,set id:-892 UNKNOWN。
END