连载中 16/20

多级缓存:本地与分布式的合璧

2026-06-02 · 3513 阅读 · 0 评论 · 0 赞

再快也有一次往返

Redis 已经把查库的十毫秒压到一毫秒以内,为什么还要更快?看一组数:同机房 Redis 一次网络往返约 0.5~1ms,加上序列化、连接池排队,一次缓存读的实际成本在毫秒级;而进程内存里的本地缓存是纳秒到微秒级,差着三个数量级。万级 QPS 的服务里,毫秒与微秒的差就是 CPU 与线程池的真金白银。热 Key 篇已经埋了伏笔:本地缓存扛第一波,本篇把这个思路补完——L1 本地缓存(Caffeine/Guava)+ L2 分布式缓存(Redis)+ 数据库的三级读路径。

读路径:逐级往下找

完整的多级读链路是一条漏斗:请求先查 L1,命中直接返回(纳秒级,扛住绝大多数热读);未命中查 L2 Redis,命中后回填 L1再返回;再未命中才回源 DB,结果同时灌进 L2 和 L1。每往下一级,成本涨一个量级,所以漏斗的设计目标就是让流量尽量停在最上层

Cache<String, String> l1 = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(Duration.ofSeconds(10))   // L1: 秒级短TTL
    .recordStats()
    .build();

public String get(String key) {
    String v = l1.getIfPresent(key);            // L1 命中:纳秒级
    if (v != null) return v;
    v = redis.get(key);                         // L2 命中:亚毫秒级
    if (v != null) { l1.put(key, v); return v; }
    v = loadFromDb(key);                        // 回源:毫秒级
    redis.setex(key, ttl(key), v);
    l1.put(key, v);
    return v;
}

注意 L1 的 TTL 是秒级的,远短于 L2——这是有意为之:本地副本存活越久,脏得越久,短 TTL 是控制脏窗口的第一道闸。

真正的难题:多实例一起失效

单实例的失效好办,多级缓存的麻烦在于:数据变了,几十个应用实例各自的 L1 都得知道。Redis 是共享的,删一次全体生效;Caffeine 是进程私有的,删自己的不删别人的。主流解法是失效广播:数据变更方把「删 key」的事件发到 Redis Pub/Sub 或 MQ,所有实例订阅,收到就清掉自己 L1 里对应的 key;广播丢了也没关系,L1 的秒级 TTL 兜底,脏窗口封顶十秒:

变更方:update db ──> del redis ──> publish "evict:item:10086"
各实例:subscribe 收到消息 ──> caffeine.invalidate(key)

延迟敏感的场景可以把广播换成 binlog 订阅触发(第 7 篇的链路直接复用),变更方代码一行不加。

边界:不是什么数据都配进 L1

多级缓存是重装备,准入门槛要守住:极热——单 key QPS 数千以上才值得(热 Key 篇的判定标准);读多写少——数据频繁变,L1 就是脏数据分发的帮凶;容量可控——本地缓存吃的是应用进程的堆内存,maximumSize 必须设。典型适合的是商品详情、配置、白名单、词典数据;典型不适合的是库存、余额这类强一致数据——它们的问题域在一致性篇,不在性能篇。

多级架构立起来之后,评价它好不好只有一个数字说了算:命中率。下一讲把这个缓存体系最重要的指标讲透。

503

10 年全栈工程师 · 503咖啡馆主理人

#多级缓存#本地缓存#Caffeine#失效广播#读路径

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞