ANDREW/
選單觀點
中文EN
← 回到文章庫

TECHNOLOGY / ARTIFACTS / OFFLINE STARTUP

下載成功,需要時還在嗎?

Andrew Yuan · 技術實驗

下載完成,是一件已經發生的事

想像公司說:「放心,檔案已經下載好了。」進度是 100%,紀錄顯示 Success。直到真正需要使用時,才發現檔案後來被清掉了。

下載紀錄還在,檔案已經不在。系統沒有說謊;只是我們拿一個過去事件的答案,回答了另一個關於現在的問題。

我做的 Cacheweft,是一個本地 HTTPS Artifact Cache。它用沒有特權的本機 Daemon 與 CLI 管理下載,保存進度,並依可信管理者提供的大小與 SHA-256 驗證內容,通過後才發布為不可變的 Artifact。這裡的不可變是受管理操作的契約,不是對惡意同 UID 程序或 root 的防竄改保證。

成功下載的收據旁是空托盤:下載成功,需要時還在嗎?
概念插圖:成功收據與空托盤呈現歷史事件和當下可用性的差別,不是實際操作介面。

成功紀錄回答的是「那次請求完成了嗎」。內容現在是否仍在,以及應用程式能否用它啟動,還需要各自檢查。這個區別,也決定了清理之後該如何處理舊請求。

把 Cache 接到服務,才看見啟動的契約

這次我在原生 macOS 做了一個受控整合,讓既有、未修改的 tiny-batch-service HTTP 推論服務,從 Cacheweft 管理的 Digits 模型啟動。它不是外部團隊採用的案例,也沒有新增遠端 Cache 管理介面。

Repository 裡另有可選的啟動整合程式。它使用實際安裝的 Cacheweft CLI,等待下載請求成功,確認內容可取用,再比對應用程式自己信任的 Release Digest。接著明確設定 Pin,存出一份應用程式持有的模型檔,再驗證這份檔案,最後才啟動既有服務。這個整合程式不在 Cacheweft 的 runtime wheel 裡。

這些步驟有不同用途。管理者的 Manifest 決定 Cache 可以接受哪些預期內容;應用程式的 Release Digest 決定這次啟動要使用哪個版本。兩者不符,不能只因為「Cache 裡有一個成功下載的模型」就繼續。

實際指定錯誤的 Release Digest 時,整合程式在推論服務啟動前拒絕繼續。這是這份啟動契約的檢查,不表示 Cacheweft 能自動替任意應用程式決定正確版本。

來源停用之後,啟動一個新的服務程序

冷啟動先下載並 Pin 住 9,890 bytes 的 Digits 模型,啟動服務,以七筆選定資料發出實際 HTTP 推論請求。七筆回應都在約定容差內符合獨立產生的參考機率。

接著停止受控的 HTTPS 來源,重啟 Cacheweft,再啟動新的服務 Worker。它載入相同模型 Digest,七筆回應再次符合參考值;保留的傳輸計數沒有增加下載嘗試,也沒有增加接收的內容 bytes。

我特別保留「新的程序」這個條件。原本仍在執行的程序可能早已把模型載入記憶體;讓它繼續回應,不能獨立證明下次啟動仍拿得到模型。

這裡的離線證據限於受控來源已停止,並以正式傳輸計數核對沒有新增嘗試。這次沒有追蹤系統呼叫,也沒有把整台主機所有網路關閉;不能將結果擴大成任意斷網環境或全部外部相依性都已排除。

Pin 保住什麼,也留下誰的工作?

下載成功,不代表內容永久保留。測試明確解除 Pin 並執行 GC 之後,再拿原本成功的 Request ID 啟動,整合程式因內容已不可用而拒絕啟動服務。舊紀錄仍然成功,卻不會因此重新下載或讓內容憑空回來。

Cacheweft 重啟後,未完成的有期限請求會標記為 INTERRUPTED。要續傳,需要用新的 Request ID 與新的期限明確提出請求;重送舊 ID 會保留原來的結果與期限,不會自動變成新的下載嘗試。已提交的發布意圖另有復原流程,不能把所有重啟狀態都叫作續傳。

Cacheweft 的 Pin 是共用的布林保留標記,不是每個消費者各持一份的租約,也不是參考計數。啟動整合程式會留下 Pin;它不會在某個程序退出或後續失敗時自動解除,因為其他使用者可能仍需要同一份內容。

這個選擇避免一次程序退出就移除別人的保留保護,但也留下維運工作:誰知道哪些版本還在使用?誰決定可以解除 Pin?空間不足而無法接納新 Artifact 時,由誰調整保留計畫?如果沒有接手安排,保守保留也會逐漸變成容量問題。

應用程式另存的模型檔不在 Cache 的用量計算與 GC 範圍內,需要另外管理。反過來說,清掉 Cache 也不會自動撤回這份副本,或讓已載入模型的服務立即停止。這次舊 ID 案例證明的是啟動整合程式不再接受那份準備狀態,並非所有使用者都失去既有副本。

三分鐘與 360 個請求,仍然是有邊界的觀察

應用整合和 Linux VM 的資源觀察是兩組證據,不能混成一次端到端壓力測試。前者只驗七筆選定資料的兩次啟動,不是完整測試集的準確率評估,也不是推論效能比較。

另一組既有 Linux VM closeout 使用實際安裝的 systemd 服務,在同一程序中完成 180.016 秒、90 個循環與 360 個接納的請求。每輪包含完整下載與回收、部分下載逾時後明確續傳,以及取消操作。因此 360 不是成功下載次數,更不是推論次數。

RSS 的早期中位數取自第 30–60 秒,晚期中位數取自第 150–180 秒,分別為 26,193,920 與 26,275,840 bytes,相差 81,920 bytes,也就是 80 KiB。FD 與執行緒的中位數維持不變;程序身分與 systemd 執行身分在這段觀察中沒有改變。

這些結果通過那份固定工作負載的門檻,但沒有證明零洩漏或長期維持相同的資源水位。保留的請求歷史仍會占用 Metadata;GC 回收 Payload,不會順便消除歷史。本文引用既有紀錄,沒有為寫作重新執行 VM、硬體或應用整合。

把「離線可用」寫成能驗收的條件

部署前,我會把目前要承諾的版本、啟動方式與保留責任一起寫清楚。以下四個受測案例各自回答不同問題;通過其中一個,不能替另外三個背書。

窄螢幕可左右滑動表格,查看完整內容。

從下載完成,到應用啟動的四個檢查
受測情境保留的結果仍不能推論什麼
冷啟動取得指定模型下載、Pin 與啟動完成;七筆推論符合參考值。不是完整準確率或負載驗證。
來源停止、Cache 重啟、新 Worker 啟動七筆推論仍符合參考值;沒有新增傳輸嘗試或接收 bytes。不是所有外部相依性都已排除。
應用程式指定錯誤的 Release Digest整合程式在推論服務啟動前拒絕繼續。沒有證明模型來源或模型本身安全。
解除 Pin、GC 後重用舊成功 ID因內容不可用,整合程式不啟動推論服務。不表示已另存的應用副本也被刪除。

實際交付時,還需要有人承擔這些條件的維護。Release Digest 由誰核准?必要版本要保留到什麼時候?應用程式退役後,由誰清掉它的副本並協調解除 Pin?歷史容量或磁碟空間用盡時,有什麼可執行的處置?

保留全部版本會增加儲存與管理成本;太早釋放,又可能讓來源不可用時的新服務無法啟動。這是部署者要明確決定的取捨,不能只交給一個「下載成功」燈號。

雜湊、重啟與離線,各有自己的邊界

雜湊一致,表示內容符合可信的預期值;它本身不證明發布者身分、模型安全或授權條件。可信 Manifest 的取得與更新,仍是部署環境要處理的信任問題。

目前是本地、受信任使用者範圍內的服務,沒有對抗惡意同 UID 或 root 的隔離保證。邏輯容量預算不是檔案系統配額,應用副本另計;請求與 Manifest 歷史有限,也沒有自動輪替。

突然斷電後的恢復、systemd 開機自動可用性與開機零空窗,都沒有在這些紀錄中完成驗證。三分鐘的受控循環,以及小模型的七筆推論,也不能支持長期穩定或大型模型部署的保證。

可用性最後仍需要有人承接

對我來說,這次整合最有用的地方,是把一個模糊的「應該有」拆開來檢查:我們要哪個版本、內容現在還在不在、全新的服務能不能使用,以及誰有權決定它不再需要保留。

Cache 可以保存下載進度、驗證內容,也可以拒絕把舊成功紀錄當成現在可用。但必要版本的保留時間、應用副本的生命週期與退役安排,仍然需要進入部署與維運計畫。下載成功,是過去發生的事件;需要時仍然可用,要有當時足夠的證據與接手安排。

來源與保留紀錄

程式碼:GitHub / Cacheweft · MIT 授權。證據連結固定到核對版本;較早量測保留原有來源與版本。

分享這篇