Java 缓存雪崩处理指南
一 概念与成因
二 预防策略
三 故障与降级处理
四 Java 代码示例
// 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);
}
// 本地缓存: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");
}
// 初始化熔断规则: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、互斥锁、多级缓存、逻辑过期与限流降级的典型落地方式,可按业务特性组合使用。
五 落地检查清单
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。