題目與背景
假設每個工作約執行 25 個 action,平均新增輸出為 300 MB。重複建置經常共享輸入,但錯誤命中可能讓錯誤工具鏈或秘密參與編譯的產物進入發布流程。快取是最佳化項目:未命中或快取故障應回退到執行,錯誤命中則屬於正確性事故。回答要把 action 結果查詢與不可變產物儲存分開,並說明遠端執行如何改變信任和容量模型。
面試官考察什麼
- 能否把影響確定性結果的輸入完整納入 action key。
- 能否分離可變的 action 元資料與不可變的內容尋址儲存(CAS)。
- 能否做到原子寫入、摘要校驗,並阻止跨租戶快取投毒。
- 能否明確容量、垃圾回收、可觀測性、故障降級和遷移。
- 能否區分建置快取與通用鍵值快取:正確性優先於接受舊讀。
建議先問的澄清問題
先問建置是否 hermetic、支援哪些作業系統和架構,以及是否必須遠端執行。確認保留時長、租戶與儲存庫邊界、最大產物大小、命中率目標、資料駐留要求,以及秘密或私有原始碼是否可能進入輸出。確認結果能否跨分支、工具鏈版本共享,還是只能在 commit 與平台組合內共享;也要確認 CI 是否寫入而開發機只讀。
30 秒回答框架
我會把規範化後的 action 描述納入雜湊,包括命令、工具鏈和平台身分、宣告輸入的 Merkle 根、相關環境和建置設定。action cache 將 key 映射到輸出摘要和結果元資料,CAS 按摘要保存不可變 blob。讀取時校驗元資料和每個 blob 後再落盤。成功的本地或遠端執行先上傳並校驗 blob,最後發布 action 結果,避免部分產物變成命中。透過命名空間、認證寫入、配額和沙箱阻止租戶洩露。快取失敗返回未命中並受控執行,同時用指標和抽樣乾淨重建發現錯誤命中。
分步深入
1. 定義 key 與儲存邊界
規範化 action 命令、編譯器和連結器版本、平台、宣告輸入、相關 flag、白名單環境變數和外部依賴鎖檔。用 Merkle 根表示輸入樹。排除秘密和不確定時間戳;非 hermetic action 應標記為不可快取或限制在明確範圍內。action 結果獨立保存輸出檔名、摘要、大小、退出碼,以及可選的 stdout/stderr 摘要。CAS 物件不可變,只由摘要尋址。
2. 設計命中、未命中和發布路徑
讀取時按租戶和 action key 命名空間路由到複製的元資料服務,取得結果後並行拉取缺失的 CAS blob。落盤前校驗大小與摘要。未命中時在本地或沙箱 worker 執行。用冪等摘要寫入上傳已校驗 blob,再以條件寫入一次性提交 action 結果,確保引用的 blob 全部存在。並行寫入可以上傳同一個 blob,但只有完整結果可見。blob 或元資料不匹配時應作為未命中並告警,不能返回成功命中。
3. 加入分布、隔離與安全
action 結果查詢可用一致性雜湊或元資料分片圖,並在故障域之間複製。大體積 CAS 放入物件儲存或分片 blob 層,熱點元資料放入低延遲儲存。每次請求認證並授權儲存庫和租戶命名空間,開發機預設只讀。傳輸和儲存加密,執行遠端 action 時使用沙箱和租戶配額。除非策略明確允許,不跨租戶去重;摘要不能繞過授權。
4. 規劃容量和生命週期
題設負載是每天 20,000 個工作 × 25 個 action,即每天 500,000 次查詢,平均約 5.8 QPS。按 20 倍突發估算約 120 QPS,還未計入並行 blob 讀取。若 10% 的 action 產生新的 300 MB 輸出,未壓縮入口約為每天 1.5 TB;壓縮和去重會降低實際儲存,但應預留多 TB 物件容量和頻寬餘量。垃圾回收從仍存活的 action 結果和 manifest 出發,沿摘要引用關係遍歷,經過寬限期後再按大小配額、LRU 或年齡清理。可達 blob 不能刪除,並要按租戶公平執行配額。
5. 讓故障和正確性可觀測
區分快取超時、權限失敗、blob 缺失、摘要不匹配和後端不可用。快取超時可以執行;持續故障需要准入控制、本地快取優先和有限重試,避免 CI 重試風暴。按儲存庫、action 類別、平台和工具鏈記錄命中率、查詢延遲、blob 頻寬、上傳中止、驅逐、損壞和租戶拒絕。定期清空本地快取做乾淨重建,比較執行日誌或產物摘要,以發現不確定性和錯誤命中。
強回答範例
我會提供兩個服務:認證的 action-cache 索引和不可變 CAS。action key 涵蓋規範化命令、編譯器與平台身分、宣告輸入 Merkle 根、白名單環境、flag 以及鎖定的外部依賴。命中返回輸出摘要,客戶端校驗並下載 blob 後再落盤。未命中進入沙箱執行,冪等上傳並校驗 blob,所有引用存在後才發布結果。action 元資料按租戶和儲存庫複製,CAS 跨故障域分片或放入物件儲存。快取故障時可回退執行;寫入只給可信 CI,並設定配額、加密和預設禁止跨租戶複用。容量按約 120 峰值 QPS 和多 TB 儲存規劃,再驗證命中率、摘要錯誤、不確定 action、並行寫入、工具鏈升級、GC 可達性和故障恢復。
常見錯誤
- 只雜湊原始碼,遺漏編譯器、flag、平台、環境或鎖定依賴。
- 把 action 結果和輸出 blob 放進一個可變記錄,導致部分發布。
- 不檢查命名空間授權就跨租戶複用摘要。
- 把快取不可用設計成建置全停,而不是受控未命中和回退。
- 使用一個全域 LRU,未追蹤存活 action 結果引用就刪除 blob。
- 把 stdout 或 stderr 數量當成命中率,應該記錄執行策略和明確的命中計數。
- 沒有乾淨建置、跨機器重現和不確定 action 測試就聲稱命中率很高。
追問與回答
編譯器工具鏈升級,但命令列沒有變化怎麼辦?
工具鏈身分必須進入 action key,通常使用固定摘要或版本化執行映像。遷移時可以雙讀舊命名空間用於回滾,但寫入應進入新命名空間並單獨統計未命中。不能只因原始碼和 flag 相同就複用舊產物。
快取被投毒後如何恢復?
停止不可信寫入,隔離受影響命名空間,並根據稽核日誌定位錯誤 action 結果及其可達 blob。失效 action 索引,用可信執行重建產物,再重新填充。恢復期間快取應保持可選,並保留證據供事故復盤。
action 在執行時下載未鎖定依賴怎麼辦?
這是非 hermetic action:在依賴固定且下載位元組納入輸入閉包前標記為不可快取。緊急情況下可以設定儲存庫範圍和短 TTL 的明確例外,但不能把它當作確定性複用。
如何從本地快取遷移且不讓 CI 中斷?
先以 shadow 模式讀取遠端快取,比較本地和遠端 key 及輸出摘要,再讓少量儲存庫啟用遠端命中。保留本地執行和本地快取回退,寫入僅開放給可信 CI,命中率、延遲和錯誤命中檢查通過後逐步擴大。