实时性高的数据应采用“极短ttl+主动刷新+精准失效”三级缓存策略:基础层设1–5秒ttl并惰性校验;协同层写后立即幂等删缓存;增强层加本地缓存与版本号控制,确保低延迟与最终一致性。

实时性要求高的数据,比如账户余额、实时库存、交易订单状态、风控评分等,不适合设长缓存,但也不能完全不缓存——全走数据库会扛不住并发,也浪费资源。关键在于:用“极短有效期 + 主动刷新 + 精准失效”组合策略,把缓存变成一个可控的“临时快照”,而非静态副本。
缓存有效期不能只靠 EXPIRE 硬设
单纯设置 1 秒或 5 秒过期,看似“短”,实则隐患大:
- 过期瞬间可能引发击穿(尤其高并发读同一 key);
- 多个服务实例各自重建缓存,导致重复查库、结果不一致;
- 无法感知业务真实变更时机,该更新时不更新,不该更新时乱更新。
所以真实落地要分三层控制:
-
基础层:极短 TTL + 惰性校验
- 设置 1–5 秒固定过期(如
SETEX key 3 "value"),确保缓存不会长期滞留; - 读取时不做“直接返回”,而是加一层轻量校验逻辑:若缓存存在且距写入时间
- 设置 1–5 秒固定过期(如
-
协同层:变更即失效,不等过期
- 所有写操作(如余额变动、库存扣减)完成后,立刻删除对应缓存 key(不是更新,是删);
- 删除动作要幂等、快速,建议用 pipeline 或 lua 脚本批量处理关联 key(如
user:balance:1001和account:summary:1001); - 避免“先删后写”或“先写后删”的竞态,统一走“写库成功 → 删缓存 → 发消息通知其他节点删”。
-
增强层:本地缓存兜底 + 版本号控制
- 在应用进程内加一级 LRU 本地缓存(如 Caffeine),容量小(100–500 条)、TTL 更短(200–500ms),用于拦截高频重复请求;
- 给缓存 value 包裹结构体,含
version(来自数据库 update_time 或 version 字段)和timestamp,读取时比对版本,旧版本自动丢弃并触发刷新。
实际例子:用户实时余额查询
// 查询逻辑伪代码
String cacheKey = "balance:user:" + userId;
String cached = redis.get(cacheKey);
if (cached != null) {
BalanceCacheDto dto = parse(cached);
// 本地缓存未超时、且版本未落后于当前窗口允许偏差
if (System.currentTimeMillis() - dto.timestamp = getCurrentMinVersion()) {
return dto.balance;
}
}
// 触发重建:加分布式锁防击穿,查库,写新缓存(TTL=3秒),删旧本地缓存
rebuildBalanceCache(userId);
这样既避免了数据库被刷爆,又保证绝大多数请求看到的是
不复杂但容易忽略。











