
本系列前幾天講的是開源服務怎麼封裝到容器中,給伺服器或 NAS 跑,至於這些服務要跑在什麼機器上、機器夠不夠、儲存要多大,則是接下來的題目。我在前一個系列的 Day 16 回答的是「要選哪個模型」,選型的五個問題後來做成了 open-model-selector 這個工具。今天把同一個工具反過來用,模型清單是輸入,節點數、記憶體、儲存容量、網路頻寬是輸出。
維運的容量規劃跟選型有一個根本差別。選型可以一次選一個,容量規劃要算的是「同時」。哪幾個模型要同時常駐、幾個人同時用、每個人開多長的 context、模型庫一年會長到多大、新模型從 NAS 載進節點要多久。這些數字決定買幾台、買多大,也決定 Day 11 的守護要盯哪些邊界、Day 13 的儲存實測要量什麼、Day 30 的電費怎麼算。
文章依 open-model-selector 的 commit 03f126f 撰寫。這個 commit 把 data.js 的每個數字都補上來源,權重檔大小取自 Hugging Face 上的量化檔,KV cache 的每 token 成本改為依模型的 config.json 推導(BF16、只計全注意力層),查不到的欄位設為空值。前一版的 KV 值普遍低估好幾倍,今天的表如果用舊版算,結論會整個相反,這件事在本文後面的第二節會講。場域的設備清單見索引 repo 的 lab/inventory.md。
| 問題 | 這個場域的答案 | 決定了什麼 |
|---|---|---|
| 有哪些工作負載 | 內部對話與 Agent 迴圈、長文與程式庫的 RAG、ComfyUI 圖像與影片生成、封裝測試 | 模型的形狀,MoE 或 Dense |
| 尖峰時同時常駐幾個模型 | 一個對話用 MoE 加一個長文用 Dense,ComfyUI 另外一台 | 節點數與每台的記憶體 |
| 同時幾個 session、多長 context | 五人團隊,尖峰 8 個 session,Agent 迴圈開 32k | KV cache 的預算 |
| 模型庫多大、一年長多少 | 目前約 600 GB,每月新增兩到三個模型 | NAS 容量與 Day 12 的清理規則 |
| 冷啟動可以等多久 | 對話服務 2 分鐘內,批次工作不限 | 節點與 NAS 之間的網路,以及哪些模型要放本機 SSD |
| 電費與散熱的上限 | 一間有冷氣的辦公室,一個 20A 迴路或二個 15A 迴路 | Day 11 的熱守護、Day 30 的一年成本 |
第一列的答案來自前一個系列,第三、四列是依團隊規模推的估計值,其他部分的計算請往下看囉。
open-model-selector 的「能跑嗎」用的公式是這一行。
需要的記憶體 = 權重檔大小 + KV cache 每 token 成本 × context 長度 + 2 GB 執行期預留
完美暢跑 = 需要的記憶體 ≤ 0.85 × (可用記憶體 − 共存保留)
0.85 是給碎片與峰值的餘裕,2 GB 是 CUDA 或 Metal 執行期的固定開銷,兩個係數都是工具的預設值。KV cache 每 token 的成本依注意力架構差很多,同樣是 30B 上下的模型,傳統 GQA 的 Qwen2.5-Coder-32B 是 256 KB,混合注意力的 Qwen3.8-27B 只有 64 KB,DeepSeek-V4-Flash 的 MLA 只有 5.4 KB。
工具一次算一個模型一個 session。容量規劃要的是多 session 與多模型,把公式展開就是把 KV 項乘上 session 數、把多個模型的權重與預留加總。以下是 DGX Spark 128 GB 統一記憶體、不保留給其他程式、32k context 的結果,單機預算是 0.85 × 128 = 108.8 GB,兩台合計 217.6 GB。
| 模型與量化 | 權重 | KV 每 session | 1 session 合計 | 8 session 合計 | 單機 108.8 GB 內 |
|---|---|---|---|---|---|
| gpt-oss-120b MXFP4 | 63.4 | 1.13 | 66.5 | 74.4 | 是 |
| Llama-3.3-70B Q8_0 | 75.0 | 10.00 | 87.0 | 157.0 | 只到 3 session |
| Llama-3.3-70B Q5_K_M | 49.9 | 10.00 | 61.9 | 131.9 | 只到 5 session |
| Ornith 1.5 35B-A3B Q8_0 | 37.8 | 0.63 | 40.4 | 44.8 | 是 |
| Qwen2.5-Coder-32B Q8_0 | 34.8 | 8.00 | 44.8 | 100.8 | 是,餘 8 GB |
| Qwen3.8-27B Q8_0 | 29.0 | 2.00 | 33.0 | 47.0 | 是 |
| DeepSeek-V4-Flash UD-Q4_K_XL | 155.1 | 0.17 | 157.3 | 158.4 | 否,兩台合計內 |
| DeepSeek-R1 UD-Q2_K_XL | 226.6 | 2.14 | 230.7 | 245.8 | 否,兩台合計也超過 |
單位 GB,context 32,768 tokens,KV 以 BF16 計。
第一,KV cache 會不會成為瓶頸,看的是注意力架構,不是參數量。Llama-3.3-70B 每個 32k 的 session 要 10 GB,8 個 session 光 KV 就 80 GB,比 Q5 的權重還大,Qwen2.5-Coder-32B 的 8 個 session 要 64 GB。反過來,MoE 的 gpt-oss-120b 與 Ornith,以及混合注意力的 Qwen3.8-27B,8 個 session 只多 5 到 16 GB。選 Dense 模型做多人服務時,要先查它是不是傳統 GQA,是的話 session 數就是記憶體的主項。Ollama 的 OLLAMA_KV_CACHE_TYPE=q8_0 可以把 KV 減半,代價是另一個要驗的品質變數,今天的表不算它。
第二,工具前一版把這幾個模型的 KV 記成實際值的四分之一到十六分之一,用舊值算會得到「8 個 session 的 KV 在 Dense 上也只有幾 GB,不是瓶頸」的結論。這是用工具做容量規劃需要留意的,公式對不代表輸入對,每一個輸入要能追到來源。
第三,DeepSeek-V4-Flash 的總參數是 284B,4-bit 級就要 155 GB,單機放不下,兩台合計的 217.6 GB 預算內放得下,這正是前一個系列 Day 27 雙機合體的實驗平台。671B 的 DeepSeek-R1 連 Q2 都要 230 GB,超過兩台合計,不是這兩台機器的選項。雙機跨機執行的代價前一個系列 Day 27 實測過,它留給實驗,不進生產。
繁體中文有一條前一個系列量出來的限制,4-bit 量化在繁中的劣化是英文的 1.67 到 2.00 倍,所以對話與 Agent 用途從 8-bit 起跳,這也是上表多數列用 Q8_0 的原因。
尖峰時要一個對話用的 MoE 加一個長文用的 Dense 同時在記憶體裡。先看它們能不能擠在同一台。
| 組合 | 每模型 session 數 | 合計 | 單機餘裕 |
|---|---|---|---|
| gpt-oss-120b MXFP4 加 Qwen3.8-27B Q8_0 | 1 | 99.5 | 9.3 |
| gpt-oss-120b MXFP4 加 Qwen3.8-27B Q8_0 | 2 | 102.7 | 6.1 |
| gpt-oss-120b MXFP4 加 Qwen3.8-27B Q8_0 | 4 | 108.9 | 不足 0.1 |
| gpt-oss-120b MXFP4 加 Ornith 1.5 Q8_0 | 1 | 107.0 | 1.8 |
| gpt-oss-120b MXFP4 加 Qwen2.5-Coder-32B Q8_0 | 1 | 111.3 | 不足 2.5 |
| gpt-oss-120b MXFP4 加 Llama-3.3-70B Q5_K_M | 1 | 128.4 | 不足 19.6 |
單位 GB,32k context。
能擠的只有 gpt-oss 加 Qwen3.8,而且每個模型 2 個 session 就只剩 6 GB。這在工具上會亮綠燈,在維運上不能當平時的組態,Day 11 的記憶體守護門檻會比 6 GB 更早觸發。第二節的節點規則從這裡來。
Ollama 的 OLLAMA_MAX_LOADED_MODELS 與 OLLAMA_NUM_PARALLEL 決定了同時載入幾個模型與每個模型幾個 session,這兩個值是 Day 8 設定檔裡的兩個鍵,容量規劃算出來的數字要寫回去。要注意 OLLAMA_NUM_PARALLEL 會讓 Ollama 依 context 長度乘上平行數配置 KV,設 4 就是一次保留 4 份 32k 的 KV,不是用到才長。
節點數由「尖峰時要同時常駐的模型組合」決定,不由模型總數或總參數量決定。這個場域的常駐組合是兩個 LLM 加 ComfyUI,ComfyUI 在 Intel 工作站上,兩個 LLM 分在兩台 DGX Spark 上各一個,而非擠在一台。理由有三個,上表顯示擠在一台時每個模型只能給 2 個 session,一台掛掉另一台還在,Day 11 的熱守護降載時不會兩個模型一起變慢。
所以每台節點的設定是 OLLAMA_MAX_LOADED_MODELS=1、OLLAMA_NUM_PARALLEL=4,兩台合計 8 個 session,符合第一節的尖峰。gpt-oss 那台 4 個 session 是 69.9 GB,Qwen3.8 那台是 39.0 GB,兩台都有 40 GB 以上的餘裕。
另外寫下降級組態。一台故障時把兩個模型擠到剩下那台,改成 OLLAMA_MAX_LOADED_MODELS=2、OLLAMA_NUM_PARALLEL=2,總 session 從 8 降到 4,餘裕 6.1 GB。這是故障期間的暫時組態,要寫進 Day 26 的變更紀錄,修好後改回來。兩台的 100GbE 直連留給實驗與模型同步,不是生產路徑。
模型庫的容量不是「選定的模型加總」,有四個乘數。
| 項目 | 估算 | 說明 |
|---|---|---|
| 選定模型的量化檔 | 約 290 GB | 上表前六列,gpt-oss、Llama 兩種、Ornith、Coder-32B、Qwen3.8 |
| 同一模型的第二種量化 | 約 100 GB | 8-bit 給對話、4-bit 給共存型工作站 |
| Ollama 的 blob 副本 | 約 165 GB | Day 8 講過,Ollama 匯入 GGUF 會複製一份進自己的 blob 目錄,以生產的四個模型計 |
| ComfyUI 的 checkpoint、VAE、LoRA | 約 100 GB | Day 7 的 <Public>/models |
| 小計 | 約 655 GB | 與第一節「目前約 600 GB」相近 |
| 雙機實驗用的 DeepSeek-V4-Flash | 155 GB | 一個實驗模型就是模型庫的四分之一 |
最後一列單獨列出,是因為它說明了模型庫會怎麼長。生產用的模型幾十 GB 一個,實驗用的大型 MoE 一個就上百 GB,模型庫的成長主要由實驗決定,不由生產決定。每月新增兩到三個模型,每個 20 到 150 GB,一年約 1 到 2 TB。Day 12 的清理規則會退掉被取代的版本,版本要保留幾代、退掉之前要留多久是那天要決定的事,今天先用「保留兩代」來估算,一年後的模型庫約 2 TB。
TS-464 是 4 bay 機種,在這系列,容量不是 NAS 的瓶頸,要看的是讀取速度,也就是往下會說明的部分。
前一個系列測試過一條規則,也就是這系列文章中使用工具的儲存決策頁內容。如果地端 AI 模型的檔案大小能夠塞進統一記憶體,那權重放 NAS 的代價只是冷啟動多十幾秒的一次性成本。放不進記憶體的模型則絕對不放 NAS,因為每一次分頁回收再讀取都走網路,最慘的案例總載入時間將慢 3.8 倍。第二條規則呢,是 loader 的磁碟依賴度,GGUF 走 mmap 的磁碟依賴達 73%,vLLM 載入後幾乎不再碰磁碟。
套用到這個場域。DGX Spark 上生產用的模型都放得進記憶體,全部從 NFS 載入,本機的 NVMe 只放 Ollama 的 blob 目錄與 KV cache 的溢出。Intel 工作站的 RTX 5060 Ti 只有 16 GB,跑 Qwen2.5-Coder-32B Q4_K_M 的 19.9 GB 會部分卸載到 CPU,這台的模型要放本機 SSD。AMD 工作站的 RTX 3060 12 GB 同理。
模型從 NAS 載入節點的時間是檔案大小除以有效頻寬。以線速的 85% 估有效頻寬。
| 鏈路 | 有效頻寬 | 63.4 GB(gpt-oss-120b) | 34.8 GB(Coder-32B Q8) |
|---|---|---|---|
| 2.5GbE | 0.27 GB/s | 239 秒 | 131 秒 |
| 10GbE | 1.06 GB/s | 60 秒 | 33 秒 |
| 100GbE | 10.6 GB/s | 6 秒 | 3 秒 |
第一節說對話服務的冷啟動要在 2 分鐘內。TS-464 的內建網路是兩個 2.5GbE 埠,走它載入 gpt-oss 要 4 分鐘,不合格。這個場域的 TS-464 已在 PCIe 插槽裝了 QNAP 的 QXG-10G1T,單埠 RJ45 的 10GbE 網卡,接上 10GbE 交換器之後估算是 60 秒,合格。兩台 DGX Spark 各自接 10GbE 交換器,節點端不是瓶頸。100GbE 只在兩台 DGX Spark 之間,NAS 不在那條線上,所以第三列對載入時間沒有幫助。
換成 10GbE 之後,網路不再是上限,瓶頸往後移了兩段。一是 TS-464 的碟組能不能持續餵出 1 GB/s 的循序讀,四顆硬碟的 RAID 5 速度是夠的。其二是 NFS 的單一連線,沒有開 nconnect 時單一 TCP 連線不一定跑得滿 10GbE。這台機器採用的網路卡 QXG-10G1T 是五速網卡,10、5、2.5、1GbE 都能協商,線材或交換器埠不對時它會安靜地降到 5GbE 或 2.5GbE,連線照樣通,只是載入時間回到上表的第一列附近,所以要看實際協商的速度,不能只看燈號。
這一節的數字是估算,Day 13 會在同一批設備上實測 SSD、NFS、iSCSI 三條路徑的載入時間,估算與實測的差距會回寫到這裡。
DGX Spark 的規格頁寫電源供應器 240 W,GB10 的 TDP 140 W,兩在規格上最大合計 480 W,實際上用不到這麼多電。我在前一個鐵人賽系列文中有寫過,在兩台的牆插上接了電力計,雙機 tensor parallel 滿載時兩台合計 327.77 W,常駐閒置 108.63 W,實測滿載約是銘牌的七成。
TS-464 的規格頁寫的是裝滿硬碟時典型運作 40.5 W、硬碟待機 21.6 W,電源變壓器 90 W。三台 Proxmox VE 節點是 Intel 處理器加 DDR4 記憶體,權衡以 200 W 估算。Intel 搭配 Nvidia 顯示卡的 AI 算力工作站含 RTX 5060 Ti 約 300 W、網路設備約 50 W,同樣是估值。DGX Spark 與 TS-464 取規格上限、其餘取估值,全部約 1,120 W,DGX Spark 改用實測、TS-464 改用典型值,約 920 W。一個 15A 的 110V 迴路是 1,650 W,這個環境設置了雙迴路用電,以及備用的迴路一個,整體夠用,但空調要另算。
電費以外,熱是另一條邊界。前一個系列遇過 GB10 在熱浸透之後跑滿載整台斷電,不留核心日誌,降功耗也避不開,這是 Day 11 熱守護要處理的事。Day 11 的取樣器會記 DGX Spark 的實際功耗與溫度,Day 30 用實際數字算一年電費。
容量規劃的產出是一份文件,這份文件在 Day 26 談變更管理時是變更單的附件,任何新增模型、調整 OLLAMA_MAX_LOADED_MODELS、換 NAS 網卡的變更,均能去對照它。放在索引 repo 的 lab/capacity-plan.md,欄位如下。
| 欄位 | 內容 |
|---|---|
| 版本與日期 | 每次變更遞增 |
| 資料來源 | open-model-selector 的 commit,換版本就要重算 |
| 工作負載清單 | 第一節的表 |
| 常駐模型組合 | 每台節點的模型、量化、OLLAMA_MAX_LOADED_MODELS、OLLAMA_NUM_PARALLEL,以及降級組態 |
| 記憶體預算 | 第二節的表,含 0.85 與 2 GB 兩個係數 |
| 儲存預算 | 第三節的表,含一年成長估計與保留代數 |
| 網路預算 | 第四節的表,含冷啟動的目標時間 |
| 電力預算 | 第五節的銘牌值與實測值,Day 30 全部換成實測值 |
| 已知的未實測項 | NAS 碟組與 NFS 的實際載入速度、NAS 網卡的實際協商速度、Proxmox VE 節點與工作站的實際功耗、團隊的實際 session 數 |
「資料來源」與「已知的未實測項」是這份文件最重要的兩列。今天的第二節就是例子,工具換一個 commit,同一個公式算出相反的結論。每一個估算值旁邊寫清楚它是估的還是量的、依據哪個版本、量的寫在哪一天量的。Day 13 與 Day 30 會各回來填一次。
用工具重算第二節的任何一列。
git clone https://github.com/ivanusto/open-model-selector && cd open-model-selector
git checkout 03f126f
python3 serve.py
在瀏覽器裡到「能跑嗎?」分頁,硬體選 NVIDIA GB10,context 設 32k,模型與量化逐一選,讀所需記憶體。多 session 與多模型的合計工具還沒有,用下面這段算,公式與工具相同,數字取自 data.js 的 sizeGB 與 kvPerTokKB。
python3 - <<'EOF'
# (權重 GB, KV KB/token) 取自 data.js @ 03f126f
models = {"gpt-oss-120b MXFP4": (63.4, 36), "Qwen3.8-27B Q8_0": (29.0, 64)}
ctx, sessions, budget = 32768, 2, 128 * 0.85
total = sum(w + kv * ctx / 1048576 * sessions + 2 for w, kv in models.values())
print(f"total {total:.1f} GB, budget {budget:.1f} GB, headroom {budget - total:.1f} GB")
EOF
# total 102.7 GB, budget 108.8 GB, headroom 6.1 GB
在 NAS 上看目前模型庫的大小與網卡。
du -sh /share/Public/models /share/CACHEDEV1_DATA/OpenWebUIOllama/ollama
for i in /sys/class/net/eth*; do echo "$(basename $i) $(cat $i/speed 2>/dev/null) Mb/s"; done
下指令後第二行會看到一個 10000 Mb/s 的介面,那是 QXG-10G1T。若顯示 5000 或 2500,就是協商降速了,這樣的話,你會需要查線材與交換器埠。而本環境中,AI 算力節點的 NFS 掛載要指向這個介面的位址。
Day 10 先插一個這兩台機器上的真實案例,節點基線移到 Day 11。今天算出來每台節點要常駐什麼、開幾個 session,明天從 DGX OS 的初始設定、帳號與 SSH 加固開始,把兩台機器整成一樣的狀態,之後本系列文章後據的守護與指標收集才有一致的對象可以測試。
系列文章與程式碼索引:onprem-ops-30days
本日程式碼:open-model-selector @ 03f126f
參考資料
OLLAMA_MAX_LOADED_MODELS、OLLAMA_NUM_PARALLEL、OLLAMA_KV_CACHE_TYPE