「同一個 CI 任務越跑越久」不能直接推導出 Mac 變慢。Git LFS 官方文件明確區分指標檔案與 LFS 物件;fetch 完成也不等於工作區已經填入完整檔案。Git LFS 機制說明 是判斷這個邊界的依據。
症狀: iOS CI checkout 階段拉長,團隊直覺想增加 Mac 建置機。
最快解法: 先分別量 Git 資料、LFS 物件、工作區恢復、依賴與 Xcode 建置;只有 CPU、記憶體或建置佇列持續飽和,才擴充固定或彈性遠端 Mac。
這篇文章適合維護大量 Git LFS 資源、且 iOS CI 檢出階段明顯變慢的研發效能負責人。
如果你負責 Mac 建置容量、憑證隔離、快取污染或企業基礎設施預算,本文可作為試點驗收與採購判斷表。
先看哪個指標:Mac 真的慢,還是資料路徑在等待?
Git LFS 為什麼會讓 iOS CI checkout 時間越來越長?常見原因不是單一的 Mac 效能下降,而是每次任務拉取了不必要的物件,或快取沒有真正命中。你需要把 checkout 拆成可比對的階段,而不是只讀取 CI 平台顯示的總耗時。
建議在同一個 commit、同一個 Xcode 建置指令和同一組依賴條件下,建立兩組基線:
- 冷啟動基線:清除工作區與可控的 LFS 物件快取後執行。
- 重複執行基線:保留允許復用的快取,再執行相同任務。
- 記錄 Git 物件傳輸、LFS 物件下載、工作區填充、依賴恢復與 Xcode 建置的起止時間。
- 同時保留下載位元組、失敗重試、磁碟使用量和節點等待時間。
判斷原則很直接:
- 網路等待和 LFS 下載佔主要比例:先優化資料路徑、拉取範圍或快取。
- 工作區填充反覆耗時:檢查 checkout 行為、深度、分支範圍和工作區是否可安全復用。
- Xcode 建置期間 CPU 或記憶體長時間飽和:才評估 Mac 節點規模。
- 任務在佇列中等待,但單次建置不飽和:優先檢查節點數與排程,而非升級單台 Mac。
這也是「Git LFS 下載慢時,應優化網路還是增加 Mac 建置機」的實際判斷方式:先看階段時間和下載量,再決定資源類型。增加 Mac 只能增加可同時執行的建置能力,不能縮短一個被資料傳輸卡住的 checkout。
建議的階段計時表
| 指標 | 要記錄的證據 | 代表的瓶頸 | 優先處置 |
|---|---|---|---|
| Git 物件傳輸 | clone、fetch 的時間與位元組 | Git 歷史或分支範圍過大 | 調整深度、分支與任務範圍 |
| LFS 物件下載 | 實際下載量、重試與來源 | LFS 儲存端或網路路徑 | 路徑過濾、快取、頻寬 |
| 工作區恢復 | checkout 或填充時間 | 指標檔案與物件使用方式不一致 | 復核 checkout 流程 |
| 依賴恢復 | 套件快取下載與解壓時間 | 依賴快取失效 | 重新設計快取鍵 |
| Xcode 建置 | 編譯、連結、簽署時間 | Mac CPU、記憶體或磁碟 I/O | 評估節點擴充 |
| 佇列與恢復 | 等待、失敗重試、重新分配 | 節點容量或故障冗餘 | 固定池、彈性池或混合模式 |
不要把某次任務的總時間當作唯一硬指標。只有在相同輸入、相同工作流程下比較,冷啟動與重複執行的差異才有決策價值。
拉取範圍如何改變每次流水線的資料成本?
Git LFS 指標檔案很小,真正的二進位資源則以 LFS 物件形式管理。取得 Git 歷史、下載 LFS 物件,以及將物件填入工作區,是三個不同動作。Git LFS fetch 手冊 說明了 fetch 的物件取得行為;Git clone 官方文件 則可用來核對 clone 的深度、分支和工作樹設定。
CI 中可以只下載目前任務需要的 Git LFS 檔案嗎?可以,但必須先確認任務所需的資源集合,而且要把過濾條件納入可重現的流水線設定。Git LFS 的 include 與 exclude 不是「下載完成後刪除檔案」;它們會影響要取得哪些物件。最小診斷片段可保留為:
git lfs fetch --include="path/to/assets/**" --exclude="path/to/assets/test/**"
git lfs checkout
這段指令只能作為隔離倉庫中的驗證起點。正式導入前,請確認 checkout 元件是否自行管理 LFS,以及它是否覆寫深度、憑證或工作區策略。checkout 元件參數文件 明確提醒,不同版本和設定會影響檢出行為,不能只依賴 Git LFS 指令名稱推測結果。
以任務資源集合取代全量拉取
| 拉取策略 | 適合的任務 | 優點 | 風險與驗收 |
|---|---|---|---|
| 全量拉取 | 發布、完整回歸、需要所有資源的建置 | 流程簡單,資源缺失風險較低 | 每個 PR 都承擔不必要的傳輸 |
| 路徑 include/exclude | 單一模組、指定平台或資產集 | 降低下載範圍 | 路徑變更可能造成隱性缺檔 |
| 任務拆分資源集 | 圖片、影片、模型等大型資源分屬不同工作 | 可按工作需求拉取 | 工作間依賴和快取鍵更複雜 |
| 淺層與指定分支 | PR 驗證只需當前提交 | 減少 Git 歷史傳輸 | 需要版本標籤或完整歷史的任務不適用 |
請先盤點倉庫實際的 LFS 物件清單,再按 PR 驗證、夜間回歸和發布建置分組。不要因為 fetch 成功就判定工作區可用;驗收時必須檢查關鍵路徑是否由指標檔案變成完整內容,並讓建置產物或資源校驗失敗時立即中止。
快取命中率與工作區隔離,哪一個更影響遠端 Mac?
自託管 Mac 如何復用 Git LFS 快取而不污染工作區?關鍵是把「物件快取可復用」和「工作區可復用」分開管理。前者保存可驗證的 LFS 物件,後者保存特定 commit 的檔案狀態;兩者的生命週期、權限和清理條件不應相同。
你至少要記錄以下指標:
- 實際下載位元組和重複物件比例。
- 快取命中前後的 LFS 階段時間。
- 快取目錄的磁碟增長趨勢。
- 工作區是否曾殘留上一個分支的檔案。
- 清理後重新執行能否得到同樣的資源校驗結果。
長期在線的專用 Mac 適合受控復用。它可保留經過驗證的物件快取,但每次任務仍應以乾淨的工作區、明確的 commit 和可追溯的快取鍵開始。共享工作區的優點是少做初始化,缺點是殘留檔案、錯誤權限和跨分支污染更難排查。
彈性遠端 Mac 則不應假設一定有熱快取。你可以用可信的預熱任務、分層資源集或預先同步的快取降低冷啟動影響,但實際收益必須來自同一條 iOS CI 流水線的冷、熱基線。沒有企業記錄或本站實測,就不要宣稱固定節點一定快多少,也不要用外部典型值代替你的倉庫資料。
第一步:先建立可清理的快取邊界
快取鍵至少應包含專案、資源集合、版本或提交範圍與信任等級。清理策略則應同時有:
- 磁碟容量門檻。
- 長時間未使用物件的回收條件。
- 任務失敗後的工作區清理。
- 發布節點與 PR 節點的物理或權限隔離。
- 清理後的完整性重跑。
依賴快取也不能和 LFS 物件快取混為一談。官方 CI 快取安全文件指出,快取內容可能被同一儲存庫後續執行的程式碼讀取;因此,快取鍵、分支信任和敏感資料不能只靠目錄名稱區分。官方依賴快取安全說明 可作為設計快取存取邊界的參考。
憑證和資源完整性,如何限制加速方案?
加速後最危險的結果,不是任務多花幾分鐘,而是建置在缺少資源的狀態下仍然產出看似成功的結果。請把以下檢查加入驗收:
- 關鍵 LFS 路徑必須通過內容或雜湊校驗。
- 失敗的物件下載不能被空檔案、指標檔案或舊工作區內容掩蓋。
- 發布節點的簽署權限不得因為快取需求而下放給一般 PR。
- LFS 下載憑證、原始碼存取權和程式碼簽署權限分開管理。
- 非可信分支不得繼承生產發布節點的長期憑證。
Git LFS 凭證、倉庫令牌、持久化工作區和跨專案快取會形成不同暴露面。下載權限只解決「能否取得資源」,不代表可以進行簽署或發布。對自託管 Runner,應再檢查工作區清理、節點標籤、網路出口、日誌遮罩和任務完成後的令牌處理。自託管 Runner 安全文件 提供了自託管執行環境的風險邊界。
第二步:用可重複任務驗收完整性
準備一個不修改原始碼的驗收工作,依序完成:
- 取得指定 commit,不使用浮動分支。
- 記錄 Git 和 LFS 下載量。
- 執行指定路徑的工作區恢復。
- 檢查關鍵資源不是 LFS 指標檔案。
- 執行資源雜湊或專案內建校驗。
- 執行最小 Xcode 編譯或測試。
- 清理工作區後再次執行,對比結果。
若第二次任務依賴第一次殘留的檔案才能成功,這不是快取命中,而是工作區污染。此類節點不應直接承接生產發布工作。
節點吞吐指標決定擴容方向
Git LFS 優化後,仍需用四個容量指標判斷節點是否不足:有效建置時間、峰值到達率、排隊時間和故障冗餘。不要用開發者人數或硬體宣傳規格直接估算節點數,因為同一團隊的 PR、夜間回歸和發布工作負載可能完全不同。
可以用不帶預設金額的 TCO 模型比較方案:
TCO = 網路流量成本 + 儲存成本 + Mac 佔用時間 + 維運工時 + 故障影響成本
其中,Mac 佔用時間應按實際任務和佇列記錄計算;網路與儲存則按你的供應商帳單或內部成本模型填入。未取得真實價格前,不要預填每月金額或宣稱某方案節省固定百分比。
| 觀察到的證據 | 優先方案 | 不應先做的事 |
|---|---|---|
| LFS 下載等待佔主要時間 | 路徑過濾、快取與資料路徑優化 | 直接購買更多 Mac |
| 下載量下降但 Mac 編譯持續飽和 | 增加固定建置節點 | 只升級 LFS 儲存端 |
| 單次建置不飽和但佇列很長 | 增加可並行節點或彈性遠端 Mac | 只更換單台更快的 Mac |
| 快取造成跨專案污染 | 專案、信任等級和工作區隔離 | 擴大共享快取範圍 |
| 峰值短、平日負載低 | 固定可信節點加彈性容量 | 為全年峰值購買全部實體機 |
| 需要穩定簽署與物理介面 | 專用固定 Mac 池 | 將生產簽署工作完全放到不受控共享節點 |
固定 Mac 池適合發布簽署、長期快取和可預測負載。彈性遠端 Mac 池適合短時間峰值、試點和不值得全年持有的容量。混合模式則保留少量可信固定節點,把 PR 驗證、夜間回歸或峰值併發交給彈性節點。
如果你要比較不同地區的遠端 Mac 交付方式,可先查看 KVMNODE 的遠端 Mac 方案頁面,再用同一份流水線驗收,而不是以節點規格表取代實際測試。
第三步:用驗收矩陣決定「只優化、擴容或混合」
在採購或遷移前,把每一項結果寫成「證據、門檻、失敗處置」。不要只留下「速度變快」這類無法稽核的結論。
建議矩陣至少包含:
- 冷啟動:完整下載量、LFS 時間、工作區恢復時間。
- 熱快取:重複物件比例、快取命中後時間、磁碟增長。
- 資源完整性:指標檔案檢查、雜湊校驗、建置產物檢查。
- 憑證隔離:PR、一般分支和發布節點的權限差異。
- 磁碟回收:達到容量門檻後是否可清理並成功重跑。
- 佇列容量:峰值期間等待時間和並行任務數。
- 故障恢復:節點中斷後能否重新分配,且不使用污染工作區。
- TCO 輸入:流量、儲存、Mac 佔用、維運與故障影響的實際記錄。
最後輸出三類結論:
- 只優化 Git LFS:傳輸與工作區階段是主瓶頸,Xcode 建置未持續飽和。
- 直接擴充 Mac 容量:資料階段已穩定,CPU、記憶體、建置佇列或故障冗餘仍不足。
- 固定可信節點加彈性遠端 Mac:發布需要固定隔離,峰值或非生產工作又具有明顯波動。
如果你尚未有遠端節點的真實記錄,可以先用 KVMNODE 的 Mac mini 遠端租用資訊 規劃短期 PoC;重點不是先承諾節省多少,而是將相同倉庫、相同 LFS 資源集和相同 Xcode 任務搬到試點中,取得冷啟動、熱快取、實際建置與峰值排隊證據。
當前以自購 Mac 為主的方案,常見限制是容量一次買死、峰值後硬體閒置,以及硬碟、系統更新、故障替換和遠端辦公連線都要由團隊自行維護。全雲端方案則可能面對 LFS 大物件反覆傳輸、快取失效和簽署環境隔離問題。若你已完成分階段計時,需要驗證短期峰值或跨地區團隊的 Mac 建置容量,租用 KVMNODE 的遠端 Mac 會比立即追加固定硬體更容易先取得可比較的流水線證據;但長期穩定重負載、需要物理介面,或已有成熟機房維運能力時,自建固定節點仍可能更合適。