1. 两级缓存的概念与适用场景

1.1 定义:什么是两级缓存

两级缓存(Two-Level Cache)是一种在应用系统与后端数据库之间插入两个不同层级的缓存实例的架构模式。其核心思想是:将访问频率最高的热点数据放在速度最快、容量较小的L1缓存中,将次热点或全部缓存数据放在容量更大、速度稍慢的L2缓存中,从而在整体上达成低延迟、高吞吐的读取效果。

维度 L1 缓存(一级) L2 缓存(二级)
部署位置 应用进程内(如本地堆、嵌入式缓存) 独立进程或分布式中间件(如 Redis、Memcached)
存储介质 进程内存(堆内、堆外、本地磁盘) 独立服务器内存 / SSD 持久化
典型延迟 微秒级(<10 μs) 毫秒级(1-5 ms)
容量上限 MB ~ GB 级别(受限于单机内存) GB ~ TB 级别(可水平扩展)
数据一致性模型 最终一致(通过 TTL / 主动失效) 强一致或最终一致(取决于策略)

1.2 典型业务数据特征

适合两级缓存的数据通常具备以下特征:

  1. 高扇出(Fan-out):同一份数据被大量请求同时读取,例如商品详情、用户基础信息、配置参数。
  2. 有限生命周期:数据变化频率低,且允许短暂的不一致窗口(秒级到分钟级)。
  3. 可枚举性:热点 Key 集合在一定时间段内可被预测或统计。
  4. 低写入频率:写入操作占比远低于读取操作。
特征判据示例:一个业务接口的读写比超过 10:1,且 80% 的流量命中不到 20% 的 Key,即可纳入两级缓存候选范围。

1.3 两级缓存的协同流程(数据流与控制流)

下图展示了两级缓存在一次读请求中的完整数据流、控制流以及信任链路边界。

两级缓存协同流程(读请求路径) Web / App 集群 L1 节点缓存(本机) L2 集群缓存(分布式) L1 本地缓存 L1 本地缓存 Redis 主节点 Redis 从节点 后端数据库 信任链路边界 应用进程内直接访问 L1(不经过网络);L1 与 L2 之间通过内部 RPC 交互;L2 与 DB 通过 JDBC/Redis协议通信

读请求的数据流遵循 L1 → L2 → DB 的逐级回退模式:

  • 步骤 1:请求先到达 Web/App 集群,查询本进程内的 L1 缓存。如果命中且数据未过期(TTL 有效),直接返回,不产生网络开销。
  • 步骤 2:L1 未命中,请求转发至 L2 分布式缓存(如 Redis 集群)。L2 从主节点读取,若命中则返回数据,同时异步回写到 L1。
  • 步骤 3:L2 也未命中,请求穿透到后端数据库。DB 返回数据后,触发“回填”流程:先更新 L2,再更新 L1。
控制流要点:L1 与 L2 之间采用缓存旁路(Cache-Aside)模式,不保持强同步。L1 的失效策略由 TTL + 主动失效通知共同驱动。L2 的失效通过 Redis 的过期策略或 Key 删除实现。

1.4 边界说明与分层职责

架构边界 职责 不负责
L1 边界 存储当前进程最热数据,提供微秒级读写 跨进程数据一致性、持久化、大流量逐出策略
L2 边界 存储全量缓存数据,提供毫秒级读写,支撑水平扩展 进程内数据加载、热点数据淘汰决策
应用层 决定缓存路径、执行降级策略、统计命中率 缓存内部失效机制、数据持久化

1.5 读多写少场景下的选型权衡

在读多写少场景中,两级缓存的主要优势是降低 L2 与 DB 的负载。但同时也带来以下权衡:

  • 一致性 vs. 性能:L1 本地缓存可能持有陈旧数据,需要配置合理的 TTL(如 1-5 秒)来平衡。
  • 内存开销:每个应用节点都维护一份 L1 数据,节点数增加时总内存消耗线性增长。
  • 缓存击穿风险:热点 Key 在 L1 失效后,瞬间大流量穿透到 L2 或 DB,需要配合本地锁或提前预热。
常见误判:不要试图用 L1 缓存替代 L2 的持久化能力。L1 只能作为加速层,不能作为可靠数据源。

1.6 风险点与落地步骤

风险点:

  1. L1 内存泄漏:缓存 Entry 未设置 TTL 或逐出策略,导致堆内存持续增长。
  2. L2 单点故障:Redis 主节点宕机,L2 整体不可用,流量直接打穿到 DB。
  3. 数据一致性问题:L2 更新后,L1 仍返回旧数据,导致业务异常。

落地步骤(第一阶段):

  1. 选定 L1 缓存组件(如 Caffeine、Guava Cache)与 L2 缓存组件(如 Redis Cluster)。
  2. 定义 TTL 基线:L1-TTL = 5s,L2-TTL = 60s。
  3. 实现 Cache-Aside 拦截器,嵌入数据访问层。
  4. 集成监控:统计 L1 / L2 / DB 各级命中率与延迟。
  5. 设置容量上限:L1 最大条目数 = 10,000,单条目最大 1MB。
缓存组件选型示例:
L1: Caffeine (Java) / node-cache (Node.js) / memcached (Go)
L2: Redis 6.x+ Cluster 或 Aliyun Redis 企业版
配置:L1 最大内存 512MB,TTL 5s;L2 最大内存 20GB,TTL 60s

1.7 验收标准

验收项 通过条件
L1 命中率 在典型业务流量下,L1 命中率 ≥ 80%
请求延迟 P99 读延迟 < 10ms(含 L1 + L2 + DB 回退)
DB 负载下降 DB 峰值 QPS 降低 70% 以上
数据一致性窗口 L1 与 L2 之间 TTL 偏差 <= 5s,L2 与 DB 之间 <= 60s
缓存击穿恢复 单 Key 失效后,L1 能在 2s 内从 L2 回填成功
架构方案型课程提示:两级缓存不是万能方案。在写密集型场景、数据强一致性要求极高的金融系统、或单机内存极小的边缘设备上,应避免使用。本章定义的“读多写少与热点场景”是后续所有章节的起点。