{"name":"缓存","id":"软件工程-架构-系统设计-缓存","content":"# 缓存体系\n\n## 缓存的本质\n\n### 核心定义\n\n缓存（Cache）是**显式管理状态（State）变更的工程机制**，通过在系统与其真实来源（数据库、服务、计算）之间建立一个**更低成本的读取层**，以**空间换时间**、以**一致性换吞吐**来达成系统性能与可用性的平衡。\n\n### 第一性原理：缓存为何有效\n\n**速度鸿沟**：计算单元与存储单元的速度存在量级差距。这一矛盾不可消除，只可缓解。缓存通过在快慢设备之间插入快速存储层，使热点数据驻留在距离计算更近的位置。\n\n**局部性原理**：程序访问数据时存在局部性——刚被访问的数据短期大概率再访问（时间局部性），被访问位置相邻的数据大概率会被访问（空间局部性）。局部性越强，缓存价值越大。\n\n**本质模型**：`缓存价值 = 局部性强度 × 速度差距`\n\n**贯穿各层**：局部性原理贯穿系统栈——CPU L1/L2/L3缓存、操作系统页缓存、应用进程内缓存、分布式缓存、CDN。不同层级的缓存，解决的是同一矛盾的不同尺度。\n\n### 核心矛盾\n\n缓存的本质围绕三大矛盾展开：\n\n| 核心矛盾            | 描述                           |\n| --------------- | ---------------------------- |\n| **一致性 vs 性能**   | 越一致越慢，越快越不一致。                |\n| **存储开销 vs 命中率** | 需控制缓存的价值密度，否则成本与收益失衡。        |\n| **复杂度 vs 可靠性**  | 引入缓存会引入副作用、过期、穿透、雪崩等大量工程复杂性。 |\n\n### 缓存的认知边界\n\n| 认知维度 | 边界要点 |\n|----------|----------|\n| **概念边界** | 缓存≠数据库≠存储，是加速层而非数据源 |\n| **性能边界** | 加速前提是访问热点存在，否则适得其反 |\n| **一致性边界** | 一致性不本质”慢”，慢的是协调机制 |\n| **工程边界** | 缓存是系统化能力，需设计先行 |\n\n## 缓存的全景架构\n\n### 三层缓存体系结构\n\n缓存体系通常呈现三层架构：\n\n```\n┌────────────────────┐\n│      L1 Cache      │  进程级（ConcurrentMap、Guava、Caffeine）\n│  极低延迟 / 小容量 │\n└─────────▲──────────┘\n          │ \n┌─────────┴──────────┐\n│      L2 Cache      │  分布式缓存（Redis、Memcached）\n│  远程访问 / 中容量 │\n└─────────▲──────────┘\n          │\n┌─────────┴──────────┐\n│   Persistent Store  │  数据库、搜索引擎、对象存储\n│ 高延迟 / 大容量 / 最终事实来源 │\n└────────────────────┘\n```\n\n### 缓存模型\n\n缓存体系可抽象为六种模型：\n\n| 模型 | 特征 | 使用场景 | 局限性 |\n| --- | --- | --- | --- |\n| **Read Through** | 业务从缓存读，缓存 miss 时由内部加载 | 透明加载 | 加载逻辑复杂；miss 时请求阻塞；可能预加载冷数据浪费内存；加载失败难排查 |\n| **Write Through** | 写入缓存同时写入 DB | 强一致写 | 写延迟 = 缓存写 + DB 写，耗时长；任一步骤失败需回滚；不适合高写吞吐 |\n| **Write Back** | 写入缓存，异步刷新 DB | 高写吞吐 | 缓存故障时数据丢失风险；需 WAL 持久化；故障恢复复杂；存在不一致窗口 |\n| **Cache Aside** | 应用显式管理缓存 | 最灵活，主流模式 | 应用代码复杂度高；显式处理 miss；缓存与 DB 竞态难避免；多次往返 |\n| **Streaming Cache** | 基于流式数据的事件驱动更新 | 高频变更 | 基础设施复杂（需 MQ、流处理）；事件乱序处理复杂；运维成本高 |\n| **Materialized View Cache** | 预计算、聚合缓存 | 分析查询或复杂计算 | 预计算成本高；刷新周期内数据陈旧；不适合频繁变更数据 |\n\n## 缓存关键策略\n\n缓存设计必须回答三个根本问题，三类策略分别对应这三个问题的解法：\n\n| 根本问题 | 策略 | 回答 |\n|----------|------|------|\n| **缓存数据怎么没的** | 生命周期策略 | 通过淘汰与过期机制管理缓存的时空边界 |\n| **缓存和数据源怎么同步** | 数据一致性策略 | 通过同步机制解决多数据源间的状态一致 |\n| **缓存坏了怎么办** | 故障防护策略 | 通过防护机制控制引入缓存带来的系统性风险 |\n\n> 缺少任一类，缓存体系都会在对应维度上失效——或空间失控、或数据陈旧、或引发系统性故障。\n\n### 生命周期策略\n\n| 策略                           | 描述                        | 场景         |\n| ---------------------------- | ------------------------- | ---------- |\n| **TTL（固定过期）**                | 设置固定过期时间                  | 高频写/低一致性要求 |\n| **LRU/LFU/FIFO**             | 基于淘汰策略管理空间                | 大规模数据映射    |\n| **随机过期（抖动）**                 | 随机化 TTL，避免集中过期            | 避免雪崩       |\n| **软/硬过期**                    | 后台刷新，新旧共存                 | 高 SLA 场景   |\n| **基于版本的过期（Versioned Cache）** | 数据含 version，version 变化即过期 | 精细化一致性     |\n\n### 数据一致性策略\n\n缓存与数据库的同步机制决定了数据一致性的强度，主要分为以下几类：\n\n| 同步机制 | 描述 | 触发时机 | 一致性强度 | 适用场景 |\n| ------- | ---- | ------- | --------- | ------- |\n| **删除失效** | 更新 DB 后删除缓存，下次访问时从 DB 回填 | 写操作时 | 最终一致 | 读多写少，主流模式 |\n| **TTL 过期** | 设置固定过期时间，到期后自动失效 | 时间到期 | 最终一致 | 允许短暂不一致 |\n| **主动失效（消息队列）** | 监听 DB 变更日志，通过消息队列主动删除缓存 | DB 变更时 | 较强一致 | 对一致性要求较高 |\n| **延迟双删** | 删缓存 → 更新 DB → 延迟 N ms → 再删缓存 | 写操作时增强 | 较强一致 | 高并发场景，防止回填 |\n| **订阅 binlog 变更** | 解析 DB binlog，实时同步变更到缓存 | DB 变更时 | 强一致 | 金融、交易类系统 |\n\n> **一致性强度说明**：越强的一致性通常以牺牲性能或增加复杂度为代价。\n\n### 故障防护策略\n\n缓存体系的防护策略是保障系统稳定性的关键：\n\n| 风险       | 现象                 | 防护                   |\n| -------- | ------------------ | -------------------- |\n| **缓存穿透** | 大量访问不存在的 key       | 布隆过滤器、空值缓存           |\n| **缓存击穿** | 热点 key 过期导致瞬时高并发回源 | 互斥锁/单飞（SingleFlight） |\n| **缓存雪崩** | 大量 key 同时过期        | TTL 抖动、逐步预热、分层缓存     |\n| **缓存抖动** | 数据频繁更新导致命中率不稳定     | 双写合并、批量更新            |\n\n## 缓存设计方法论\n\n### 设计的核心原则\n\n1. **数据价值优先级（Value Density）原则**\n\n   * 访问频率\n   * 获取成本\n   * 变化频率\n   * 可接受不一致性\n\n2. **一致性预算（Consistency Budget）**\n\n   * 明确一致性等级：可接受的“错多久”。\n\n3. **降级能力（Graceful Degradation）**\n\n   * 缓存不可用时业务不能死。\n\n4. **限制缓存滥用（Cache Abuse Control）**\n\n   * 禁止缓存全量数据、长生命周期大对象等反模式。\n\n### 原则 → 策略 映射矩阵\n\n四大原则是决策的**约束边界**，三类策略是**策略联动**的输出。在给定约束下，原则指导三类策略的选择：\n\n| 原则 | 生命周期策略 | 一致性策略 | 防护策略 |\n|------|:-----------:|:---------:|:--------:|\n| **数据价值优先级** | 高频访问→长TTL/LRU；低频→短TTL/FIFO | 高价值数据→强一致；低价值→最终一致 | 热点数据需防击穿；冷数据可简化防护 |\n| **一致性预算** | 允许较长不一致→长TTL；需实时一致→软硬过期 | 强一致→同步更新/延迟双删；最终一致→删除失效 | 强一致场景→缓存故障时需快速降级 |\n| **降级能力** | 需高可用→多层缓存+L1本地缓存 | 降级时缓存不可用→一致性策略需考虑回源路径 | 高可用→防穿透/击穿/雪崩全链路防护 |\n| **限制缓存滥用** | 大对象→不进缓存或拆分；频繁变更→评估收益 | 频繁写数据→不建议缓存 | 防护策略本身也是复杂度，需评估收益 |\n\n### 策略间联动关系\n\n#### TTL与一致性的联动\n\n```\nTTL越长 → 一致性越弱（数据变更传播越慢）\nTTL越短 → 一致性越强（但淘汰频繁，命中率下降）\n```\n\n**决策锚点**：根据一致性预算（可接受的\"错多久\"）确定TTL上限。\n\n#### 淘汰策略与容量的联动\n\n```\n容量充足 → 可用LRU/LFU，侧重时效性\n容量紧张 → 侧重LFU，保留高频数据，牺牲偶然热点\n```\n\n#### 生命周期与防护策略的联动\n\n```\nTTL集中 → 需防雪崩（加随机抖动）\nTTL分散 → 雪崩风险低，但击穿风险可能上升\n热点key → 需防击穿（SingleFlight/互斥锁）\n```\n\n### 缓存规划流程\n\n```\n选择存储对象 → 评估成本/命中率 → 选择缓存模型 → 设计一致性策略 → 设置TTL与淘汰策略 → 完成防护措施 → 运维治理\n```\n\n## 缓存的数据结构与模型级优化\n\n### 核心数据结构\n\n| 类型           | 使用场景       |\n| ------------ | ---------- |\n| key-value    | 标准缓存场景     |\n| hash         | 大对象拆分更新    |\n| sorted set   | 排序数据、高频榜单  |\n| bitmap       | 布尔状态/大规模计数 |\n| bloom filter | 穿透防御       |\n| hyperloglog  | 近似统计计数     |\n\n### 数据建模层的缓存策略\n\n**结构决定了访问成本的上限**，而不仅仅是实现细节的优化。如果数据模型设计不当（过度规范化、跨服务边界过细），再怎么优化缓存策略都事倍功半\n\n#### 聚合缓存\n\n将多个表/服务的数据聚合成一次命中的对象。\n\n#### 反范式化缓存\n\n在缓存中维持高度去规范化的数据以提升读效率。\n\n#### 预计算缓存\n\n复杂计算提前离线形成缓存。\n\n## 缓存运维与治理\n\n缓存不是部署就完事的技术组件，而是需要持续治理的系统。\n\n### 监控指标体系\n\n* 命中率（Hit Ratio）\n* 过期率（Expire Rate）\n* 回源量（Back-to-Origin QPS）\n* 队列堆积（异步更新）\n* 内存碎片率 / 扩容趋势\n\n### 常见运维动作\n\n* 热 key 分析与拆分\n* 大对象治理\n* 自动化预热\n* 分片规划与重均衡\n* 灾备与多集群切流\n\n## 缓存体系的演进路线图\n\n```\n1. 基础版：使用 L2 Redis → 设置 TTL → 手工管理 Key\n2. 稳定版：引入防护（穿透/雪崩/击穿）→ 热 Key 监控\n3. 体系版：多级缓存（L1+L2）→ 版本化保证一致性\n4. 企业级：全链路缓存治理 → 事件驱动的实时更新体系\n5. 云原生时代：Sidecar Cache / 全局缓存网格（Cache Mesh）\n```\n\n## 缓存的适用边界\n\n缓存不是架构设计的必选项，也不是业务开发的必要功能点。引入缓存意味着引入复杂性——需要处理一致性问题、防护策略、运维治理。\n\n**核心判断原则**：引入缓存的收益，必须大于其带来的额外复杂度。\n\n### 适合使用缓存的场景\n\n| 场景特征 | 说明 |\n|---------|------|\n| **读密集型** | 请求模式以读为主，写入频率低 |\n| **存在热点数据** | 访问呈现幂律分布，少量数据承载大量访问 |\n| **对响应时间敏感** | 需要毫秒级响应，纯数据库无法满足 |\n| **一致性要求可妥协** | 可接受最终一致性，允许短暂的数据不一致 |\n| **热数据量可预估** | 热点数据规模在缓存容量可承受范围内 |\n\n### 不适合使用缓存的场景\n\n| 场景特征 | 说明 | 原因 |\n|---------|------|------|\n| **写密集型** | 写入频率远高于读取 | 缓存收益低，维护成本高 |\n| **强一致性要求** | 如金融交易、库存扣减 | 缓存的最终一致性与业务需求冲突 |\n| **数据量极小** | 直接查询数据库代价可接受 | 引入缓存徒增复杂性 |\n| **访问完全随机** | 无热点、无局部性 | 缓存命中率低，收益有限 |\n| **数据变更频繁** | 需要实时同步 | 缓存更新代价高，一致性难以保证 |\n\n## 缓存的反模式\n\n### 架构层面的反模式\n\n**把缓存用作服务间数据通道**\n\n服务间约定key传递数据，违背\"让专业软件干专业事\"的原则。消息队列（MQ）更适合数据传递场景。\n\n**多服务共用同一缓存实例**\n\n不同服务共用缓存会导致：业务耦合；数据覆盖风险；相互影响。\n\n**调用方自行缓存**\n\n服务提供方缓存数据，调用方也缓存一份，先读自己的缓存再决定是否调用服务。服务修改DB后难以通知调用方淘汰缓存，导致数据不一致。\n\n**缓存作为数据主来源**\n\n缓存是加速层，数据库才是事实来源。任何时候都不应让缓存替代数据库承担数据持久化的职责。\n\n### 防护层面的反模式\n\n**未考虑雪崩**\n\n缓存挂掉后所有请求压到数据库，未提前做容量预估可能把数据库压垮，导致系统整体不可服务。解决：使用高可用缓存集群，或一致性哈希水平切分。\n\n### 实现层面的反模式\n\n**缓存大对象**\n\n缓存MB级图像等大对象，序列化和反序列化开销大，降低CPU效率。建议：单缓存项不超过8KB，大对象拆分独立缓存。\n\n**缓存活动对象**\n\n缓存持有打开的文件句柄、网络连接等，这些项从缓存移除时无法自动销毁，导致资源泄露。\n\n**嵌套集合存储**\n\n在单个缓存项存储完整集合，读取某项时需加载整个集合，网络开销大。建议：独立存储集合中的每一项。\n\n**父子对象存储不当**\n\n父对象和子对象分开存储但未同步更新，导致数据不一致。建议：实体在缓存中只存储一次，或存储ID而非完整对象。\n\n**假设缓存立即可用**\n\n存储后假设项立即可读，但内存压力时缓存项可能被清除。永远不要假设总能获得缓存中的某一项。\n\n**多键存储同一值**\n\n用Key和索引同时存储对象副本，修改对象后无法同步到所有缓存副本，导致数据不一致。\n\n**缓存配置项**\n\n用缓存存储配置数据，序列化开销使\"缓存\"不廉价，不如使用静态变量+配置监听机制。\n\n## 关联内容\n\n- [/软件工程/架构/系统设计/高并发.md](/软件工程/架构/系统设计/高并发.md) - 高并发场景下，缓存是应对高并发的重要策略，与分库分表、读写分离配合使用能有效提升系统并发能力\n- [/软件工程/架构/系统设计/分布式/分布式系统.md](/软件工程/架构/系统设计/分布式/分布式系统.md) - 分布式系统中的数据缓存与同步机制，以及缓存中间件在分布式架构中的应用\n- [/中间件/数据库/redis/Redis.md](/中间件/数据库/redis/Redis.md) - Redis作为主流分布式缓存的实现原理、数据结构、持久化、复制和集群等关键技术\n- [/操作系统/内存管理.md](/操作系统/内存管理.md) - 操作系统层面的缓存机制，包括TLB（转换检测缓冲区）、页缓存等与应用层缓存的类比\n- [/操作系统/多处理机系统.md](/操作系统/多处理机系统.md) - 多核处理器缓存一致性协议（如MESI）与分布式缓存一致性问题的类比\n- [/中间件/数据库/mysql/查询优化.md](/中间件/数据库/mysql/查询优化.md) - 数据库查询缓存机制及优化策略\n- [/计算机网络/应用层.md](/计算机网络/应用层.md) - DNS作为大型分布式缓存系统的设计思想\n- [/软件工程/架构/系统设计/可用性.md](/软件工程/架构/系统设计/可用性.md) - 多级缓存架构下的可用性保障策略\n- [/软件工程/架构/系统设计/伸缩性.md](/软件工程/架构/系统设计/伸缩性.md) - 本地缓存 + 分布式缓存 + 数据库的多层缓存伸缩性架构\n","metadata":"tags: ['计算机系统', '分布式系统', '性能']","hasMoreCommit":true,"totalCommits":25,"commitList":[{"date":"2026-04-01T16:16:20+08:00","author":"MY","message":"docs(cache): 重构缓存体系文档结构并完善技术内容","hash":"fe638fd9dc4209b7845a6391ed5ca8624e338dfa"},{"date":"2026-02-12T14:07:03+08:00","author":"MY","message":"doc: 整理标签","hash":"290b3e8ad18f48832ac282290238d020fc030a88"},{"date":"2025-11-16T21:30:56+08:00","author":"MY","message":"docs: 统一并精简文档标签","hash":"21362e9d7aeb62e05364cd5e7f3a3c24d7e293c7"},{"date":"2025-11-14T14:32:36+08:00","author":"MY","message":"docs(cache): 移除EhCache和Memcached相关文档","hash":"94ea969aa21dc7c128ae725f898ead8a5f4bc47e"},{"date":"2025-11-14T14:26:37+08:00","author":"MY","message":"docs(cache): 重构缓存设计文档，完善架构与策略细节","hash":"ffd3fe3b90c9c47ee944a24efb41d2f23f49dff4"},{"date":"2024-11-21T19:38:10+08:00","author":"MY","message":"📦流控 & 缓存","hash":"ec18717ffca6c3c8867ce0cf6bbbeff241c19ff8"},{"date":"2024-06-03T20:02:39+08:00","author":"MY","message":"✏缓存","hash":"3b9168ab8e255e7336587bbbcccb572147314bfb"},{"date":"2024-02-27T20:07:27+08:00","author":"MY","message":"✏算法","hash":"8a6529c0b37f98855cb1857f560564cc6401fd7b"},{"date":"2023-11-22T20:09:44+08:00","author":"MY","message":"✏缓存","hash":"b38350d2024c1b603465e19f3a27f46c57eefa3f"},{"date":"2023-07-04T20:17:01+08:00","author":"MY","message":"✏缓存","hash":"0f48db6ff9abf11cb30d7c12cf1ae1d67cd547a1"}],"createTime":"2020-03-17T15:36:37+08:00"}