redis缓存失效问题

avatar
作者
猴君
阅读量:2

缓存时效问题

缓存穿透

问题说明:指大量请求缓存中不存在的数据,导致这些请求都访问备用数据源(如数据库、外部服务等),从而引起系统资源浪费和性能问题。
解决方案:有“参数校验”、“缓存空值”、“布隆过滤器检测记录ID存在性”3种。使用布隆过滤器的方案较为复杂,建议优先考虑参数校验、缓存空值。

  1. 参数校验:通过参数校验拦截非法请求,避免不必要的查询。
  2. 缓存空值:数据源查询结果为空时,将Redis缓存值设置为特殊值,以标识记录不存在。具体流程如下图所示。


3. 布隆过滤器检测记录ID存在性:利用布隆过滤器以较小的内存开销、时间复杂度实现存在性判断,具体用法如下。
1)基于数据库记录初始化布隆过滤器;
2)新增记录时,同步将该记录的ID添加到布隆过滤器里;
3)查询Redis缓存前,先使用布隆过滤器检查。如果布隆过滤器判断不存在,则记录一定不存在。如果布隆过滤器判断可能存在,才会查询Redis。

在这里插入图片描述


使用布隆过滤器时,不易支持删除记录的场景,目前只提供简单的Gauva的示例,会冗余存储在各个应用实例,且一致性较低(新增记录生效延迟),若使用Redis存储Bloom过滤器的数据需考虑Redis中的数据丢失等问题。

  1. 缓存击穿
    问题说明:指在高并发情况下,一个热点key失效或未缓存时,大量请求同时访问备用数据源(如数据库、外部服务等),导致备用数据源压力过大甚至宕机的情况。
    解决方案:有“控制并发量”、“二级缓存”、“双key”、“后台刷新热数据”4种。优先考虑控制并发量,对响应时间较敏感的情况可同时考虑二级缓存或双key。
  2. 控制并发量: 如果热点key在缓存中不存在,将通过控制访问备用数据源的并发量,避免对备用数据源造成冲击。 如果当前场景实例较多、请求量较大,可以考虑使用分布式锁控制并发,否则可基于简化实现的角度考虑使用Java提供的互斥锁、限制连接池的最大连接数等机制。
    在这里插入图片描述


该方案如上图所示,若干个线程同时请求,第一个到达的线程会加锁,后续线程只能阻塞等待,直到第一个线程执行完。
2. 二级缓存: 使用互斥锁只允许一个线程更新缓存,其他线程需要等待。为了解决该问题,可以结合业务场景考虑添加“二级缓存”方案。 具体为,使用Redis缓存(A1)和本地缓存(A2)两个缓存,A2缓存过期时间长于A1。A1失效时,第一个线程将会去数据源中查询,其他线程可以先返回A2缓存中的数据,避免等待。
3. 双key: 也可以用“双key”方案分别缓存“缓存过期时间”和”缓存数据”,解决其他线程等待的问题。具体流程为:
1)如果“缓存过期时间”Key过期,则更新该Key;
2)若某个线程成功更新“缓存过期时间”Key,该线程将会从数据源获取数据并更新”缓存数据”Key;
3)其他线程将会直接获取”缓存数据”Key的旧数据并返回。

在这里插入图片描述


4. 后台刷新热数据: 通过定时任务后台刷新,避免热点数据丢失。该方案需考虑区分业务上的热点数据和非热点数据,且要设置合理的过期时间,不推荐使用。

  1. 缓存雪崩
    问题说明:指因Redis故障、操作不当等原因导致缓存中大量的键同时失效,导致所有相关的请求都落到了备用数据源(比如数据库),从而造成备用数据源瞬间压力过大甚至宕机的情况。
    解决方案:有“控制并发量”、“设置适当的过期时间”、“拷贝缓存”、“熔断”4种方案。通常采用“熔断”方案,对于采用双活实例部署架构的场景可同时考虑双活实例的“拷贝缓存”。
    具体方案如下:
  1. “控制并发量”:参考“缓存击穿”部分中的“控制并发量”方案,控制请求备用数据源的并发量;
  2. “设置适当的过期时间”:为Key的过期时间合理设置随机偏移量以打散过期时间;
  3. “拷贝缓存”:对于采用“双活实例”部署架构提升Redis缓存层高可用的场景,可考虑拷贝缓存以降低Redis雪崩的概率;
  4. “熔断”: 可根据错误率、响应时间等设置熔断机制。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!