题记与说明
- 日期:2026-11-01
- 唯一前缀:knowledge-4okgaw4b-3
- 类型:主题研究(跨层总结)
- 来源(本次精读的 5 个一手/权威来源,均为网络在线抓取全文):
- CPU 层:Cache hierarchy - Wikipedia(引 Hennessy & Patterson《Computer Architecture: A Quantitative Approach》等)
- 文件系统层:Page cache - Wikipedia(引 Robert Love《Linux Kernel Development》Ch.15)
- 数据库层:MySQL 8.0 Reference Manual :: 17.5.1 Buffer Pool
- HTTP 层:HTTP caching - MDN Web Docs(基于 RFC 9111)
- LLM 层:Prompt caching - Anthropic Docs
- 方法说明:主题式跨层精读——逐层抓取权威文档全文,对齐比较各层的缓存键、准入、写策略、失效机制与性能模型,归纳可迁移的共同规律。
一、核心问题
存储与计算之间、节点与节点之间的速度差是跨数量级的:CPU 快于内存约两个数量级,内存快于磁盘若干数量级,源站处理快于网络往返,LLM 重复 prefill 相同前缀是纯浪费。缓存要解决的问题是:如何用一层"小而快"的存储挡在"大而慢"的存储(或重复计算)前面,吸收大部分重复访问。 本笔记进一步追问:CPU 缓存、OS page cache、数据库 buffer pool、HTTP 缓存、LLM prompt cache 这五个看起来毫不相干的层,是否共享同一组设计变量与规律?
二、主要主张
五层缓存共享同一组设计变量——层级位置、缓存键、准入策略、写策略、失效机制、TTL——差异只在参数取值,不在原理。 具体展开为十条共同规律(见第四节),其中最核心的三条:
- 局部性是燃料:没有时间局部性(重复访问)与空间局部性(成块访问),缓存收益归零。
- 失效一致性没有免费午餐:五层全都放弃了强一致,改用"TTL + 验证 + 不可变化"的组合来逼近正确性。
- 应用越靠近缓存,越要求应用主动配合设计:从 CPU 的透明自动缓存,到 prompt cache 要求把静态内容前置——"让缓存命中"正在从硬件问题变成 prompt 工程问题。
三、方法
- 来源选择:每个抽象层选一个权威来源——CPU 层用 Wikipedia「Cache hierarchy」(底层数据引 Hennessy & Patterson 教材)、文件系统层用 Wikipedia「Page cache」(引 Linux 内核开发权威著作)、数据库层用 MySQL 官方手册、HTTP 层用 MDN(对应 RFC 9111)、LLM 层用 Anthropic 官方文档。
- 对齐维度:对每一层统一提取六个变量——缓存位于哪两层之间(层级)、如何判断"是同一条数据"(缓存键)、什么内容允许进入(准入/粒度)、写如何处理(写策略)、何时作废(失效机制)、收益如何度量(命中模型)。
- 跨层归纳:将五层的同名机制横向并置,提炼参数之外的共同规律;对无法从本次来源证实的内容明确标注"基于已有知识"。
四、数据与证据(逐层精读 + 原文引述)
4.1 CPU 缓存(L1/L2/L3)
- 动机原文(CPU 与内存速度差):
"In the history of computer and electronic chip development, there was a period when increases in CPU speed outpaced the improvements in memory access speed. … This issue motivated the creation of memory models with higher access rates in order to realize the potential of faster processors." —— Cache hierarchy - Wikipedia
- 性能模型:
AAT = hit time + (miss rate × miss penalty)。维基给出的算例:主存 50 ns,L1 = 1 ns(缺页率 10%),L2 = 5 ns(1%),L3 = 10 ns(0.2%):- 无缓存 AAT = 50 ns → 只有 L1 = 6 ns → L1+L2 = 1.55 ns → L1+L2+L3 = 1.5101 ns。
- 含义:每加一层缓存都把 miss penalty 换成"更贵但更准的下一级",平均访问时间被压低约 33 倍。
- 历史:缓存概念由 Maurice Wilkes 于 1965 年提出,初名 "slave memory"。
- 设计变量:
- 相联度权衡:"using a fully associative cache may result in more power consumption, as it has to search the whole cache every time."(全相联命中率最高但功耗最高)
- 写策略:write-through(层层直写)vs write-back("A 'dirty bit' is attached to each cache block and set whenever the cache block is modified.")——脏位 + 逐出时回写。
- 包含策略:inclusive / exclusive / NINE。
- 私有 vs 共享:L1 每核私有(低延迟),L3 全核共享(去重、高命中)。
- 真实容量级差(文中实测数据):Intel Xeon Emerald Rapids (2024):L1 80 KB/核、L2 2 MB/核、L3 5 MB/核(最高 320 MB 总量);Apple M1 Ultra:L1 320/192 KB、L2 52 MB、L3 96 MB。
- 边界条件原文:
"Benefits may be minimized or eliminated in the case of large programs with poor temporal locality, which frequently access the main memory."
4.2 文件系统缓存(OS page cache)
- 定义原文(透明性):
"a page cache, sometimes also called disk cache, is a transparent cache for the pages originating from a secondary storage device such as a hard disk drive (HDD) or a solid-state drive (SSD). The operating system keeps a page cache in otherwise unused portions of the main memory (RAM)… and is mostly transparent to applications." —— Page cache - Wikipedia
- 容量策略:空闲内存全部当缓存("all physical memory not directly allocated to applications is used by the operating system for the page cache"),且可随时回收——所以 Windows 把它记为 "available" 而非 "free",曾引发大量困惑。
- 写策略:脏页机制——"Pages in the page cache modified after being brought in are called dirty pages.";写命中时直接改内存页,按页边界整页写入时甚至无需先读盘。
- 失效 hazard:缓存中创建但未落盘的文件,后续读可能得到 0 字节文件(文档明确列出该风险)。
- 缓存作为攻击面:
"In 2019, security researchers demonstrated side-channel attacks against the page cache: it's possible to bypass privilege separation and exfiltrate data about other processes by systematically monitoring whether some file pages … are present in the cache or not."(Gruss et al., *Page Cache Attacks*, arXiv:1901.01161)
- 可执行文件共享:二进制经 page cache + mmap 在进程间共享,兼做内存节约手段。
4.3 数据库缓存(InnoDB Buffer Pool)
- 定位原文(缓存大小即"内存数据库化"程度):
"The buffer pool permits frequently used data to be accessed directly from memory, which speeds up processing. On dedicated servers, up to 80% of physical memory is often assigned to the buffer pool." / "The larger the buffer pool, the more InnoDB acts like an in-memory database." —— MySQL 8.0 手册 §17.5.1
- 替换算法:改良 LRU(中点插入),专门解决"扫描污染":
"A table scan, performed for a mysqldump operation or a SELECT statement with no WHERE clause, for example, can bring a large amount of data into the buffer pool and evict an equivalent amount of older data, even if the new data is never used again."
对策:新页默认插入链表中点(默认 3/8 给 old 子链表),只有被再次访问才"变年轻"升入 new 子链表——一次性扫描的数据没资格挤掉热点页。准入控制(admission control)是 LRU 的必要补丁,五层里 DB 层把它做成了默认行为。
- 可观测性:
SHOW ENGINE INNODB STATUS直接输出Buffer pool hit rate 1000 / 1000(千分命中率)、youngs/s、non-youngs/s、Modified db pages(脏页数)。缓存命中率被做成了一等监控指标。 - 空间局部性配套:read-ahead 预读 + 多 buffer pool instance 降低并发争用 + 重启后保温(saving and restoring buffer pool state,"avoid a lengthy warmup period"——缓存冷启动是通用问题)。
4.4 HTTP 缓存(浏览器/代理/CDN)
- 收益双通道原文:
"First, since there is no need to deliver the request to the origin server, then the closer the client and cache are, the faster the response will be. Also, when a response is reusable, the origin server does not need to process the request… That reduces the load on the server. Proper operation of the cache is critical to the health of the system." —— HTTP caching - MDN
- 私有/共享分级:private cache(浏览器,可存个性化响应)vs shared cache(proxy / managed 即 CDN、反向代理)——与 CPU 的 L1 私有 / L3 共享同构;个性化内容进共享缓存 = 信息泄露。
- 新鲜度模型:fresh/stale 由 age 决定(
max-age,等价于 TTL);无Cache-Control时走启发式缓存("HTTP is designed to cache as much as possible",Last-Modified 距今时长的 ~10%)——HTTP 的默认值是"能缓存就缓存"。 - 失效之难(原文):
"There is no way to delete responses on an intermediate server that have been stored with a long max-age." / "Caching reduces access to the server, which means that the server loses control of that URL."
对策不是"删除",而是三种替代:① 条件请求验证(If-None-Match/ETag、If-Modified-Since → 304 Not Modified,把失效从"推送失效"改成"拉取验证");② cache busting("changing the URL each time the content changes",用版本化文件名 bundle.v123.js 把可变资源变成不可变资源——改键不改值);③ managed cache 的主动 purge API(CDN 面板/接口删除,逃出协议限制)。
- 请求合并:多个相同请求同时到达时共享缓存只转发一次(request collapse),且"even if max-age=0 or no-cache is given in the response, it will be reused"——单飞(single-flight)防击穿在 HTTP 层是内建行为。
- 键的设计教训:
Vary: User-Agent会让键空间爆炸、"drastically reduces the chance that the cache will be reused"——缓存键每多一个高基数字段,命中率塌方。
4.5 LLM prompt cache(Anthropic Claude)
- 机制原文:
"The system checks if a prompt prefix, up to a specified cache breakpoint, is already cached from a recent query. If found, it uses the cached version, reducing processing time and costs." —— Prompt caching - Anthropic Docs
- 定价(Opus 4.1,$/MTok):基础输入 $15;5 分钟缓存写入 $18.75(+25% 写溢价);1 小时缓存写入 $30(+100%);缓存命中读 $1.50(= 基础价 10%,即命中部分省 90%)。Haiku 3.5:$0.80 / $1.00 / $1.60 / $0.08。
- TTL:默认 5 分钟,命中即免费续期("The cache is refreshed for no additional cost each time the cached content is used.");可付 2 倍写溢价买 1 小时 TTL——TTL 本身成了可购买的分层商品;"cache hits are not deducted against your rate limit"(命中不占速率配额)。
- 缓存键 = 逐字节相同前缀:
"Cache hits require 100% identical prompt segments, including all text and images up to and including the block marked with cache control." / "Caches are isolated between organizations."
- 失效是前缀级联的(层级结构 tools → system → messages):
"Changes at each level invalidate that level and all subsequent levels."
官方给出完整失效矩阵:改工具定义 → 全失效;开/关 web search、citations(动 system)→ system+messages 失效;改 tool_choice、插图片、改 thinking 参数 → 仅 messages 失效。这与文件路径前缀失效、HTTP 的 URL 键完全同构——失效沿前缀树向下传播。
- 粒度下限:最小可缓存长度 1024 tokens(Opus/Sonnet)、2048(Haiku),低于此直接不缓存——与 cache line / page 的最小粒度同构:太小的块不值得建立缓存元数据。
- 应用侧配合:静态内容(工具定义、系统提示、长文档)放前、动态内容放后;最多 4 个断点实现分层缓存;系统自动在断点前 ~20 个块边界回溯找最长命中前缀。并发场景下"cache entry only becomes available after the first response begins"——写入未完成时并发请求全是 miss,需要先等首响应(又是单飞问题的变体)。
- 正确性保证:"Prompt caching has no effect on output token generation. The response you receive will be identical…"——缓存必须对语义透明,与 CPU 缓存对程序透明同理。
五、结论:跨层共同规律(十条)
| # | 共同规律 | CPU | page cache | buffer pool | HTTP | prompt cache |
|---|---|---|---|---|---|---|
| 1 | 层级化:缓存永远夹在两个速度差数量级的存储/计算层之间 | L1-L2-L3-DRAM | RAM↔磁盘 | 内存↔磁盘页 | 浏览器-CDN-源站 | KV 前缀↔重复 prefill |
| 2 | 局部性是燃料:时间局部性决定 TTL/LRU 收益,空间局部性决定块粒度 | cache line | page | 16KB page | 整响应 | token 前缀 |
| 3 | 命中是指数杠杆:AAT = hit + miss×penalty,命中率小幅提升 → 平均延迟大幅下降 | 50ns→1.51ns | — | hit rate 1000/1000 可观测 | 304 只传头 | 读价 10% |
| 4 | 缓存键=内容身份:键必须精确判定"同一条数据";键里塞高基数变量会杀死命中率 | 地址 tag | (inode, offset) | (tablespace, page) | URL + Vary | 逐字节相同前缀 |
| 5 | 无强一致:五层都选"TTL + 验证 + 不可变化"而非推送失效 | 协议保证 | 脏页回写 | WAL/checkpoint | ETag 304 + cache busting | 前缀级联失效表 |
| 6 | 写比读贵:进缓存要付溢价,命中才打折 | write-back 脏位成本 | dirty page 刷盘 | flush 开销 | 源站写入后才能缓存 | 写 +25%~100%,读 −90% |
| 7 | 准入控制必要:一次性扫描不得冲刷热点页 | nontemporal hints(基于已有知识) | — | 中点插入 LRU(默认) | — | 多断点分层 TTL(1h+5m) |
| 8 | 透明性光谱:越靠上层,越要求应用主动配合缓存设计 | 硬件透明 | 对应用透明 | SQL 透明、需调参 | 需显式 header | 需重排 prompt 结构 |
| 9 | 不可变性是缓存之友:把可变的东西变成不可变的键,失效问题消失一半 | — | 只读页共享 | — | cache busting + immutable | 静态前缀前置 |
| 10 | 缓存是攻击面与竞争点:命中与否泄露信息、被争抢、被合并 | 侧信道/分区 | Page Cache Attacks | 多 instance 分片 | private 防泄露、request collapse 防击穿 | 组织隔离、并发首响应前全 miss |
一句话结论:缓存不是五种技术,而是同一个设计问题在五个速度尺度上的五次实例化;设计新系统的缓存时,答案几乎总能在另一层里找到——你缺的只是把 LRU 改成中点插入、把失效改成 cache busting、把静态内容前置这类"本层方言"。
六、局限
- Anthropic 延迟收益数字未在本次精读页面出现:官方营销页常引用"最高 85% 延迟降低",但本次精读的文档页只说 "reducing processing time and costs",未给出具体百分比,故笔记不引用该数字(成本 −90% 有定价表直接支撑)。
- 部分跨层对应关系标注为"基于已有知识":如 CPU 的 nontemporal/streaming 访问提示、Phil Karlton "computer science 两大难题"名言的归属、Linux multi-gen LRU 等新算法,本次 5 个来源未覆盖或 Wikipedia 条目较简略。
- 来源以文档与百科为主,缺少对账式实测(如 CDN 命中率统计、vLLM/SGLang 自动前缀缓存的 benchmark),LLM 层仅精读了 Anthropic 一家,OpenAI 的自动缓存(50% 折扣档)未核证。
- 缓存击穿/雪崩/穿透三件套在 HTTP 层只覆盖了 request collapse,DB 层未展开。
- Wikipedia 条目存在少量
[citation needed]标记(inclusive/exclusive 策略部分),引用时已避开依赖这些句子的结论。
七、对我的启发
- Prompt 排序即缓存优化:写 system prompt 时把工具定义、长文档、few-shot 例子全部前置并用
cache_control断点收口,动态内容放最后——这是 prompt 工程里的"局部性优化",命中部分直接打 1 折;长会话 agent 场景付 2 倍写溢价上 1 小时 TTL 是划算的(读价只有 10%)。 - 失效优先选"改键"而非"删值":HTTP 层 40 年的教训——中间缓存的值删不掉,所以发明了 cache busting。做应用缓存(如构建产物、API 响应)时优先用版本化键 + 长 TTL,而不是绞尽脑汁做主动失效。
- 给任何 LRU 配准入控制:一次性批量任务(全表导出、全库扫描)会把热点数据冲出缓存,InnoDB 中点插入是现成答案;自研缓存至少要有"新页先进 old 区"的意识。
- 把命中率做成一等监控指标:InnoDB 连
youngs/s、脏页数都直接输出;应用缓存如果连 hit rate 都看不到,等于没有缓存。 - 不可变内容无限缓存,可变内容永不进长 TTL:跨层通用的二分法——静态资源、append-only 会话前缀走长缓存;用户画像、实时状态走短 TTL + 验证(no-cache + ETag 模式)。
- 跨层阅读是设计捷径:以后设计任何"快慢层"结构(包括 agent 的记忆分层:工作记忆/情景记忆/长期知识库),先问一句"CPU/DB/CDN 是怎么解决键、准入、失效、冷启动的",大概率有现成答案。
*精读完成于 2026-11-01,全部 5 个来源为当日在线抓取全文;引述均为原文摘录,链接见文首来源列表。*