缓存预热雪崩击穿穿透
面试题
缓存预热、雪崩、穿透、击穿分别是什么?遇到过哪几种情况?
缓存预热是怎么做的?
如何避免或者减少缓存雪崩?
穿透和击穿有什么区别?他俩是一个意思还是截然不同?
穿透和击穿你有什么解决方案?如何避免?
加入出现了缓存不一致,你有哪些修补方案?
参考: https://xiaolincoding.com/redis/cluster/cache_problem.html
缓存预热
Redis缓存预热是一种在应用程序启动或数据更新之前,提前将一些数据加载到Redis缓存中的过程,这样可以提高后续对这些数据的访问速度和性能。
缓存预热的主要目的是在应用程序开始服务请求之前,确保缓存中已经存在一部分重要的数据,以便在实际请求到达时能够快速地响应。这样可以避免因为第一次访问时需要从数据库或其他数据源加载数据而导致的延迟,提高了系统的响应速度和性能。
进行缓存预热通常涉及以下几个步骤:
-
识别关键数据:首先,需要了解应用程序中哪些数据是频繁访问的或者是最重要的。这些数据通常是经常被查询或者在应用程序中频繁使用的数据。
-
编写预热脚本:根据识别到的关键数据,编写预热脚本来加载这些数据到Redis缓存中。预热脚本通常会从数据库或其他数据源中读取数据,并将其逐一存储到Redis中。
-
选择合适的时机:确定何时执行缓存预热操作。这可以在应用程序启动时执行,或者可以定期执行预热操作,例如每天的低峰时段或者在系统负载较低的时候执行。
-
执行预热操作:在选择的时机执行预热脚本,将数据加载到Redis缓存中。确保在执行预热操作时不会对应用程序的正常运行造成影响,避免预热操作导致系统负载过高或者响应变慢。
-
监控和优化:监控预热操作的执行情况,确保预热完成并且缓存中包含了预期的数据。根据实际情况调整预热策略,例如调整预热的时间间隔或者优化预热脚本,以提高缓存预热的效率和性能。
缓存雪崩
缓存雪崩是指在缓存系统中,大量的缓存数据在同一时间失效或者被清除,导致大量的请求直接访问数据库或者其他数据源,从而导致数据库负载急剧增加,甚至引发数据库宕机或系统崩溃的现象。
主要有两种情况:
-
Redis主机挂了,Redis全盘崩溃,偏硬件运维
-
Redis中有大量 key 同时过期大面积失效,偏软件开发
预防 + 解决
-
Redis中key设置为永不过期或者过期时间为指定时间+随机时间,错开同时过期的概率
-
Redis缓存集群实现高可用
主从+哨兵
Redis Cluster
开启Redis持久化机制AOF/RDB,尽快恢复缓存集群
-
多缓存结合预防雪崩
ehcache本地缓存 + Redis缓存
-
服务降级
Hystrix或者阿里sentinel限流&降级
-
人民币玩家
阿里云-云数据库Redis版:https://www.aliyun.com/product/kvstore?spm=5176.54432.J_3207526240.15.2a3818a5iG191E
缓存穿透
介绍
请求去查询一条记录,先查redis无,后查mysql无,都查询不到该条记录但是请求每次都会打到数据库上面去,导致后台数据库压力暴增,这种现象我们称为缓存穿透,这个redis变成了一个摆设。
简单说就是本来无一物,两库都没有,既不在Redis缓存库,也不在mysql,数据库存在被多次暴击风险。
解决
-
空值缓存:对于查询结果为空的请求,也将空值存储到缓存中,但设置一个较短的过期时间,这样可以避免对于相同的无效查询频繁地直接访问数据库。这样即使有恶意的查询请求,也能够通过缓存返回空值,减轻数据库负载。
缺陷:只能解决出现过的无效 key,而且 redis 中的无关紧要的 key(空值key)也会越写越多。
-
布隆过滤器:使用布隆过滤器来快速过滤掉恶意请求。布隆过滤器是一种空间效率高的数据结构,可以快速判断一个元素是否可能存在于集合中。如果查询请求的参数在布隆过滤器中不存在,可以直接拒绝该请求,从而减轻数据库的负载。
-
缓存预热:在应用程序启动或者数据更新之后,提前将一部分常用的数据加载到缓存中。这样可以避免在应用程序启动或者热点数据失效后导致大量请求直接访问数据库。缓存预热可以通过定期执行预热脚本来实现。
-
数据库层面防御:在数据库层面可以采取一些措施来防御缓存穿透,例如在应用程序中校验查询参数的合法性,只有合法的查询才会被发送到数据库中进行处理。
缓存击穿
介绍
我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频地访问的数据被称为热点数据。
如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
大量请求同时查询一个 key 时,此时这个 key 正好失效了,就会导致大量的请求都打到数据库,简单点就是热点 key 突然失效了,暴打 MySQL。
解决
为了解决缓存击穿问题,可以采取以下几种措施:
-
加锁更新缓存:在缓存失效时,只允许一个请求去查询数据库并更新缓存,其他请求等待该请求完成后再从缓存中获取数据,避免了大量请求同时直接访问数据库。
-
设置热点数据永不过期:对于一些热点数据,可以设置其在缓存中永不过期,或者设置一个较长的过期时间,这样可以避免热点数据在缓存中失效时引起缓存击穿问题。
永不过期实际包含两层意思:
- 物理不过期,针对热点key不设置过期时间
- 逻辑过期,把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建。
-
双key策略:主key设置过期时间,备key不设置过期时间,当主key失效时,直接返回备key值。
- 构建多级缓存架构: nginx缓存 + redis缓存 +其他缓存(ehcache本地等)
- 将缓存失效时间分散开: 比如我们可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。