连载中 16/20

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

2026-06-02 · 3516 阅读 · 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)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞