温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java Cache缓存:如何处理缓存雪崩

发布时间:2025-12-12 01:32:41 来源:亿速云 阅读:170 作者:小樊 栏目:编程语言

Java 缓存雪崩处理指南

一 概念与成因

  • 缓存雪崩指在同一时间大量缓存条目失效或被清空,导致请求洪峰直达数据库,引发数据库过载甚至雪崩扩散。常见成因包括:大量 key 设置了相同的过期时间;缓存集群宕机/重启/分片重哈希导致瞬时不可用;突发流量洪峰压垮部分节点并蔓延;系统配置或资源问题造成缓存异常清空。预防思路是让失效时间错峰、提升缓存层可用性、在过载时限流降级保护后端。

二 预防策略

  • 错峰过期:为每个 key 的 TTL 增加随机抖动(如基础 1 小时 + 0~10 分钟随机),避免集中失效。适用于首页、推荐、列表等批量加载场景。
  • 多级缓存:组合本地缓存(Caffeine)+ 分布式缓存(Redis),即使分布式缓存抖动,本地缓存仍能提供兜底命中,显著降低穿透到 DB 的 QPS。
  • 缓存预热:系统启动或发布后,主动加载热点数据到缓存;结合业务访问画像定期刷新热点,减少高峰期的首次击穿。
  • 高可用架构:部署Redis 集群/主从 + 哨兵或集群模式,避免单点;对热点数据配置副本,在节点异常时仍可读取副本分流。
  • 限流降级与熔断:在访问压力或错误率异常时,对 DB 读请求限流/熔断/快速失败,保障核心链路可用(如基于 Sentinel 的规则配置)。
  • 异步刷新与逻辑过期:对读多写少的热点数据采用逻辑过期(缓存不设置物理 TTL),后台异步更新,避免重建缓存的同步阻塞与峰值冲击。

三 故障与降级处理

  • 读开关与快速失败:当监测到 DB 响应变慢或慢查询激增,临时关闭部分读 DB 开关,业务侧 failfast 返回兜底数据或默认值,待 DB 恢复后再开启。
  • 多副本容错:同一数据在多个缓存副本中保存,客户端在命中失败时自动切换到其他副本,将异常隔离在局部,避免级联扩散。
  • 实时监控与告警:对缓存命中率、延迟、异常率、节点存活等指标实时监控与阈值告警,配合自动降级/替换异常实例,缩短恢复时间。

四 Java 代码示例

  • 随机 TTL 防止集中失效
// TTL 基础 1 小时 + 0~600 秒随机抖动
int baseTtl = 3600;
int randomTtl = baseTtl + new Random().nextInt(600);
redisTemplate.opsForValue().set(key, value, randomTtl, TimeUnit.SECONDS);
  • 互斥锁重建缓存(防止并发击穿引发雪崩)
String lockKey = "lock:" + key;
Boolean acquired = redisTemplate.opsForValue()
    .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS); // 锁过期兜底
if (Boolean.TRUE.equals(acquired)) {
    try {
        // 双重检查
        Product v = (Product) redisTemplate.opsForValue().get(key);
        if (v == null) {
            v = productRepository.findById(id).orElse(null);
            if (v != null) {
                redisTemplate.opsForValue().set(key, v, 1800 + new Random().nextInt(600), TimeUnit.SECONDS);
            } else {
                // 可选:缓存空对象,短 TTL,防穿透
                redisTemplate.opsForValue().set(key, NullProduct.INSTANCE, 60, TimeUnit.SECONDS);
            }
        }
    } finally {
        redisTemplate.delete(lockKey);
    }
} else {
    // 未抢到锁,短暂等待后重试或直接返回兜底
    Thread.sleep(100);
    return getProductById(id);
}
  • 多级缓存(Caffeine + Redis)
// 本地缓存:5 分钟写后过期
Cache<Long, Product> localCache = Caffeine.newBuilder()
    .expireAfterWrite(5, TimeUnit.MINUTES)
    .build();

public Product getProduct(Long id) {
    return localCache.get(id, k -> {
        Product v = (Product) redisTemplate.opsForValue().get("product:" + k);
        if (v == null) {
            v = productRepository.findById(k).orElse(null);
            if (v != null) {
                int ttl = 1800 + new Random().nextInt(600);
                redisTemplate.opsForValue().set("product:" + k, v, ttl, TimeUnit.SECONDS);
            }
        }
        return v;
    });
}
  • 逻辑过期 + 后台刷新(读多写少热点)
// value 内包含逻辑过期时间:{data: ..., exp: 1734019200}
public Product getWithLogicalExpire(String key) {
    Map<String, Object> wrapper = (Map<String, Object>) redisTemplate.opsForValue().get(key);
    if (wrapper == null) return null;
    long now = System.currentTimeMillis() / 1000;
    if (now < (long) wrapper.get("exp")) {
        return (Product) wrapper.get("data");
    }
    // 过期则异步刷新,当前请求仍返回旧数据
    executor.submit(() -> {
        Product fresh = productRepository.findById(idFromKey(key)).orElse(null);
        if (fresh != null) {
            long newExp = now + 1800; // 新的逻辑过期时间
            Map<String, Object> w = new HashMap<>();
            w.put("data", fresh);
            w.put("exp", newExp);
            redisTemplate.opsForValue().set(key, w, 0); // 不设置物理 TTL
        }
    });
    return (Product) wrapper.get("data");
}
  • 限流降级示例(Sentinel)
// 初始化熔断规则:5 个异常在 10 秒内触发熔断,窗口 10 秒
List<DegradeRule> rules = new ArrayList<>();
DegradeRule r = new DegradeRule("getHotspotData")
    .setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
    .setCount(5).setTimeWindow(10);
DegradeRuleManager.loadRules(rules);

// 使用
Entry entry = null;
try {
    entry = SphU.entry("getHotspotData");
    return getData(key);
} catch (BlockException ex) {
    return fallback(key); // 降级返回
} finally {
    if (entry != null) entry.exit();
}

以上示例分别展示了随机 TTL、互斥锁、多级缓存、逻辑过期与限流降级的典型落地方式,可按业务特性组合使用。

五 落地检查清单

  • 缓存键的 TTL 是否都加入了随机抖动,避免批量同时失效。
  • 热点数据是否已配置多级缓存与异步刷新策略。
  • 是否具备缓存预热机制与定时任务,覆盖高峰访问路径。
  • 缓存集群是否启用高可用(主从/哨兵/集群)与副本容错。
  • DB 访问是否接入限流/熔断/降级,并具备读开关能力。
  • 是否建立监控告警(命中率、延迟、异常、节点存活)与应急预案(降级、切换、回滚)。
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手