Redis——缓存雪崩

文章目录

  • [1. 问题介绍](#1. 问题介绍)
  • [2. 解决方案](#2. 解决方案)
    • [2.1 方案一:随机过期时间](#2.1 方案一:随机过期时间)
    • [2.2 方案二:增强 Redis 集群的可用性](#2.2 方案二:增强 Redis 集群的可用性)
    • [2.3 方案三:多级缓存](#2.3 方案三:多级缓存)
      • [2.3.1 做法](#2.3.1 做法)
      • [2.3.2 流程](#2.3.2 流程)
      • [2.3.3 示例代码](#2.3.3 示例代码)
      • [2.3.4 评价](#2.3.4 评价)
    • [2.4 方案四:限流](#2.4 方案四:限流)
  • [3. 总结](#3. 总结)

1. 问题介绍

缓存雪崩:大量缓存同时过期,或 Redis 宕机,导致大量请求访问 MySQL 数据库,导致其承受不住压力而宕机。

2. 解决方案

从问题介绍中可以发现,对于大量缓存同时过期的情况,只要让缓存的过期时间不同即可;对于 Redis 宕机的情况,则可以通过 增强 Redis (集群) 的可用性、多级缓存、限流 等方案解决。

2.1 方案一:随机过期时间

在缓存数据时,给固定的过期时间加上一个随机值,例如对于原本 10min 过期的数据:

java 复制代码
redisTemplate.opsForValue().set("key", "value", 10, TimeUnit.MINUTES);

通过 new Random().nextInt(10) (获取随机值还可以使用别的方法,并不局限于此) 给它加上一个 60s 以内随机值,从而避免大量数据同时在 10min 这一时刻过期,而是将其分散到 10min 后的 1min 时间段内过期。

java 复制代码
redisTemplate.opsForValue().set("key", "value", 600 + new Random().nextInt(60), TimeUnit.SECONDS);

2.2 方案二:增强 Redis 集群的可用性

可以通过 Redis 的集群模式或哨兵模式来达到 Redis 的高可用 (之后会讲)。

2.3 方案三:多级缓存

2.3.1 做法

除了使用 Redis 这样的分布式缓存中间件之外,还可以使用 Caffeine、Guava 这样的框架实现应用内部的本地缓存,这样可以减轻 MySQL 的访问压力。

2.3.2 流程

Created with Raphaël 2.3.0 开始 从本地缓存中获取 本地缓存是否为 null? 从 Redis 中获取 Redis 缓存是否为 null? 从数据库中获取 数据库中有没有这个数据? 将数据缓存到 Redis 将数据缓存到本地 返回数据 结束 yes no yes no yes no

2.3.3 示例代码

java 复制代码
public Order get(long orderId) {
    // 先从 Caffeine 缓存中获取
    Order order = caffeineCache.getIfPresent(orderId);
    if (order == null) {
    	String key = "order:" + orderId;
        // 如果 Caffeine 缓存未命中,再从 Redis 缓存中获取
        order = (Order) redisTemplate.opsForValue().get(key);
        if (order == null) {
        	// 如果 Redis 缓存未命中,从 MySQL 中获取
        	order = orderMapper.getById(orderId);
	        if (order != null) {
		        // 将数据放入 Redis 缓存
		        redisTemplate.opsForValue().set(key, order, 3, TimeUnit.MINUTES);
	        }
        }
        if (order != null) {
	        // 将数据放入 Caffeine 缓存
	        caffeineCache.put(orderId, order);
        }
    }
    return order;
}

2.3.4 评价

一般情况下,使用本地缓存的响应时间会少一点,因为避免了分布式缓存的网络 IO 时间。但这种方案实现起来比较复杂 (查询时需要查询两级缓存,更新时也一样),而且由于缓存在本地,还对服务器的内存有一定的要求。

2.4 方案四:限流

限流也可以避免缓存雪崩的问题,通过限制一个接口的访问量,从而防止大量请求通过,压垮 MySQL。

3. 总结

缓存雪崩指的是由于大量缓存同时过期或 Redis 宕机,导致大量请求直接访问 MySQL,以致其宕机的问题。

缓存雪崩还是很好理解的,不同问题的应对方案如下:

  • 对于大量缓存同时过期的问题,可以采取设置随机的过期时间来解决。
  • 对于预防 Redis 宕机,可以通过 Redis 的集群模式或哨兵模式来保证其高可用性。
  • 对于 Redis 宕机后的处理,可以使用多级缓存,在本地也缓存一份数据。
  • 无论应对缓存雪崩的哪种问题,都可以通过限流来解决,防止大量请求访问 MySQL。
相关推荐
云和数据.ChenGuang4 分钟前
用 Claude Code 重构遗留系统:从评估到落地的完整指南
java·人工智能·spring boot·后端·重构·springai
霸道流氓气质7 分钟前
AI 应用异常检测与根因分析:语义漂移检测、因果图推理与LLM-as-Judge的 Java 生产级实现
java·开发语言·人工智能
xuxigifxfh15 分钟前
牛客:BISHI2 【模板】栈的操作
java·开发语言·windows·算法
房开民36 分钟前
通俗总结 Octree(八叉树)
java·服务器·数据库
2302_805771071 小时前
Day23:POM设计模式(封装)
java·开发语言·设计模式
SL_staff1 小时前
APS降本增效的关键:在JVS中实现‘人-机-料-法-环’全要素耦合调度
java·github·全栈
十年Java程序媛1 小时前
Java String、StringBuilder、StringBuffer 底层原理|字符串拼接性能与线程安全
java·开发语言·spring boot·安全·面试
鱼宵1 小时前
LangChain4j 生产化改造:记忆落 Redis、向量落 ES,重启再也不丢
数据库·redis·elasticsearch·langchain4j
SamDeepThinking1 小时前
CyclicBarrier的底层实现
java·后端·面试
我是人✓1 小时前
SpringMVC异常处理与拦截器实战揭秘
java·开发语言·后端