摘要: Cloudflare 工程實習生做出 Cache Transcoding 原型,在 Pingora 中把符合條件的快取資產先用 zstd 壓縮再落盤。初步測試顯示資產平均只剩原本磁碟大小的三分之一,代價是少量 CPU 用量增加。方案只處理至少 4 KiB 的可壓縮文字,不重複壓縮圖片、影片或字型。
記憶體的成本一路往上走,RAM 與硬碟的售價在過去一年明顯抬升。Cloudflare 經營的正是仰賴大量分散式儲存(CDN 便是其中之一)的生意,怎麼把手上既有的記憶體用得更省,直接關係到服務能不能撐得住。
一名參與 1.1.1.1 Intern Program 的 Cloudflare 工程實習生,在實習期間做出了名為 Cache Transcoding 的原型,成果也放上了官方部落格。它的做法是在 Pingora 架構裡,把符合條件的資產在寫入快取之前先用 Zstandard(zstd)壓縮,藉此換到相當可觀的儲存空間與跨資料中心頻寬節省。
取捨所在:少量 CPU 換來可觀儲存
Cache Transcoding 的構想並不複雜:符合條件的回應要進快取時,先經過 zstd 編碼再落盤;資產在整個快取生命週期裡都保持壓縮,連在 Tiered Cache 各層之間移動時也是壓縮形式;一直要到準備回應客戶端之前才解碼。
Cloudflare 的初步測試顯示,經過這道編碼,符合條件的資產平均只剩原本磁碟大小的三分之一。付出的代價是 CPU 使用率略為上升,但 Cloudflare 認為這筆交易划算——編碼只在資產進入快取時做一次,儲存與頻寬的好處卻會在資產每次被重複取用時持續累積。
原型選用 zstd level 3,理由是它能在壓縮率與速度之間取得平衡。Cloudflare 先前的測試指出,zstd 的壓縮速度比 Brotli 快 42%,而檔案大小幾乎一樣;與 gzip 相比,在速度相近的前提下,產出的檔案小了 11.3%。
不是每一種內容都值得壓縮
Cache Transcoding 並不是看到什麼都壓。圖片、影片與字型本來就已經壓縮過,再壓一次只是白白消耗 CPU。在 Cloudflare 取樣的流量裡,這類媒體占請求數的 21.4%,卻占了 63.3% 的位元組。
真正壓得動的是可壓縮的文字類內容,像是 HTML、JSON、CSS 與 JavaScript。它們占請求數 67.3%、位元組數 22.3%;其中大約 71% 送達時並未壓縮(Content-Encoding 未設定),而且壓縮效果很好。在受控的測試語料上,符合條件的資產壓縮率約 2.8 倍。
也因此,原型訂下了嚴格的資格檢查:只處理 200 OK 回應,且必須 Content-Encoding 未設定、Content-Type 屬於可壓縮文字、Content-Length 已知且至少 4 KiB。門檻以下的請求一概排除,原因是把門檻往下調,只會讓每個物件的開銷變多,儲存空間卻省不到更多。
設計細節:編碼一次,好處多次
Cache Transcoding 的運作分成以下幾種情況:
- 快取未命中:Pingora 代理先把 body 以 zstd 編碼再寫入磁碟,中繼資料會記下壓縮狀態,並保留原始內容長度。回應在離開代理之前會解碼回原本的表示。
- 快取命中:從磁碟讀出 zstd 物件後解碼。若使用 Tiered Cache,壓縮表示會由上層往下層傳送,只有在面向客戶端的那一跳才解碼。
- 完整未命中:上層向來源取得原始位元組,編碼一次後存成 zstd,再以壓縮形式傳給下層。下層同樣存下 zstd 表示,等請求路徑上再解碼。
- 下層未命中但上層已有物件:來源完全不參與,壓縮物件直接在快取層之間搬移,一路保持壓縮,直到下層解碼。
- 下層已有物件:既不需要網路傳輸也不必編碼,直接讀出 zstd 位元組、解碼後送出。
儲存編碼標記可以避免同一個物件被重複編碼。從其他層收到物件的快取層,看得出它已經以 zstd 儲存,就會讓它維持原樣。
測試結果與後續方向
Cloudflare 用受控的測試區來驗證原型,並把每一個請求與請求日誌、Prometheus 指標及 Jaeger 追蹤串起來。效能測試送出超過一百萬個請求,分布在 10 台快取伺服器上,其中一半停用 Tiered Cache、一半啟用,以便分別量測本機快取行為與跨層傳輸。
測試資產大約是 195 KiB 與 272 KiB,壓縮率約 2.8 倍。Cloudflare 特別說明,這是刻意挑選的可壓縮語料,用途在於驗證架構,不能代表網際網路上所有的文字物件。若要把這個壓縮率當成全網路的常數,得用更廣泛的語料再測一輪。
初步結果顯示,在測試條件下 CPU 成本只多了幾個百分點,儲存與頻寬的節省卻很明顯。團隊原本想過只壓熱門內容,後來發現這樣做儲存效益會下滑,CPU 開銷卻不會等比例變少,於是改採更單純的政策:所有符合條件的可壓縮文字(≥4 KiB)一律壓縮。
接下來要做的方向包括:評估更高的 zstd 等級、測試更多內容類型與物件大小、調整資格條件的參數,以及研究 range requests、預壓縮的來源回應,或是直接把壓縮物件交給支援的下游元件。
這個原型說明,即使不動現有基礎設施,Cloudflare 仍有辦法把效率再榨出來一些。對產品建構者來說,重點是要看懂取捨:壓縮本身有成本,但只要找到「編碼一次、多次受益」的情境,一點 CPU 投入就可能換回相當可觀的儲存與頻寬。
