Cache-Aside 的基本顺序是“读缓存,未命中再读数据库并回填;更新数据库后删除缓存”。它不能自动解决所有异常流量,需要针对穿透、击穿和雪崩分别治理。
Table of contents
Open Table of contents
先运行 Cache-Aside
CacheAsideService.java下载实现了最小流程:
Optional<String> cached = cache.get(key);
if (cached.isPresent()) return decode(cached.get());
Optional<String> value = repository.findProduct(id);
cache.put(key, value.orElse(NULL_SENTINEL), ttl);
return value;
mvn -Dtest=CacheEngineeringTest#cacheAsideCachesValuesAndShortLivedNulls test
空值使用 30 秒短 TTL,正常值使用 300 秒加随机抖动。这样既阻挡短时间重复查询不存在 ID,也避免大量 Key 在同一秒集中过期。
三种故障的区别
| 问题 | 发生方式 | 常用手段 |
|---|---|---|
| 穿透 | 请求的数据本来就不存在 | 参数校验、空值缓存、布隆过滤器 |
| 击穿 | 单个热点 Key 过期,大量请求回源 | 请求合并、互斥重建、逻辑过期、预热 |
| 雪崩 | 大批 Key 或整个缓存同时不可用 | TTL 抖动、多级缓存、限流、降级、隔离 |
布隆过滤器是一种概率集合:它能确定“肯定不存在”,但“可能存在”会有假阳性。删除、容量和误判率必须预先设计;过滤器说存在后仍要查询真实数据源。
请求合并比无限等锁更安全
同一进程可让首个请求回源,其余请求等待同一个 Future;等待要有超时和失败清理。跨实例互斥仍可能因租约过期重复回源,所以数据库必须能承受受控并发,并配合限流和熔断。
缓存完全失效是必测场景。压测应关闭缓存或清空一批 Key,确认回源速率、数据库连接池和降级策略不会级联崩溃。
下一步
继续阅读07-08 缓存与数据库一致性,分析并发读写下删除缓存为什么仍可能留下旧值。