SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor

Ollama 並行設定:NUM_PARALLEL 與 MAX_QUEUE 怎麼運作

了解 OLLAMA_NUM_PARALLEL 與 OLLAMA_MAX_QUEUE:第二個請求會等待還是收到 HTTP 503,以及每個並行 slot 為何都會增加 KV cache 記憶體。

第一個 Ollama 請求產生回應時,第二個請求會發生什麼事

Ollama 的並行處理由 3 個環境變數決定。預設情況下,一個已載入的模型一次只處理一個請求。第二個請求不會被拒絕,也不會收到不完整的回答。它會在佇列中等待,直到有可用插槽,接著以正常速度執行。

傳入的請求有 3 種可能結果。它可能立即在可用插槽中啟動,也可能在佇列中等待。如果佇列已滿,伺服器則會以 HTTP 503 拒絕請求。實際結果由 OLLAMA_NUM_PARALLEL、OLLAMA_MAX_QUEUE 和 OLLAMA_MAX_LOADED_MODELS 決定。目前版本截至 October 2026 有一項例外。HTTP 503 只適用於模型仍需載入時送達的請求。對於已載入的模型,Ollama 不會拒絕請求。該請求會持續等待可用插槽,等待多久都一樣。

預設設定較為安全。當實際上沒有任何故障時,這也是第二位使用者回報伺服器「卡住」的原因。增加插槽只需修改 2 行設定。真正的限制在於記憶體。每個並行插槽都需要自己的 key/value cache(KV cache)。這是模型用來保存已處理 token 的記憶體區塊。在未增加 VRAM(GPU 上的 video memory)的情況下增加插槽,可能讓原本只是回應較慢變成模型載入失敗。僅使用 CPU 的伺服器則會從 system RAM 分配相同的快取。

OLLAMA_NUM_PARALLEL、OLLAMA_MAX_QUEUE 與 OLLAMA_MAX_LOADED_MODELS 各自控制的項目

以下是截至 2026 年 10 月目前 Ollama 發行版本的預設值。請使用下方顯示的日誌行檢查自己的設定,不要直接採信這裡的數字。

  • OLLAMA_NUM_PARALLEL 表示一個已載入模型可同時處理的請求數。預設值為 1,因此請求會依序處理。
  • OLLAMA_MAX_LOADED_MODELS 表示可同時常駐的不同模型數。預設值為 0,表示由 Ollama 自行選擇:每個 GPU 使用 3 個模型;沒有 GPU 的機器則使用 3 個模型。
  • OLLAMA_MAX_QUEUE 表示可等待排程的請求數。實際上,這通常代表等待模型載入。預設值為 512。佇列已滿時送達的請求會立即遭拒。要求使用已載入模型的請求會略過此佇列,改為等待可用的 slot;這項等待沒有上限。Ollama 維護者已將此問題列為功能請求(issue #7758),截至 2026 年 10 月仍未關閉。

最壞情況下的記憶體使用量,是前兩項的乘積。兩個已載入模型各使用 4 個 slot,表示一次常駐 8 個 KV cache slot 配置;Ollama 會嘗試滿足這項需求。在單一 GPU 的主機上,通常最好只保留一個模型並為其提供多個 slot,因為這樣的計算可以直接在腦中完成。

為什麼每個平行 slot 都會占用 VRAM

Ollama 載入模型時,會啟動個別的 runner process。這裡有兩個重要參數:-c 是 runner 為 KV cache 配置的總 context,-np 是平行序列的數量。Ollama 會將 -c 設為每個請求的 context length 乘以 slot 數量。接著,runner 會把這個總量平均分配給各個 slot,因此每個請求仍會取得你指定的 context length。

這就是完整的限制,也是平行處理並非免費的原因。在每個請求使用相同 context 的情況下,slot 從 1 增加到 4,KV cache 需求會變成 4 倍。各 slot 之間不會共用空間,閒置 slot 的配額也不會借給忙碌的 slot,因為這項分配會在 runner 啟動時固定。在 GPU 上,這項記憶體是 VRAM。在僅使用 CPU 的伺服器上,這項記憶體是系統 RAM,乘法關係相同。

你可以讀取實際數值,而不是查看原本想設定的數值:

journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"

該行包含完整的 runner command line,包括 -c 和 -np。如果你設定變數後 -np 仍為 1,可能有兩個原因。第一個原因是模型本身。無論你設定什麼值,Ollama 都會將部分模型架構限制為 1 個 slot,並在這種情況下記錄 model architecture does not currently support parallel requests。截至 2026 年 10 月,該清單包括 Qwen 3.5、Qwen3-VL、Qwen3-Next、LFM2 和 Nemotron-H 系列;embedding models 則一律使用 1 個 slot。執行 journalctl -u ollama --no-pager | grep "does not currently support parallel" 進行確認。如果沒有這項警告,表示設定沒有傳遞到伺服器,下一節會說明原因。

如果模型權重加上 KV cache 超出 VRAM 容量,Ollama 會將部分 layers 移到系統 RAM,這些 layers 會在 CPU 上執行。CPU layers 的速度遠低於 GPU layers,因此每個請求都會變慢,包括你原本執行的單一請求。提高平行度可能因此降低吞吐量,而不是提高吞吐量。對於大型模型,單是權重就會在進行任何 slot 計算前決定結果。這也是為什麼 自架 Kimi K3 這種規模的模型討論的是你有多少張卡,而不是設定多少個 slot。

ollama ps

如果整個模型都能容納,PROCESSOR 欄會顯示 100% GPU。像 35%/65% CPU/GPU 這樣的分割表示部分模型正在 CPU 上執行。SIZE 欄包括 KV cache,因此提高 slot 數量並重新載入模型後,該欄的數值會增加。提高 OLLAMA_NUM_PARALLEL、重新啟動、傳送一個請求,再次執行 ollama ps:這就是變更的記憶體成本,是實際測量而非推測的結果。如果測量結果顯示模型已無法容納,請記住權重是同一份預算的另一半,而 將模型從 fp16 改為 q8 或 q4 build通常能釋放比新增 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=Environment

systemctl show 會顯示 systemd 傳給程序的內容。如果其中缺少你的變數,表示 drop-in 檔案未儲存,或略過了 daemon-reload。也請從伺服器本身確認:

journalctl -u ollama --no-pager | grep "server config" | tail -1

Ollama 啟動時會在訊息為 server config 的日誌行中記錄完整環境。該對應表會精確顯示伺服器讀取到的內容,是確認變數是否生效最快的方法。它顯示的是你設定的值,不是特定模型實際取得的 slot 數量。若要查看後者,請讀取上方 runner 行中的 -np 值。

已載入的模型會保留啟動時使用的 slot 數量,因為該值會在 runner 程序啟動時固定下來。上述重新啟動會卸載所有內容,因此下一個請求會依新設定重新載入模型,並只支付一次載入時間。模型在此後會在記憶體中保留多久,則由另一項設定控制,詳見 讓 Ollama 模型在請求之間保持載入。

從用戶端觀察已服務、排入佇列與拒絕的請求

同時送出數個請求並測量時間。以下指令會平行執行 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
wait

ttfb是串流收到第一個位元組所需的時間。由於串流的第一個區塊會帶有第一個 token,因此這個時間接近首個 token 時間(TTFT)。

平行服務。 每個請求回報的 ttfb 相近,而所有請求的 total 會一起增加。執行中的工作槽會共用 GPU,因此每個回答都比單獨執行時慢,但每分鐘完成的回答數較多。提高 OLLAMA_NUM_PARALLEL 時,購買的就是這種運作模式。

排入佇列。 前幾個請求會快速回應,後面的請求則會先出現較長的 ttfb,接著以正常速度產生內容。等待時間來自佇列,不是模型。使用者觀看聊天視窗時,會先遇到長時間空白,接著文字以完整速度顯示。這種先慢後快的形狀,是請求排隊而非 GPU 過載的特徵。

拒絕。 用戶端幾乎會立即收到 http=503,而回應本文是:

{"error":"server busy, please try again.  maximum pending requests exceeded"}

這則訊息表示請求抵達時,排程佇列已滿。它與 VRAM 無關,也無法反映模型狀態。在目前的版本中,該佇列只會保留尚未載入模型的請求。如果執行上述迴圈時模型已常駐,無論將 OLLAMA_MAX_QUEUE 設為多低,預期每個請求都會回傳 200。此時溢出會改以較長的 ttfb 呈現。

有一項必須說明的限制:Ollama 不會公布佇列深度。ollama ps 與 /api/ps 端點會回報已載入的模型,不會回報正在等待的請求。因此,您必須從用戶端觀察首個位元組的時間來測量佇列,或統計位於前端的元件所收到的 503 回應數量。

為何較小的 MAX_QUEUE 通常是較好的設定

512 的佇列看似寬裕,但在單一 slot 的情況下幾乎沒有實際作用。第 300 個請求必須排在前面 299 次完整生成之後。這至少需要數分鐘。所有 HTTP client 都會在這之前放棄,因此呼叫端只會看到 client 端逾時。這無法說明原因,也無法讓監控系統針對該問題發出告警。

較小的佇列會將溢位立即轉為 503,但只適用於正在等待模型載入的請求,例如重新啟動後突然湧入的請求,或模型正在切換時的請求。截至 2026 年 10 月,對已載入模型的請求會繞過 OLLAMA_MAX_QUEUE,並無限制地等待可用的 slot。因此,在只有一個常駐模型且伺服器繁忙時,降低佇列大小不會縮短等待時間。若要在這種情況下快速拒絕請求,請在 Ollama 前方限制並行數,如下一節所述。503 很有用:反向代理可以重試,client 可以退避,儀表板可以統計,人員也能直接讀懂。請根據實際測量結果決定上限。如果一次生成約需十秒,而 client 的等待時間為 60 秒,則每個 slot 約可在該時間範圍內處理 6 個請求;允許更多請求等待只會造成逾時。

何時應在 Ollama 前方加入佇列

內建佇列採先進先出(FIFO),不會辨識呼叫端。若只有一個應用程式與一台伺服器互動,這樣就足夠;額外加入基礎架構反而會增加故障點。符合以下任一情況時,才應在前方加入其他元件。

  • 需要優先順序。互動式聊天不應排在批次摘要工作之後等待。Ollama 的佇列沒有優先順序,因此必須在外部暫存批次工作,並以較慢的速度送入。
  • 需要公平性。單一用戶端可能占滿所有處理時段,並自行累積等待中的請求。其他用戶端接著都必須排在該用戶端之後等待;如果其請求需要載入模型,則可能收到 503。
  • 需要設定等待上限。對於已載入的模型,Ollama 會無限期保留請求,因此唯一可靠的限制必須由前方元件設定。
  • 需要讓工作在重新啟動後仍能保留。佇列儲存在伺服器記憶體中。重新啟動 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 的比較適合用來做出這項判斷。不過,不要只因為原則而切換:另一種伺服器需要更多維運工作;如果你的流量只有幾位使用者,內建行為才是正確選擇。如果真正的問題是是否要自行執行 model server,比較僅提供報價的 private AI server 與在租用的 GPU 上建置相同堆疊會逐步說明這項決策,也會涵蓋 API 何時更值得採用。

測量實際吞吐量與首個 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 連線,但在可用插槽釋出前不會傳送任何位元組。從用戶端來看,這與模型速度緩慢的情況相同。判斷方式是觀察時間分布:先長時間暫停,之後文字以全速輸出,表示請求正在佇列中;若從第 1 個 token 開始就持續緩慢輸出,則表示模型速度較慢。使用 systemd drop-in 提高插槽數,然後重新啟動服務。接著查看 runner 行上的 -np 值,因為部分模型架構無論設定為何都只能使用 1 個插槽。

「server busy, please try again. maximum pending requests exceeded」表示什麼?

這是 Ollama 的佇列溢位錯誤,會以 HTTP 狀態碼 503 傳回。等待排程,也就是等待模型載入的請求數量已達 OLLAMA_MAX_QUEUE。該值預設為 512,因此最新請求會遭拒絕,不會加入佇列。對已載入模型發出的請求不會計入這項限制。通常會在啟動期間出現大量請求,或模型正在切換時看到此錯誤。這不是記憶體錯誤,也不是模型錯誤。提高佇列上限只會讓呼叫端等更久,最後仍收到相同的拒絕結果。因此,真正的處理方式是:若 VRAM 足夠,增加插槽數;降低傳入負載;或在前方加入能夠重試並設定優先順序的佇列。

提高 OLLAMA_NUM_PARALLEL 會讓 Ollama 變快嗎?

不會。這會讓更多請求同時執行,但因為它們共用同一個 GPU,每個請求的速度都會比單獨執行時慢。這也會增加 KV cache,因為 Ollama 啟動 runner 時,總 context 會設為 context length 乘以插槽數。如果結果超出 VRAM 容量,Ollama 會將部分 layer 移至 CPU,導致所有請求變慢,包括沒有其他請求競爭的單一請求。變更後檢查 ollama ps,並確認 PROCESSOR 欄仍顯示 100% GPU。

變更這些變數後,需要重新啟動 Ollama 嗎?

需要。伺服器會在啟動時讀取這些變數,而執行中的模型會沿用啟動 runner process 時固定的插槽數。使用 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 行;該行會列出伺服器實際載入的環境變數。

應設定多少個平行插槽?

先從 1 開始,每次增加 1 個插槽。每次變更後重新啟動 Ollama,傳送 1 個請求以載入模型,然後執行 ollama ps。停在 PROCESSOR 仍顯示 100% GPU,且 SIZE 欄對所提供的最長 context 仍保有餘裕的最後一個值。接著在實際並行量下,測量該設定的首次 token 時間與每秒 token 數。如果每個請求的速度低於使用者可接受的程度,則退回前一個值。

#ollama#concurrency#vram#queueing#self-hosted-llm