兩台 DGX Spark 級主機,一個模型:每台各放一份副本,取代拆分方式
維運
過去七週,我們的本地語言模型以張量並行方式拆分在兩台 NVIDIA GB10 機器上執行。10 月 22 日,我們改為在每台機器上放置完整的模型副本,並在前方加上最少連線數代理。吞吐量從約每秒 180 個 token 提升至 210 個,且任一機器重啟時,模型服務不會中斷。
為何先前要拆分
每台機器擁有 128 GB 記憶體,由 CPU 與 GPU 共用。9 月時,模型本身可容納於單台機器,但其快取幾乎放不下:我們使用的 vLLM 版本無法將此模型的 KV 快取以 FP8 儲存,因此快取採用 BF16 格式,單台機器僅能容納 499,110 個 token 的快取。這少於模型完整上下文長度 262,144 個 token 的兩個請求所需空間。透過兩台機器間的直接網路連結以張量並行拆分後,快取容量增至超過三百萬個 token。我們拆分模型是為了空間,而非速度。
改變了什麼
同一模型較新的 4-bit 版本(NVFP4,透過量化感知蒸餾製作)約佔用 71 GiB 記憶體,而適用於 GB10 的社群版 vLLM(eugr/spark-vllm-b12x)可將快取以 FP8 執行。現在單台機器可容納整個模型及 0.76 至 1.08 百萬個 token 的快取,視機器分配多少記憶體而定,可容納 2.9 至 4.1 個完整上下文長度的請求。兩份副本皆使用模型自身的推測解碼(MTP,四個草稿 token)。切換前,我們在新版本上執行工具呼叫測試:得分為 86,而被取代的版本得分為 75。
我們測量的結果
| 拆分於兩台機器 | 每台各一份副本 | |
|---|---|---|
| KV 快取 | 超過 300 萬個 token | 0.76 與 1.08 百萬個 token |
| 完整上下文下的請求數 | 約 12 個 | 2.9 與 4.1 個 |
| 我們負載下的吞吐量 | 約每秒 180 個 token | 每秒 210 個 token(111 + 99) |
| 啟動時間 | 約 20 分鐘 | 每份副本 5 至 13 分鐘 |
| 單台機器重啟 | 模型服務中斷 | 另一份副本繼續服務 |
單份執行個體,依同時處理的請求數量而定:使用短提示詞時,1 個請求每秒產生 36 個 token,4 個為 82,8 個為 109,16 個為 150。使用我們郵件代理程式的較長提示詞時,4 個為 81,8 個為 113,16 個僅為 87:超過八個此類請求後,增加數量反而會變慢。
在一個下午的測試中,一份執行個體最多同時處理 12 個請求,另一份為 8 個。前者每秒產生 91 至 93 個 token,每分鐘完成 26 至 27 個請求;後者每秒產生 81 至 83 個 token,每分鐘完成 22 個請求。兩者現在都設定為 12。
我們放棄了什麼
空間。分割模型擁有一個超過三百萬 token 的快取;執行個體則有兩個較小的快取,且請求只能使用處理該請求之執行個體的快取。我們的代理程式發送許多短至中長度的請求,對它們而言吞吐量更為重要。若您同時處理幾個非常長的上下文,分割可能仍是較佳的選擇。我們保留了分割設定,切換回去只需一個腳本。
切換過程中出了什麼問題
- 模型缺席十一分鐘,接著是 30 秒的 502 錯誤。拆分模型必須在副本能於相同機器上載入之前停止,因此我們的代理等待了約十一分鐘。當第一個副本啟動時,代理伺服器又持續回應「502 no live upstreams」約 30 秒:它在後端離線期間已將它們標記為失敗(
max_fails=3、fail_timeout=30s),直到該時間結束前都不再嘗試連線。 - 繞過代理伺服器的客戶端。我們的一個批次作業在設定中寫入了第一台機器的位址,導致其所有負載都集中到一份執行個體,而另一份則有閒置容量。現在所有客戶端都透過代理伺服器;機器本身的位址僅用於健康檢查。
- 跳動的指標。我們的吞吐量監控器透過代理伺服器讀取 vLLM 的
/metrics。在兩個後端的情況下,連續的讀取來自不同的副本,計數器來回跳動,監控器因此報告模型處於飢餓狀態。現在它直接讀取每個副本並加總。 - 原本會阻止新副本啟動的舊守護程序。拆分設定有一個守護程序,會在模型停止回應時重啟其服務。新服務宣告與舊服務
Conflicts=,因此該重啟動作會阻止新副本啟動。必須使用systemctl disable --now將其關閉,而不只是停止,因為我們的維運層會重啟已啟用但未執行的單元。 - 執行其他工作的機器上的記憶體。其中一台機器也執行我們的資料庫與網站建置。將 vLLM 的
gpu-memory-utilization設為 0.78 時,僅剩 5 GiB 供其他所有用途使用,因此我們將其降至 0.74,並僅重啟該副本,同時由另一個副本承擔負載。在這些機器上,您分配給 vLLM 的份額與其他所有服務共用同一份記憶體。
如果您有兩台這類機器
- 如果模型與您需要的快取能容納在一台機器上,請在每台機器各執行一個副本,並置於最少連線代理之後。僅當單台機器無法容納所需快取時,才拆分模型。
- 將所有客戶端指向代理,包括批次作業與舊設定。
- 直接從每個副本讀取指標。
- 根據每台機器上執行的其他工作,分配各自的記憶體份額。
- 根據您的流量設定每個副本同時處理的請求數:以我們的流量組合而言,12 優於 8。
- 預期切換過程會使模型離線一段等於副本啟動所需的時間,並據此規劃。
Factory Floor 提供一台或兩台機器的代理與啟動設定、切換模型前執行的健康檢查與工具使用測試,以及針對機器其餘部分的守護程序與記憶體防護機制。