TouchAll技术博客

TouchAll技术博客

[系统设计 - 缓存设计专题] 1. 缓存分层架构

2026-07-12

缓存分层架构

标准分层链路:
L0 CDN 边缘缓存 → L1 网关 / 反向代理缓存 → L2 应用本地缓存(进程内) → L3 分布式共享缓存(Redis) → L4 数据库层缓存(Buffer Pool / 查询缓存)

每层统一按 4 个维度展开:

  1. 使用场景
  2. 本层能解决什么问题
  3. 本层固有、无法彻底根除的短板(解决不了的问题)
  4. 引入该层后的最终业务结果

L0. CDN 边缘缓存(最外层,用户侧)

1. 使用场景

静态资源:图片、视频、JS/CSS、静态页面、公共无敏感接口、首页骨架、静态配置文件;
全国 / 全球多地域访问、大流量公开静态内容;
不包含用户隐私、个性化数据。

2. 能解决的问题

  • 跨地域网络延迟,就近节点响应,大幅降低跨城 / 跨运营商耗时;
  • 削峰:海量静态请求不回源业务服务器,减轻源站带宽、CPU 压力;
  • 带宽成本降低,大文件下载分流;
  • 抵御 CC 攻击,边缘节点拦截无效请求。

3. 固有无法解决的问题

  1. 强一致性无法实现:CDN 多节点副本,统一刷新有延迟,无法做到实时同步脏数据;
  2. 不支持个性化、私有数据缓存:缓存基于 URL,无法按用户 ID 隔离,缓存用户隐私会泄露;
  3. 容量成本高、粒度粗:只适合大体积静态资源,不适合高频小粒度业务对象;
  4. 无法做复杂业务逻辑缓存:不支持 Hash、ZSet、计数器等数据结构;
  5. 节点故障、缓存穿透回源、热点 URL 打爆源站只能缓解不能根除。

4. 最终结果

静态流量 90%+ 在边缘拦截,源站 QPS 大幅下降,页面加载速度显著提升;但动态个性化接口完全无法依赖 CDN。

L1. 网关 / Nginx 反向代理缓存(机房入口层)

1. 使用场景

公共开放接口、无登录通用页面、高频只读短接口、活动页、商品列表公共数据;
统一入口拦截流量,在进入业务服务前拦截重复请求;
Lua 脚本缓存接口响应报文。

2. 能解决的问题

  • 屏蔽大量重复请求,减少下游应用服务并发压力;
  • 统一缓存 TTL、统一限流熔断、统一缓存失效规则;
  • 减轻应用服务网络、序列化开销;
  • 多实例服务共享同一层缓存,相比本地缓存集群一致性更好。

3. 固有无法解决的问题

  1. 无业务上下文隔离:很难精细按用户、租户、业务模块隔离缓存;
  2. 缓存粒度粗,只能缓存完整 HTTP 响应,无法缓存单个业务对象;
  3. 网关集群多节点,多副本存在短暂不一致;
  4. 不支持复杂数据结构,仅支持 KV 字符串缓存;
  5. 无法读取应用内存对象,必须序列化报文存储。

4. 最终结果

公共接口流量提前拦截,下游服务并发量下降 30%~60%;个性化、带用户身份的数据无法使用该层缓存。

L2. 应用本地缓存(进程内 LRU)

1. 使用场景

  1. 超高热点小数据:基础配置、字典、分类、热门商品基础信息、活动开关;
  2. 单实例高频重复访问、访问延迟敏感链路(P99 优化);
  3. 兜底防护:分布式缓存宕机降级使用;
  4. 低变更、读多写少、可容忍短暂不一致的数据;
  5. 热点 key 打散,防止 Redis 单节点热点。

2. 能解决的问题

  • 零网络 RTT,纳秒级访问,消除 Redis 网络往返、序列化 / 反序列化 CPU 消耗;
  • 打散热点流量:同一热点 key 分散到所有应用实例,不会集中压垮 Redis 单节点;
  • 分布式缓存故障降级兜底,避免全量穿透 DB;
  • 减轻 Redis 集群 QPS 压力,提升整体缓存命中率;
  • 轻量、无额外中间件运维成本。

3. 固有无法解决的问题(核心短板)

  1. 集群数据天然不一致(最致命):每个应用实例独立内存,更新后仅单实例失效,其他实例仍存旧数据;即便用 Pub/Sub 广播失效,仍存在消息延迟、丢消息导致脏读;无法做到集群实时强一致
  2. 容量受单实例内存限制:堆内存有限,只能存百 MB 级热点,无法承载全量业务数据;单服务扩容实例越多,总缓存副本越多,内存总占用线性上涨。
  3. 服务重启全量失效:发布、重启、扩缩容时本地缓存清空,瞬间大量请求穿透 Redis,引发缓存击穿风暴。
  4. 无法跨服务共享:A 服务缓存的数据,B 服务不能复用,重复缓存浪费内存。
  5. 无持久化,进程退出数据丢失;淘汰算法只能基于本实例访问统计,无法感知全局冷热。

4. 最终结果

最热流量直接内存命中,P99 延迟大幅优化,Redis 压力减半;但必须接受短时间数据不一致,需要分布式缓存做统一数据源兜底。

L3. 分布式共享缓存(Redis Cluster)

1. 使用场景

  1. 全服务集群共享业务数据:用户信息、购物车、库存、订单、商品详情;
  2. 需要跨实例、跨服务统一数据视图,对一致性有基础要求;
  3. 数据量较大,单实例内存无法承载;
  4. 需要分布式能力:分布式锁、计数器、排行榜、消息队列、过期淘汰;
  5. 本地缓存失效后统一回写的唯一可信缓存源。

2. 能解决的问题

  • 全集群统一数据副本,所有应用读取同一份缓存,天然解决本地缓存集群不一致问题;
  • 容量横向扩容,百 GB 级存储,可承载全量热点业务数据;
  • 丰富数据结构、原子操作,支撑各类业务计数、限流、锁场景;
  • 持久化 RDB/AOF,进程重启不丢失缓存数据;
  • 主从 / 集群高可用,单节点故障自动切换;
  • 统一缓存更新入口,所有业务写操作统一修改此处,作为缓存事实标准。

3. 固有无法解决的问题

  1. 存在网络开销:每次读写都有 RTT(0.5~2ms),并发极高时网络 IO、序列化成为瓶颈;
  2. 热点 key 问题无法根除:极端热点会集中打到单个分片主节点,造成 CPU 打满;
  3. 集群故障、主从切换、槽迁移会产生短暂不可用,仍有穿透 DB 风险;
  4. 无法消除序列化开销,对象进出 Redis 必须编解码;
  5. 多机房部署存在跨城同步延迟,异地多活天然不一致;
  6. 无法完全规避缓存穿透、击穿、雪崩三大经典问题,只能通过策略缓解。

4. 最终结果

全服务共享统一缓存数据源,解决集群数据同步问题,承载绝大多数业务读写;但延迟高于本地缓存,高并发下网络与序列化存在性能瓶颈,依赖本地缓存做前置加速。

L4:数据库层缓存(MySQL Buffer Pool / 索引缓存)

1. 使用场景

所有最终落库查询兜底;低频冷门数据、未缓存业务数据;复杂多表联查、聚合统计;无业务缓存兜底时的最后性能防线。

2. 能解决的问题

  • 磁盘 IO 拦截,热点索引、行数据加载到内存,避免每次查询读磁盘;
  • 无业务缓存时,兜底降低数据库磁盘压力;
  • 索引页、数据页自动冷热淘汰,无需业务手动维护 TTL;
  • 事务内数据一致性天然保障。

3. 固有无法解决的问题

  1. 延迟最高:即使命中 Buffer Pool,仍有 SQL 解析、锁、事务、内存拷贝开销,5~50ms;
  2. 数据库资源上限极低,大量并发查询会打满 CPU、连接池;
  3. 无法做复杂业务计算、分布式协同(锁、限流、计数);
  4. 容量有限,优先缓存索引,业务数据缓存容量不足;
  5. 无法拦截重复相同查询,每次都要执行 SQL 逻辑。

4. 最终结果

缓存全层全部失效后的最后兜底,大幅降低磁盘 IO;但性能最差,不能作为高并发流量的主力缓存层。