Ollama 並行設定:NUM_PARALLEL 與 MAX_QUEUE
Ollama 第二個請求會等待還是收到 HTTP 503?了解 OLLAMA_NUM_PARALLEL、OLLAMA_MAX_QUEUE 如何決定佇列與拒絕,以及每個平行 slot 為何都會增加 VRAM 用量。
第一個 Ollama 請求產生內容時,第二個請求會發生什麼事
Ollama 的並行處理由 3 個環境變數決定。根據預設,1 個已載入的模型一次只處理 1 個請求。第二個請求不會被拒絕,也不會收到不完整的回答。它會在佇列中等待,直到有可用的處理槽位,然後以正常速度執行。
傳入的請求有 3 種可能結果。它可能立即在空閒槽位中啟動,也可能在佇列中等待。如果佇列已滿,伺服器會以 HTTP 503 拒絕請求。實際結果由 OLLAMA_NUM_PARALLEL、OLLAMA_MAX_QUEUE 和 OLLAMA_MAX_LOADED_MODELS 決定。
預設設定較為安全。當系統沒有任何故障時,這也是第二位使用者回報伺服器「卡住」的原因。增加槽位只需修改 2 行設定。真正需要注意的是記憶體。每個平行槽位都需要自己的 key/value cache(KV cache)。這是模型用來保存已處理 token 的記憶體區塊。如果增加槽位卻沒有增加 VRAM(GPU 上的視訊記憶體),原本只是速度較慢的回答就可能變成載入失敗。
OLLAMA_NUM_PARALLEL、OLLAMA_MAX_LOADED_MODELS 與 OLLAMA_MAX_QUEUE 各自控制的項目
以下是截至 August 2026 的 Ollama 版本預設值。請使用下方顯示的日誌行檢查自己的設定,不要直接套用這裡的數值。
OLLAMA_NUM_PARALLEL指單一已載入模型同時處理的請求數。預設值為 1,因此請求會依序處理。OLLAMA_MAX_LOADED_MODELS指同時常駐的不同模型數量。預設值為 0,表示由 Ollama 自行選擇:每個 GPU 3 個模型;沒有 GPU 的機器則為 3 個模型。OLLAMA_MAX_QUEUE指可在佇列中等待的請求數量。預設值為 512。佇列已滿時抵達的請求會立即遭到拒絕。
最壞情況下的記憶體用量,是前兩項的乘積。若載入 2 個模型,且每個模型各有 4 個工作槽,就會同時常駐 8 個 KV cache 配置;Ollama 會嘗試滿足這項需求。在單一 GPU 的主機上,通常最好只常駐 1 個模型,再為它配置多個工作槽,因為這樣的計算可以直接心算。
為什麼每個平行 slot 都會占用 VRAM
Ollama 載入模型時,會啟動個別的 runner process。這裡有兩個傳入的引數很重要:-c 是 runner 為 KV cache 配置的完整 context,-np 則是平行序列的數量。Ollama 會將每個請求的 context length 乘以 slot 數量,並把結果設定給 -c。接著,runner 會將這個總量平均分配給各個 slot,因此每個請求仍會取得你指定的 context length。
這就是完整的限制,也是平行處理並非免費的原因。在每個請求的 context 維持不變時,slot 從 1 增加到 4,KV cache 的需求就會變成 4 倍。各個 slot 之間不會共用記憶體,閒置 slot 所占用的部分也不會借給忙碌中的 slot,因為這項分配在 runner 啟動時就已固定。
你可以讀取實際數值,而不是查看原本打算設定的數值:
journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"該行包含完整的 runner command line,其中包括 -c 與 -np。如果你設定變數後,-np 顯示為 1,表示這項設定沒有傳到伺服器;下一節會說明原因。
如果模型權重加上 KV cache 後超出 VRAM,Ollama 會將部分 layer 移到 system RAM,並由 CPU 執行這些 layer。CPU layer 的速度遠低於 GPU layer,因此所有請求都會變慢,包括你原本只啟動的單一請求。提高平行度可能因此降低 throughput,而不是提高 throughput。對於足夠大的模型,光是權重就會在進行 slot 計算前決定結果;因此,自架 Kimi K3 這類規模的模型討論的是你有多少張顯示卡,而不是設定多少個 slot。
ollama psPROCESSOR 欄位在整個模型都能載入時會顯示 100% GPU。像 35%/65% CPU/GPU 這樣的分配表示模型有一部分正在 CPU 上執行。SIZE 欄位包含 KV cache,因此提高 slot 數量並重新載入模型後,該欄位會增加。提高 OLLAMA_NUM_PARALLEL、重新啟動、傳送一個請求,再次執行 ollama ps:這就是這項變更的記憶體成本,是實際測量值,不是估算值。如果測量結果表示模型已無法完整載入,請記住權重也是同一份記憶體預算的另一半;將 fp16 改為 q8 或 q4 build通常能釋放更多 VRAM,超過你為增加 slot 所需的 VRAM。
Context length 與 slot 數量會相乘,因此必須一併選擇。4 個 slot 搭配大型 context,就等於 4 個大型 context。如果你也在調整模型的 num_ctx context window,請一次只變更其中一項,否則你將無法判斷是哪一項填滿了顯示卡。
如何設定這些變數,讓它們在重新開機後仍然保留
在 Linux 上,Ollama 會以 systemd 服務執行。在 shell 中執行 export OLLAMA_NUM_PARALLEL=4 不會產生任何作用,因為 systemd 會使用自己的環境啟動服務,不會取得您的 shell 環境。請使用 drop-in 檔案。
sudo systemctl edit ollama.service在開啟的編輯器中加入以下內容:
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MAX_QUEUE=32"接著重新載入並重新啟動服務:
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environmentsystemctl show 會顯示 systemd 傳給程序的內容。如果其中缺少您的變數,表示 drop-in 檔案未儲存,或略過了 daemon-reload。也請從伺服器本身確認:
journalctl -u ollama --no-pager | grep "server config" | tail -1Ollama 啟動時會在訊息為 server config 的日誌行中記錄完整環境。該映射就是實際結果。若要確認變數是否生效,這是最快的方法。
已載入的模型會保留啟動時設定的工作槽數,因為該值會在 runner 程序啟動時固定。上述重新啟動操作會卸載所有模型,因此下一個請求會以新設定重新載入模型,並只支付一次載入時間。模型之後會在記憶體中保留多久,則由另一項設定控制,詳見讓 Ollama 模型在請求之間保持載入。
從用戶端觀察 served、queued 與 refused
同時送出多個請求並測量時間。以下指令會平行執行 8 個串流請求,並列出每個請求的狀態與耗時:
for i in $(seq 1 8); do
curl -s -o /dev/null \
-w "req$i http=%{http_code} ttfb=%{time_starttransfer}s total=%{time_total}s\n" \
http://127.0.0.1:11434/api/generate \
-d '{"model":"llama3.2:3b","prompt":"Explain what a KV cache is.","stream":true}' &
done
waitttfb 是串流的第一個位元組到達時間。由於第一個串流區塊會帶有第一個 token,因此這個時間接近第一個 token 到達時間(TTFT)。
平行 served。 每個請求回報的 ttfb 相近,且所有請求的 total 會同時增加。GPU 會在執行中的工作槽之間共用,因此每個回答都比單獨執行時慢,但每分鐘完成的回答數會增加。提高 OLLAMA_NUM_PARALLEL 時,購買的就是這種執行模式。
Queued。 前面的請求很快收到回答,後面的請求則會先出現較大的 ttfb,之後以正常速度生成。等待時間來自佇列,不是模型。使用者查看聊天視窗時,會先長時間看不到內容,接著文字以完整速度出現。這種先慢後快的形狀,是佇列造成的特徵,不是 GPU 過載。
Refused。 用戶端幾乎立即收到 http=503,內容如下:
{"error":"server busy, please try again. maximum pending requests exceeded"}這則訊息表示請求抵達時佇列已滿。它無法說明 VRAM 的狀態,也無法說明模型的狀態。
必須注意一項限制:Ollama 不會公開佇列深度。ollama ps 與 /api/ps endpoint 會回報已載入的模型,而不是正在等待的請求。因此,您必須從用戶端觀察第一個位元組到達時間來測量佇列,或計算前端元件收到的 503 回應數。
為何較小的 MAX_QUEUE 通常是更好的設定
512 的佇列看似寬裕,但在單一 slot 上幾乎沒有作用。第 300 個請求必須排在前 299 個完整生成作業之後。這至少需要數分鐘。所有 HTTP client 早在那之前就會放棄,因此呼叫端只會看到 client 端逾時。這項資訊無法說明原因,也無法讓監控系統針對問題發出警示。
將佇列設定為伺服器能在 client 逾時前處理完的數量,溢出的請求就會立即收到 503。503 很有用:反向代理可以重試,client 可以退避,儀表板可以統計,人員也能直接讀懂。請根據自己的測量結果計算數值。如果一次生成約需 10 秒,而 client 的等待時間為 60 秒,則每個 slot 約可在這段時間內處理 6 個請求。佇列深度若遠大於此數值,只會產生逾時。
何時應在 Ollama 前方加入佇列
內建佇列採先進先出(FIFO),而且不知道請求來源。對於一個應用程式連線到一台伺服器的情況,這已經足夠;加入額外基礎架構只會增加失效模式。符合以下任一情況時,才需要在前方加入其他元件。
- 需要優先順序。互動式聊天不應排在批次摘要工作之後等待。Ollama 的佇列沒有優先順序,因此必須在佇列外暫存批次工作,再逐步送入。
- 需要公平性。單一用戶端可能獨占整個佇列,導致其他用戶端收到 503。
- 需要讓工作在重新啟動後仍然存在。佇列儲存在伺服器記憶體中。重新啟動 Ollama 後,所有等待中的請求都會消失。
- 需要具備退避機制的實際重試,並將記錄儲存在之後可供檢查的位置。
較簡單的做法是使用反向代理。在 nginx 中,limit_conn 可限制同時連線數,limit_req 可限制每個用戶端的抵達速率,因此超出限制的請求會在代理層遭拒絕,不會進入 Ollama 的佇列。較完整的做法是在工作程序前方使用搭配資料庫的工作佇列,由工作程序呼叫 Ollama。當請求必須在程序重新啟動後仍然存在時,就應採用這種架構。依據實際流量進行容量規劃是另一項工作:規劃可供並行使用者使用的自架 LLM 說明相關計算方式,而 在 VPS 上執行 Ollama 涵蓋這些變數所需的基礎安裝。
當誠實的答案是改用其他伺服器
有一項限制無法靠調整設定來突破。Ollama 在模型載入時,會將 KV cache 分割成大小相同且固定的 slot。閒置 slot 的記憶體無法供忙碌的 slot 使用,而 slot 數量也不能在不卸載模型的情況下變更。這種設計適合單一使用者、小型團隊或 coding agent。
為許多同時使用者打造的伺服器採用不同方式。它們會依需求以小型頁面配置 KV cache,並將新到的請求加入已在執行的 batch,讓記憶體使用量依實際需求變化,而不是固定分割。如果目標是在單一 GPU 上服務大量並行使用者,這項架構差異比 OLLAMA_NUM_PARALLEL 的任何數值都更重要。Ollama 與 vLLM 的比較是判斷這件事的依據。不過,不要只因原則而切換:不同的伺服器需要更多維運工作;如果流量只有幾位使用者,內建行為才是正確選擇。
測量實際吞吐量與首個 token 的產生時間
已發布的每秒 token 數據來自他人的 GPU、模型、量化設定、上下文長度與提示。這些條件都不符合你的環境,因此任何讀到的數值都只能作為粗略參考,應直接測量目前使用的機器。
Ollama 會在每次回應最後的 JSON 物件中回傳計時資訊。eval_count 是產生的 token 數量,eval_duration 是產生這些 token 所耗用的時間,單位為奈秒。
sudo apt install -y jq
curl -s http://127.0.0.1:11434/api/generate \
-d '{"model":"llama3.2:3b","prompt":"Explain what a KV cache is.","stream":false}' \
| jq '{prompt_eval_count, eval_count, eval_duration, tokens_per_second: (.eval_count / (.eval_duration / 1000000000))}'先以一個 slot 執行,再以實際預期的並行數執行,然後比較兩個會影響使用者體驗的數值:首個 token 的產生時間,以及每個請求每秒產生的 token 數。加入更多 slot 後,單一請求的吞吐量一定會下降。問題在於,下降幅度是否超出使用者可接受的範圍。測量本機 LLM 的每秒 token 數會更詳細說明這項方法,包括如何在不同執行間維持提示不變。
公開端點搭配寬鬆佇列,容易成為阻斷服務攻擊目標
設定 OLLAMA_HOST=0.0.0.0:11434 會讓 API 監聽所有介面,而 Ollama 沒有內建驗證機制。使用預設佇列的開放端點,任何找到它的人都能提交 512 個等待中的請求。攻擊者幾乎不需成本就能填滿佇列:提交冗長提示、無須登入、沒有速率限制,也不會產生費用。接著,您自己的使用者會收到 503 回應或長時間等待,而機器也會持續忙碌。
讓監聽器維持在 loopback,透過 SSH tunnel 或私有網路存取;或者在端點前方加入驗證與速率限制。保護 Ollama API 端點涵蓋這兩種方式。完成上述設定後,再調整佇列,因為佇列長度是容量設定,無法提供任何防護。
FAQ
為什麼我發出的第 2 個 Ollama 請求,必須等第 1 個請求完成?
因為 OLLAMA_NUM_PARALLEL 預設為 1。載入的模型一次只處理 1 個請求,其餘請求會依序等待。等待中的請求會維持 HTTP 連線開啟,但在有可用的 slot 前不會傳送任何位元組,因此從用戶端看起來,與模型速度緩慢完全相同。判斷方式在於計時特徵:長時間暫停後突然以完整速度輸出文字,表示請求正在佇列中;而第 1 個 token 開始就持續緩慢輸出,則表示模型本身速度較慢。使用 systemd drop-in 提高 slot 數量,然後重新啟動服務。
「server busy, please try again. maximum pending requests exceeded」是什麼意思?
這是 Ollama 的佇列溢位錯誤,會以 HTTP status 503 回傳。當時已在等待的請求數量達到 OLLAMA_MAX_QUEUE;該值預設為 512,因此最新請求會遭拒絕,不會加入佇列。這不是記憶體錯誤,也不是模型錯誤。提高佇列大小只會讓呼叫端等待更久,最後仍收到相同的拒絕結果。真正的處理方式是:在 VRAM 足夠時增加 slot 數量、降低傳入負載,或在前方加入可重試並能進行優先排序的佇列。
提高 OLLAMA_NUM_PARALLEL 會讓 Ollama 變快嗎?
不會。它會讓更多請求同時執行,但每個請求的速度都會比單獨執行時慢,因為這些請求會共用同一個 GPU。它也會增加 KV cache 的用量,因為 Ollama 啟動 runner 時,會將總 context 設為 context length 乘以 slot 數量。如果結果超出 VRAM 容量,Ollama 會將部分 layers 移至 CPU,導致所有請求變慢,包括沒有其他請求競爭資源的單一請求。變更後檢查 ollama ps,確認 PROCESSOR 欄仍顯示 100% GPU。
變更這些變數後,需要重新啟動 Ollama 嗎?
需要。伺服器會在啟動時讀取這些變數,而執行中的模型會沿用 runner process 啟動時固定的 slot 數量。使用 sudo systemctl edit ollama.service 編輯 drop-in,接著執行 sudo systemctl daemon-reload 和 sudo systemctl restart ollama。使用 systemctl show ollama --property=Environment 確認,然後檢查 journalctl -u ollama 中的 server config 行;該行會列出伺服器實際載入的環境。
應設定多少個 parallel slot?
先從 1 開始,每次提高 1 個。每次提高後,重新啟動 Ollama,傳送 1 個請求以載入模型,然後執行 ollama ps。當 PROCESSOR 仍顯示 100% GPU,且 SIZE 欄對所提供的最長 context 仍保有餘裕時,停止在最後一個符合條件的數值。接著在實際並行量下,測量該設定的首個 token 時間與每秒 token 數。如果每個請求的速度低於使用者可接受的程度,則回退 1 個步驟。