內容鍵快取紀律(Cache Discipline)
什麼時候用
任何時候你想「這個算過了/驗過了,下次別重來」——建置產物快取、增量測試、資料頁攤平快取、
記憶化(memoization)、跨期產物庫。快取是效能的第一把刀,也是正確性最陰的敵人:
快取供錯值時,值本身看起來完全合理(它曾經是對的),只是來源是舊的——沒有任何當場的荒謬感
提醒你。這技能講怎麼讓「快」不用「對」來換。
核心法則
法則 1:捷徑=可證等值,不是跳驗
「命中快取所以不重算/不重驗」之所以合法,是因為一條可證的推理鏈:
同內容鍵 → 同 bytes → 同結果,且該 bytes 建造當下已完整驗過。三環缺一,捷徑就是在驗證上開洞。
- 鍵不合 → 落回完整路徑,或吠;絕不「不合但大概沒差」放行。靜默放行=洞。
- 推理鏈的最後一環(建造當下已驗)見法則 4。
法則 2:鍵必複合,裸雜湊=靜默錯值的入口
內容鍵至少三元複合:內容雜湊 + 大小 + 身分(路徑/名稱)。
- 短雜湊(如 32-bit CRC)單獨當鍵,理論上兩份不同內容可同鍵——碰撞的後果不是報錯,是拿舊內容
當新內容靜默供出(如拿上一期的資料頁當本期),下游全對、來源全錯。
- 加大小擋「內容變、雜湊碰巧不變」;加身分擋「不同位置的同雜湊互吃」。三者同時巧合才可能碰撞,
機率壓到工程上可忽略。
- 鍵選型也有經濟學:能從容器 metadata 直接取的雜湊(免解壓)優於要展開全文才能算的——快取的
存在理由就是省那次展開(成本考量見 engineering-economy)。
法則 3:快取項自帶 manifest,開檔即驗,絕不靜默供值
每個快取項完成寫入時同時寫 manifest:來源複合鍵 + 規模統計(筆數/格數)+ 內容摘要 +
(若適用)已通過的驗證層。每次取用前先驗 manifest:
- 不符 / 缺失 / 截斷(種到一半崩掉的半成品)→ 一律視同 miss 重種,並記錄事件;絕不把可疑項
當好的供出。
- 摘要要能抓「同筆數但內容被竄」(如 XOR/rolling digest),不只數筆數。
- 配破壞測試常備:截斷快取項→會吠並重種;竄改內容→摘要不合會吠;偽造 manifest→會吠。
守門的先驗會吠(呼應 verification-discipline「不信自報」——快取也是一種自報)。
法則 4:命中=證明傳遞(快取項承載驗證結論)
一般快取只省「算」;把 manifest 記上「此內容建造時已通過哪些驗證」,命中就同時合法傳遞
「已驗過」的結論——快取成為驗證結論的載體,增量驗證因此成立(沒變的部分,上次的「過」
繼續有效)。前提兩條,缺一即假:
- 建造時的驗證是完整的(該層該驗的全驗了,不是抽驗冒充全驗);
- 「沒變」是法則 1/2 等級的沒變(複合鍵一致),不是「看起來沒人動過」。
被快取省掉的檢查,必須能指出它在建造時點的等價完成處——省的是重複,不是覆蓋
(呼應 verification-discipline「該有而沒有」)。
法則 5:快取衛生——省的成本不得在別處長回來
快取是用磁碟換時間,這筆帳要持續是正的:
- 快取目錄有容量上限與汰換(如 LRU by mtime);沒有上限的快取=慢性磁碟洩漏。
- 孤兒鍵可清:來源已不存在/已不會再命中的項,能被識別、能被清。
- 每項回報自己的磁碟占用,總帳可見——「快了多少、佔了多少」都要量得出來,不是感覺。
法則 6:一次掃描餵多個消費者
種快取本來就要把來源完整掃一遍——這一遍是已付的成本,把之後每個消費者要的東西順路一起萃取
落進同一個快取項(值+統計+驗證要素+領域訊號),而不是各消費者各掃一遍。
- 反例:產出流程掃一遍取值、驗證流程再掃一遍取統計——同一份大來源被展開兩次,快取只救了一半。
- 順手萃取的東西「先記錄、不斷言」也划算:訊號躺在 manifest 裡,將來要接檢查時一行就接上,
不用回頭重掃(決策還沒定的守門,先把料備好)。
本專案案發現場(佐證,非通用必需)
- 法則 1/2 同場:某財務報表自動化專案的依賴頁快取,鍵定為(CRC32+未壓大小+part路徑)三元複合
——把關者連問三輪「鍵的完整組成」才放行,理由即「這快取直接餵當期正確性,碰撞=靜默錯期」。
CRC 從 ZIP 中央目錄直接取、免解壓 296MB,正是法則 2 的鍵選型經濟學。
- 法則 3:快取項(SQLite 值庫)開檔先驗 manifest(quick_check+格數),深驗走 XOR digest 抓
「同格數竄改」;兩條破壞測試(截斷→重種且值正確、竄值→digest 不合)都真吠過才收。
- 法則 4:靠「建造即驗證 + manifest 記已驗層」,驗證階段對依賴頁免重 parse(245K 公式的巨頁)
——某報表的驗證從全載 150 秒級降到點查,而七維度逐格驗在報表頁一格未省:省重複,不省覆蓋。
- 法則 5:LRU 汰換 + 磁碟占用回報,是把關者以「不浪費」為由押進首版的,不是事後補。
- 法則 6:值與頁級統計同一次串流落同一 SQLite;期別訊號順手進 manifest「先記錄、不斷言」
——對應的守門選項當時還在決策者手上,料先備好,裁定後一行接上。
- 姊妹技能:等值門開在內容層、巧合窗口是假綠 → verification-discipline 比對 5;快取的成本帳與
效能斷言 → engineering-economy 法則 12;大檔種快取的串流物理 → xlsx-surgery 法則 8。
1---2name: cache-discipline-23description: 內容鍵快取紀律——任何「為了快而略過重算/重驗」的機制(建置快取、增量回歸、依賴頁快取、記憶化、產物庫)怎麼做到快而不錯。用於任何加速工作:捷徑必須是可證等值而非跳驗、鍵必複合防碰撞、快取項自帶 manifest 開檔即驗、命中即證明傳遞、衛生上限防浪費轉移、一次掃描餵多個消費者。快取供錯值=最陰的錯:值看起來合理、來源卻是舊的。4---56# 內容鍵快取紀律(Cache Discipline)78## 什麼時候用910任何時候你想「這個算過了/驗過了,下次別重來」——建置產物快取、增量測試、資料頁攤平快取、11記憶化(memoization)、跨期產物庫。快取是效能的第一把刀,也是**正確性最陰的敵人**:12快取供錯值時,值本身看起來完全合理(它曾經是對的),只是**來源是舊的**——沒有任何當場的荒謬感13提醒你。這技能講怎麼讓「快」不用「對」來換。1415---1617## 核心法則1819### 法則 1:捷徑=可證等值,不是跳驗2021「命中快取所以不重算/不重驗」之所以合法,是因為一條可證的推理鏈:22**同內容鍵 → 同 bytes → 同結果,且該 bytes 建造當下已完整驗過**。三環缺一,捷徑就是在驗證上開洞。23- 鍵不合 → **落回完整路徑,或吠**;絕不「不合但大概沒差」放行。靜默放行=洞。24- 推理鏈的最後一環(建造當下已驗)見法則 4。2526### 法則 2:鍵必複合,裸雜湊=靜默錯值的入口2728內容鍵至少三元複合:**內容雜湊 + 大小 + 身分(路徑/名稱)**。29- 短雜湊(如 32-bit CRC)單獨當鍵,理論上兩份不同內容可同鍵——碰撞的後果不是報錯,是**拿舊內容30 當新內容靜默供出**(如拿上一期的資料頁當本期),下游全對、來源全錯。31- 加大小擋「內容變、雜湊碰巧不變」;加身分擋「不同位置的同雜湊互吃」。三者同時巧合才可能碰撞,32 機率壓到工程上可忽略。33- 鍵選型也有經濟學:能從容器 metadata 直接取的雜湊(免解壓)優於要展開全文才能算的——快取的34 存在理由就是省那次展開(成本考量見 engineering-economy)。3536### 法則 3:快取項自帶 manifest,開檔即驗,絕不靜默供值3738每個快取項**完成寫入時**同時寫 manifest:來源複合鍵 + 規模統計(筆數/格數)+ 內容摘要 +39(若適用)已通過的驗證層。**每次取用前先驗 manifest**:40- 不符 / 缺失 / 截斷(種到一半崩掉的半成品)→ 一律**視同 miss 重種**,並記錄事件;絕不把可疑項41 當好的供出。42- 摘要要能抓「同筆數但內容被竄」(如 XOR/rolling digest),不只數筆數。43- 配**破壞測試常備**:截斷快取項→會吠並重種;竄改內容→摘要不合會吠;偽造 manifest→會吠。44 守門的先驗會吠(呼應 verification-discipline「不信自報」——快取也是一種自報)。4546### 法則 4:命中=證明傳遞(快取項承載驗證結論)4748一般快取只省「算」;把 manifest 記上「此內容建造時已通過哪些驗證」,命中就同時合法傳遞49「已驗過」的結論——**快取成為驗證結論的載體**,增量驗證因此成立(沒變的部分,上次的「過」50繼續有效)。前提兩條,缺一即假:51- 建造時的驗證是**完整的**(該層該驗的全驗了,不是抽驗冒充全驗);52- 「沒變」是**法則 1/2 等級的沒變**(複合鍵一致),不是「看起來沒人動過」。53被快取省掉的檢查,必須能指出它在建造時點的等價完成處——省的是重複,不是覆蓋54(呼應 verification-discipline「該有而沒有」)。5556### 法則 5:快取衛生——省的成本不得在別處長回來5758快取是用磁碟換時間,這筆帳要持續是正的:59- 快取目錄有**容量上限與汰換**(如 LRU by mtime);沒有上限的快取=慢性磁碟洩漏。60- **孤兒鍵可清**:來源已不存在/已不會再命中的項,能被識別、能被清。61- 每項**回報自己的磁碟占用**,總帳可見——「快了多少、佔了多少」都要量得出來,不是感覺。6263### 法則 6:一次掃描餵多個消費者6465種快取本來就要把來源完整掃一遍——這一遍是**已付的成本**,把之後每個消費者要的東西順路一起萃取66落進同一個快取項(值+統計+驗證要素+領域訊號),而不是各消費者各掃一遍。67- 反例:產出流程掃一遍取值、驗證流程再掃一遍取統計——同一份大來源被展開兩次,快取只救了一半。68- 順手萃取的東西「先記錄、不斷言」也划算:訊號躺在 manifest 裡,將來要接檢查時一行就接上,69 不用回頭重掃(決策還沒定的守門,先把料備好)。7071---7273## 本專案案發現場(佐證,非通用必需)7475- **法則 1/2 同場**:某財務報表自動化專案的依賴頁快取,鍵定為(CRC32+未壓大小+part路徑)三元複合76 ——把關者連問三輪「鍵的完整組成」才放行,理由即「這快取直接餵當期正確性,碰撞=靜默錯期」。77 CRC 從 ZIP 中央目錄直接取、免解壓 296MB,正是法則 2 的鍵選型經濟學。78- **法則 3**:快取項(SQLite 值庫)開檔先驗 manifest(quick_check+格數),深驗走 XOR digest 抓79 「同格數竄改」;兩條破壞測試(截斷→重種且值正確、竄值→digest 不合)都真吠過才收。80- **法則 4**:靠「建造即驗證 + manifest 記已驗層」,驗證階段對依賴頁免重 parse(245K 公式的巨頁)81 ——某報表的驗證從全載 150 秒級降到點查,而七維度逐格驗在報表頁一格未省:省重複,不省覆蓋。82- **法則 5**:LRU 汰換 + 磁碟占用回報,是把關者以「不浪費」為由押進首版的,不是事後補。83- **法則 6**:值與頁級統計同一次串流落同一 SQLite;期別訊號順手進 manifest「先記錄、不斷言」84 ——對應的守門選項當時還在決策者手上,料先備好,裁定後一行接上。85- **姊妹技能**:等值門開在內容層、巧合窗口是假綠 → verification-discipline 比對 5;快取的成本帳與86 效能斷言 → engineering-economy 法則 12;大檔種快取的串流物理 → xlsx-surgery 法則 8。