vatt'ghern jaskier's ballads
本文 6 個互動圖表在手機上以重點摘要呈現,互動版請以桌面瀏覽器開啟。

Magic Pocket 是 Dropbox 的 immutable blob store,EB 級規模、用 erasure coding 取代複本。原本只有一條 compaction pipeline——對「快要滿但還沒滿」的 volume 做 top-off。然後某次事件讓一大批 volume 同時掉到不到 5% 使用率,原本的 pipeline 根本來不及把它們排空。新加的兩條 pipeline 不是優化原有的 L1,而是把 compaction 拆成三種完全不同的工作量。

Magic Pocket 的三層 compaction——L1 維穩、L2 動態規劃打包、L3 串流排空

Magic Pocket 把資料切成 fragment,加上少量 parity fragment 後散佈到不同的物理 volume。

Volume 是 append-only 的:刪資料只是標記、空間不會立刻釋放。

Compaction 的工作就是把多個半滿 volume 的有效資料搬到較少的滿 volume,然後回收空 volume。

三層 pipeline——L1、L2、L3——對應「volume 稀疏化速度不同」時的三種應對節奏:穩態維持、中度批次重組、極稀疏應急排空。

這個拆法的有趣之處不在演算法本身,而在於 Dropbox 工程師明確拒絕「一個更聰明的 unified compaction」這個方向。

三條 pipeline 共享 volume 視圖、共享 metadata service,但工作的單位、選擇候選的策略、對 metadata system 的壓力,都刻意不同。

理解三層為什麼非得分開,比理解任何一條 pipeline 內部都來得重要。

底層的物理事實是這樣:Magic Pocket 把資料用 erasure coding 切成 k 個 data fragment 加 m 個 parity fragment,散佈到不同 cell、不同機架的物理 volume 上。

任何一個 volume 都不會持有完整 blob——它持有的是 blob 的某個 fragment。

volume 是 append-only 寫入的物理單位,一旦封閉就不再接受新寫入。

刪 blob 只是在 metadata service 把它標成 garbage——對應的 fragment 仍然躺在 volume 裡,占著磁碟空間,等下次 compaction 真的把它們搬走、把整個 volume 回收。

當 Magic Pocket 規模還小、刪除壓力溫和的時候,這種 append-only + 異步回收的模型代價很低。

volume 平均使用率穩定在高位,compaction 只需要對「最近被刪了一點點」的 volume 做小幅整理——把幾個 80% 滿的 volume 合併成 95% 滿的 volume,回收掉幾顆磁碟。

但隨著 EB 規模成長,刪除模式變得不規律:某類客戶大規模 churn、某個內部 lifecycle policy 上線、某次資料遷移完成——這些事件都會讓 volume 稀疏化的速度遠遠超出穩態流程能處理的範圍。

原本的單一 pipeline——現在我們稱為 L1——面對突發稀疏化幾乎沒有反應能力:它的設計前提是「世界是穩態的」。

把所有 compaction 都當作穩態工作來做,會出現一種尷尬的失敗:當大批 volume 同時掉到 5% 以下時,L1 還在慢慢拉那些 80% → 95% 的 volume,極稀疏的那批根本排不上隊。

Dropbox 工程師選擇承認這個失配,把問題拆成三類獨立的工作量——而不是寫一個更複雜的 L1。

下面這張互動架構圖把三層放在同一個視圖。點選任一層 rect 會展開該層的責任邊界、它知道什麼、它不知道什麼——「不知道」是分層設計的關鍵,比「知道」更能告訴你為什麼這層的範圍只能到這裡。

三層 compaction:對齊 volume 稀疏化速度的三種節奏 L1:穩態維持 top-off 較滿 volume → 合併成更滿 節奏:分鐘級 · 低 metadata 開銷 候選:使用率 50–90% volume L2:動態規劃打包 中度稀疏 volume 群組 → DP 求近似最佳打包 節奏:小時級 · CPU + I/O 中重 候選:使用率 30–60% volume L3:稀疏 volume 排空 < 5% 使用率 volume → Live Coder 串流重編碼 節奏:天級 · metadata 壓力最高 候選:使用率 < 5% volume 三條 pipeline 共享 volume 視圖與 metadata service,但不共享 work queue 點選任一層查看細節 · click any tier to inspect

L1 · 穩態維持

L1 是原本就存在的 pipeline。它的工作節奏是「分鐘級 micro-batch」:每次跑一輪,挑一個 highly-filled 的 host volume 作為打包目標,從候選池中選幾個 live byte 加總剛好塞得進 host 剩餘空間的 donor volume,把 donor 的有效 fragment 搬過去、回收 donor。

L1 不做大範圍搜尋。它的選擇接近 first-fit decreasing:candidate pool 用使用率 bucket 化、host 從使用率最高的 bucket 取,donor 從中段 bucket 取。每一輪平均回收不到一整個 volume——這是穩態的合理輸出。

L1 不知道:volume 之間的「最佳組合」是什麼。它只看一個 host、幾個 donor。如果有一千個 30% 滿的 volume 同時等著被回收,L1 會一個一個慢慢處理,不會嘗試「最佳化全域配對」。

L2 · 動態規劃打包

L2 把問題建模成 bounded bin packing:給定一組 donor candidate 的 live byte 陣列、destination 容量上限、單次選擇 volume 數量上限,求「能塞進 destination 的最大 live byte 總和」。

實作是經典 0/1 knapsack 的 DP,狀態 (volume_index, count, capacity)。原始 live byte 數會被 granularity factor 縮放——例如以 1 MiB 為一格——讓 DP 表的容量維度從 TB 縮成幾千格。回溯解出最佳組合,把選中的 donor volume 搬過去。

L2 對 donor pool 設了硬上限(單次取最多 N 個 volume),所以 DP 表的大小可控、單次 compaction 的 CPU 與 I/O 開銷都在預算之內。

L2 不知道:哪些 volume 應該被優先回收。L2 只負責「給我這批 candidate,我找到最佳組合」——caller 才決定送什麼進來。極稀疏 volume 不適合送進 L2,因為 DP 在「絕大多數 volume 都半空」的 candidate pool 上會找到「把它們塞進 destination」的解,但這個解需要重寫整個 destination,metadata churn 過高。

L3 · 稀疏 volume 排空

L3 對「使用率不到 5%」的 volume 採取完全不同的策略:放棄全域最佳化,採用 Live Coder service 作為 streaming pipeline,連續吃進稀疏 volume 的 live blob、用 on-the-fly erasure coding 重新編碼後寫入新 volume。

L3 不在乎「打包效率」——它在乎「立刻把空間歸還給 cluster」。L3 優先處理「最稀疏」的 volume:99% 是垃圾的 volume,搬走那 1% live blob 後整個 volume 立刻回收,回收率超過任何 L1/L2 組合。

代價是 metadata system 的壓力:L3 每搬一個 blob 就要更新它的 fragment 位置、可能還要分配新的 blob identifier。Dropbox 工程師在文章中明確指出「metadata capacity turned out to be one of our biggest constraints」——這也是 L3 不能無限制跑滿的原因。

L3 不知道:什麼時候該停。L3 是 demand-driven 的:cell 偵測到極稀疏 volume 的批次達到某個門檻時觸發,跑完那一批就收手,把節奏交回給 L1/L2。

三條 pipeline 同時跑,但各自處理不同的 volume 區段:L1 守住 50–90% 中段、L2 攻 30–60% 中度稀疏批次、L3 應對 5% 以下的極稀疏尾部。點選任一層查看其責任邊界與「它不知道的事」。

三條 pipeline 同時跑,但各自處理不同的 volume 區段:L1 守住 50–90% 中段、L2 攻 30–…

L1 守住穩態 50–90%、L2 用 DP 打包中度稀疏 30–60%、L3 以 streaming 應急排空 5% 以下——三層各自對齊不同稀疏化速度。

L1 穩態維持

L1 是原本就存在的單一 pipeline,現在還在跑——只是不再獨自承擔所有 compaction 工作。對應的場景:每天有少量 volume 因為日常刪除而從接近 100% 降到 70–80%,L1 把它們重新打回接近滿。

L1 的選擇邏輯近似 first-fit decreasing 的近親:選一個 highly-filled 但還有 free capacity 的 host;從候選池挑「live byte 加總剛好塞得進 host 剩餘空間」的幾個 donor;把 donor 的 live fragment 搬到 host、回收 donor。每輪平均回收不到一整個 volume,在穩態時剛好夠抵消當天的稀疏化速度。

兩個設計約束讓 L1「只能做這件事」。一是只看 highly-filled 的 host 候選池、不做全域最佳化——分鐘級就能跑完,metadata 壓力極低。二是策略保守:donor 的 live byte 必須遠小於 host 的 free byte,否則搬完 host 也才升到 85%,沒比 70% 好多少。

這兩個約束讓 L1 對突發稀疏化幾乎沒有反應能力。一千個 volume 一夜從 60% 降到 10%,L1 根本不會去看它們——它們不在 highly-filled host 的候選池裡。等 L1 透過補貨機制接觸到時,新的稀疏化已經堆積成山。

L1 還有一個沒明說但關鍵的好處:metadata 壓力最低。Dropbox 工程師在文章裡點名「metadata capacity turned out to be one of our biggest constraints」——每次 fragment 移動都帶來 metadata 更新成本,L1 的低開銷讓它能在穩態長期跑、不會吃光 metadata budget。

有了 L2 與 L3 之後,L1 從「唯一的 compaction」變成「最後一道日常修整」。L1 在 Magic Pocket 早期就刻意寫得簡單、保守、可預測——這個保守性給了後來 L2/L3 演化空間:candidate filter 從一開始就嚴格限制在「中高使用率」這個區段,加新 pipeline 時不需要重寫 L1 的調度邏輯。

L2 動態規劃打包

L2 處理的是「volume 中度稀疏化」的場景:使用率 30–60% 的 volume 大量出現,L1 不會去碰它們(不在 L1 的 candidate pool 裡),但這些 volume 也還沒稀疏到值得用 L3 強力排空。

L2 把這個區段建模成有界 bin packing——目標是「以最少的新 volume 容納多個半滿 donor volume 的全部有效資料」。

實作上 L2 是經典 0/1 knapsack 的動態規劃。

狀態維度是 (volume_index, count, capacity):第 i 個 volume、目前已選的 volume 數、destination volume 已用掉的容量。

DP 值是「在這個狀態下能塞進 destination 的最大 live byte」。

原始 live byte 數會被一個 granularity factor 縮放——例如以 1 MiB 為一格——把容量維度從 TB 級的格子數壓到幾千格,DP 表的記憶體與計算量都在合理範圍。

L2 的關鍵設計參數有三個:donor pool 大小 N、destination 容量上限 C、granularity factor G。DP 的時間複雜度是 O(N · count · C/G),N 不能太大——donor pool 加上 granularity 縮放是讓 DP 表落在分鐘級可跑範圍的關鍵。L2 從「中度稀疏」bucket 取,不取極稀疏的 volume——那些是 L3 的範疇。

下面把 N 與 G 兩個旋鈕同時打開:左軸是 DP 表格子數(log),右軸是近似回收量。N 拉大、G 拉小,表大小很快超預算。

20
1
DP table cells
est. CPU
reclaim / round
L2 knapsack cost vs N · granularity G fixed by slider N (donor pool size) DP cells (log) reclaim / round 分鐘級 CPU 預算 DP cells (log) reclaim / round
DP cells = N · count_max · (C / G),count_max 固定為 8、C 固定為 2 TiB。橘色實線(左軸 log)是 DP 表大小、橄欖色虛線(右軸線性)是該 N 下單次 compaction 的近似回收量。N 拉到 80、G 拉到 1 MiB 時 DP 表破億格——超出分鐘級預算(虛線)。G 拉到 1 GiB 時即使 N=80 仍在預算內,但 reclaim 也跟著粒度損失下降。

DP cells = N · count_max · (C / G),count_max 固定為 8、C 固定為 2 …

L2 的 DP 表格子數 = N × count × (C/G);N 拉到 80、G 縮到 1 MiB 時破億格、超出分鐘級 CPU 預算。

DP 在中度稀疏 pool 上的解品質很高:candidate volume 的 live byte 加總多半比 destination 容量大,DP 能找到「6 個 50% 滿 volume 剛好打包成 1 個 95% 滿的 destination」這種解。每一輪 L2 平均回收 5–6 個 volume——相比 L1 的「不到一個」是接近一個數量級的吞吐提升。

Dropbox 在 production 部署 L2 後測到的數字:在啟用 L2 的 test cell,一週內整體 compaction overhead 比純 L1 低了 30–50%;overhead 收斂到 sustainable level 的速度比純 L1 快 2–3 倍。在 EB 規模上,這意味著不需要為了稀疏化容忍多預留 10–20% 的磁碟。

「overhead 收斂」的具體形狀是下面這條曲線:橫軸是稀疏事件後的天數、縱軸是 cell 過剩容量百分比。

compaction overhead 收斂:純 L1 vs L1+L2(test cell)
每條曲線都是事件 t=0(一批 volume 同時稀疏化)後的 overhead 衰減。純 L1(橘色)需要 ~14 天收斂回 sustainable 水位 7%;L1+L2(橄欖色)約 5 天就收斂——對應 Dropbox 報告的「2–3× faster convergence」。終態差距(橘 7% vs 橄欖 4%)反映「30–50% lower overhead」。資料形狀依照文章描述合成;引用 Dropbox 報告的數字邊界。

每條曲線都是事件 t=0(一批 volume 同時稀疏化)後的 overhead 衰減

加入 L2 後稀疏事件的 overhead 收斂從 14 天壓縮到 5 天、終態從 7% 降到 4%——對應 2–3× faster convergence。

關鍵不只是終態差距,更是初期斜率——L2 d3 已逼近終值,L1 同時刻仍超過 15%。

L2 不是萬能的。當 candidate pool 全是極稀疏 volume 時,DP 仍會找到解,但解的代價是用一個 destination 容納 20 個 donor 的 live byte——20 份 metadata 更新、每個 blob 都要重新分配 location,Live Coder 還沒派上用場就被 metadata service 卡住。極稀疏 candidate 的 live blob 雖少但分布散亂,metadata 開銷反而最重——這就是為什麼它們需要 L3 的「streaming pipeline + 攤銷 metadata 開銷」設計。

L3 稀疏 volume 排空

L3 是事件驅動的應急機制——某種客戶活動或內部 lifecycle policy 變動,讓一大批 volume 同時掉到 5% 以下使用率。對這類群體,DP 仍然太慢、即使算出解也需要重寫 20–30 個 destination volume,metadata churn 不划算。

L3 改用 Live Coder service 作為 streaming pipeline:稀疏 volume 的 live fragment 解碼後餵進 Live Coder 的 buffer,等於重做一次「新寫入」流程,erasure coding 在 streaming 過程中即時計算。Live Coder 本來就是背景寫入路徑的元件,L3 直接重用——沒寫新的 streaming compaction code,Live Coder 的任何優化(batching、pipelining)都自動被 L3 享受到。

L3 的優先級是「最稀疏優先」:99% 是垃圾的 volume 排在 95% 是垃圾的前面。原因直接——搬動的 blob 數量越少,這個 volume 越快被完全清空。

L3 的 metadata 壓力是三層裡最高的——每搬一個 blob 都要更新 fragment 位置。Dropbox 工程師明確指出 metadata capacity 是「最大的限制之一」,L3 的 throughput 不是被磁碟 I/O 限制,而是被 metadata service 的處理速率限制。這也決定了它的部署方式:以 cell 為單位開啟、依當前 metadata 負載動態調整 throttle、跑完批次就收手。大部分時間 L3 是休眠的——cell 的 metadata budget 留給 L1 與 L2。

三層的協同與「為什麼不是 unified 演算法」

三條 pipeline 表面上各自獨立——不共享 work queue、有各自的調度器與資源預算——但它們對 volume 視圖(哪些 volume 使用率多少、哪些可以動、哪些正在被搬)是同步的。

同一個 volume 不會同時被 L2 與 L3 挑中,因為它們的 candidate filter 不重疊:L2 要求使用率 30–60%,L3 要求 < 5%,L1 要求 50–90%。

三層的候選區段有少量重疊(L1 跟 L2 都看得到 50–60% 的 volume),這部分由更高層的 priority logic 處理——通常是「regime 偵測」:cell 偵測到自己處於穩態還是異常批次,不同 regime 下三層的權重不同。

更有趣的觀察是「為什麼不是一個更複雜的 unified compaction 演算法」。

Dropbox 工程師在文章中明確指出:unified 設計會被「最稀疏的情境」拖累——若要同時最佳化穩態與應急,演算法的搜尋空間爆炸、收斂變慢,反而比三條獨立 pipeline 慢。

把問題拆成三層的本質是承認「不同稀疏化速度需要不同的搜尋策略」,而不是強迫一個演算法處理所有情境。

這個觀察的可推廣性在於:很多 distributed system 的設計都有「regime 切換」的本質。

consensus 演算法在「節點都活著、網路通暢」的 regime 跟「節點失聯、需要選舉新 leader」的 regime 行為完全不同。

memory allocator 的 fast path 跟 slow path 是兩套機制。

compaction 也一樣——「日常維持」跟「應急排空」是兩種 regime。

承認這點、設計兩到三套機制分別處理、用簡單的 dispatch logic 在它們之間切換,比設計一個自適應的單一演算法更穩、也更容易推理。

Dropbox 在 production 部署三層 compaction 後,overhead 數字穩定收斂。

前面提到的「30–50% 降低」是 L2 vs 純 L1 的數字;加入 L3 之後對極稀疏事件的應對能力從「天級慢慢追」變成「天級就能清空」。

對於 EB 規模的 immutable blob store 來說,這意味著不需要為了應對突發稀疏化長期預留 10–20% 的硬碟容量——這部分容量可以拿來服務新資料,等於免費獲得了一定比例的儲存。

把三層放在同一張表裡比較,每一層的「擅長 / 不擅長」很清楚地對應到不同維度:搜尋空間、metadata 壓力、單次回收量、適用 regime。

下表整理了 Dropbox 工程師描述中可量化或可推論的數字——按任一欄排序可以看出三層在那個維度上的相對位置。

tier 適用 regime 候選使用率 回收速率(相對) metadata 壓力 節奏
L1穩態維持50–90%1.01分鐘級 micro-batch
L2中度稀疏批次30–60%2.53小時級 DP 打包
L3大規模極稀疏事件< 5%8.06天級 streaming drain
回收速率與 metadata 壓力都是相對於 L1 的倍數——L3 的回收吞吐約為 L1 的 8 倍,但每單位回收消耗的 metadata 操作也是 6 倍。三層各自最佳的 regime 與候選使用率邊界對應 Dropbox 工程師描述的部署參數。

回收速率與 metadata 壓力都是相對於 L1 的倍數——L3 的回收吞吐約為 L1 的 8 倍,但每單位回收消耗…

L3 的回收速率是 L1 的 8 倍但 metadata 壓力也是 6 倍;三層沒有任何一層在所有維度都贏——各自對應最佳 regime。

關鍵不是任一欄的絕對值,而是「沒有單一 tier 在所有維度都贏」——每一層在自己 regime 下都是最佳,跨 regime 比較沒有意義。

unified 演算法有三個固有問題。第一是搜尋空間:要同時最佳化「穩態 top-off」與「應急排空」,得涵蓋兩個 regime 的所有可能解;L1 的「幾個 host 配幾個 donor」與 L3 的「幾百個 volume 排序+分批」合併後不是更聰明,而是更慢,違反 distributed system 的 decision latency 約束。

第二是 regime 偵測本身比 regime 內最佳化更簡單。掃一次使用率分布直方圖就能毫秒級決定該啟動哪些 tier;把這件事抽出來變成 dispatcher 的工作,三條 pipeline 各自設計都簡化——L1 不需要知道現在是不是 burst,L3 不需要知道現在是不是穩態。

第三是 metadata 預算。L1 的 metadata 消耗是已知常數、L2 受 N 控制、L3 透過 throttle 控制;metadata service 接近飽和時可以單獨壓 L3、保留 L1 與 L2 容量。unified 演算法很難對「每一輪消耗多少 metadata operation」做硬上限。

這三個問題的共同主題是「工程系統的設計優先順序通常不是『最佳解』而是『可控、可推理、可調整』」。

可推理性帶來的營運價值——能在事件中診斷、能在 dashboard 上看到哪一層在工作、能單獨調整任一層——遠超過理論上「最佳解」的 1–2% 改善。

Dropbox 工程師描述的另一個細節印證這點:L1 仍然每天在跑、L2 不會去碰 L1 已經處理好的 volume、L3 只在偵測到批次條件時啟動。

如果是 unified 演算法,這些「不做某件事」的條件會散落在演算法各處變成 corner case;分成三層之後,「不做」的邏輯就是 candidate filter 的補集——L1 不看 30% 以下的 volume,因為 L2 會看;L2 不看 5% 以下的 volume,因為 L3 會看。

每層的職責邊界是 candidate filter,這比「演算法內部的 if-else」清楚得多。

把 candidate filter 翻過來看,就是「volume 在不同生命階段被哪一層接手」。拖下方游標可以看到對應年齡由哪一層處理。

一個 volume 的典型生命週期 · 拖動游標查看當下由哪一層處理 L1 守備區(50–90%) L2 守備區(30–60%) L3 守備區(< 5%) d0 d0 ~3mo ~9mo ~18mo retention exit 退役
剛寫入 · 使用率 ~95%
volume 剛剛封閉,幾乎沒有 deletion。任何 compaction tier 都不會看它。
dispatcher:跳過——沒有候選資格
橫軸是 volume 的年齡(不是嚴格時間,而是「累積經歷的刪除壓力」)。三個守備區的寬度反映 production 觀察:volume 大部分生命都在 L1 區(高使用率穩態),中段被 L2 攻打、末段才落入 L3。retention exit 是 lifecycle policy 觸發大規模刪除的位置——這正是 burst event 的來源,也是 L3 存在的理由。

橫軸是 volume 的年齡(不是嚴格時間,而是「累積經歷的刪除壓力」)

lifecycle policy 大規模觸發時直接把一批 volume 推進 L3 極稀疏區——這是 burst compaction 的來源。

從更大的角度看,三層 compaction 是「組合性勝過單體性」這個原則的具體案例。

當系統面對多種輸入分布時,把 input space 切分、為每個切片設計專門的處理路徑,往往比設計一個自適應的單體更穩。

這個原則在 compiler、database query planner、network scheduler 都看得到——不同的 input 走不同的快速路徑(fast path),共用同一份 metadata,但 algorithm 完全分開。

Magic Pocket 的三層 compaction 是這個 pattern 在 EB 規模 immutable blob store 上的一個樣本。

動態觀察:三層在不同 regime 下的回收節奏

下面的 canvas widget 把這個 cell 抽象成 80 個 volume 的 fleet 視圖,每一格代表一個 volume,高度代表 live byte。

churn rate 控制日常刪除的速率——拉高會讓更多 volume 稀疏化、推動 sparse backlog 累積。

「inject sparse-burst」按鈕一次注入 60 個 < 5% 的 volume,模擬大規模 lifecycle policy 變動或客戶 churn 事件。

觀察點:L1、L2、L3 各自的計數器在不同 regime 下會以不同速率成長。穩態時 L1 主導;持續中度 churn 時 L2 開始追上;burst 注入後 L3 立刻拉起、清空極稀疏 backlog,然後回到 L1/L2 的常態流程。

20
t = 0.0s
volumes reclaimed by L10
by L20
by L30
sparse backlog0
每一格是一個 volume;高度代表 live byte。churn rate 拉高會讓更多 volume 稀疏化、推動 backlog 累積。「inject sparse-burst」一次注入 60 個 < 5% volume 模擬大規模事件;觀察 L2 vs L3 在不同 regime 下的回收速率。

每一格是一個 volume;高度代表 live byte

注入 burst 時 L3 計數器急升後回穩;高持續 churn 下 L2 成為主力回收者、sparse backlog 仍會緩慢累積。

這個模擬不是 Dropbox 系統的精確重現——它的常數是為了讓在瀏覽器內幾秒內看到三層分工而調整過的。

但它捕捉到了三層 compaction 的核心動態:每一層的觸發條件是 candidate volume 的使用率分布、每一層的回收速率對應它擅長的 regime、burst 事件會讓 L3 計數器突然拉高然後回到平穩。

把 churn rate 拉到最大可以看到另一個現象:在持續高 churn 下,L1 完全跟不上、L2 變成主力,但 sparse backlog 仍然會緩慢累積——這是穩態 + 中度稀疏 regime 之外的另一種失配,現實中 Dropbox 會用 L3 的低 throttle 慢慢消化這個 backlog,避免讓它累積到觸發 burst 偵測。

互動 widget 的價值在於:靜態圖表能說明「三層各自擅長的 regime」,但只有動態觀察能讓讀者體會「regime 切換時三層的權重變化」這個概念。

從三層看出去:可推廣的設計直覺

把 Magic Pocket 的三層抽象成可推廣的設計直覺,有兩條最值得記住。

第一條:metadata 是 distributed system 的隱形瓶頸。L1 之所以省、L2 之所以受 N 限制、L3 之所以需要 throttle,都是因為 metadata service 的處理速率有上限。許多設計者把注意力放在 datapath,但 production 規模下 metadata path 往往才是瓶頸——先估算 metadata operation 預算、再回頭看 datapath 設計,比反過來做更省彎路。

第二條:把 regime 偵測放在 dispatcher 層,把 regime 內最佳化放在 worker 層。dispatcher 看 cell 的使用率分布、決定該啟動哪些 worker;三條 pipeline 各自處理 candidate filter 內的工作,互相無知。加一條新 pipeline 只需要改 dispatcher,不影響其他 worker。

Magic Pocket 的三層是這個 pattern 在 EB 規模 immutable blob store 上的一個格外清晰的樣本——問題明確、解法明確、量化效果明確(30–50% overhead reduction、2–3× faster convergence)。當下次面對「寫一個聰明的單體還是三個簡單的專用模組」這個問題時,答案常常是後者——可推理性、metadata 預算、regime 偵測的成本都站在「拆」這一邊。

What this enables:三層 compaction 把 Magic Pocket 對「volume 稀疏化速度」的應對能力從「分鐘級的慢慢追」擴展到「天級的批次排空」,整體 compaction overhead 在 EB 規模上降低 30–50%、收斂速度提升 2–3 倍——這個能力讓 immutable blob store 可以承受不規律的刪除模式而不需要超量預留容量,等於把原本被「為突發事件留 buffer」綁住的硬碟容量釋放出來服務新資料。