Ollamaの同時実行設定 NUM_PARALLELとMAX_QUEUE
Ollamaの2つ目のリクエストは待機するかHTTP 503で拒否されます。OLLAMA_NUM_PARALLELとOLLAMA_MAX_QUEUEの違い、並列スロットごとに必要なVRAMとKV cacheの関係を解説します。
最初の生成中に2つ目のOllamaリクエストはどうなるか
Ollamaの同時実行は3つの環境変数で決まり、初期状態では、読み込まれた1つのモデルが一度に1つのリクエストだけを処理します。2つ目のリクエストは拒否されず、不完全な回答が返ることもありません。空きスロットができるまでキューで待機し、その後、通常の速度で処理されます。
受信したリクエストの処理結果は3通りあります。空きスロットがあれば直ちに開始します。空きがなければキューで待機します。キューも満杯なら、サーバーはHTTP 503で拒否します。どの結果になるかは、OLLAMA_NUM_PARALLEL、OLLAMA_MAX_QUEUE、OLLAMA_MAX_LOADED_MODELSで決まります。
デフォルト設定は安全です。ただし、何も問題がないのに2人目のユーザーがサーバーが「ハングした」と報告する原因にもなります。スロットの追加は2行を変更するだけです。問題になるのはメモリです。並列スロットごとに専用のkey/valueキャッシュ(KV cache)が必要です。これは、モデルが処理済みのトークンを保持するメモリ領域です。VRAM(GPU上のビデオメモリ)を増やさずにスロットだけ増やすと、回答が遅くなるだけでなく、モデルの読み込みに失敗します。
OLLAMA_NUM_PARALLEL、OLLAMA_MAX_QUEUE、OLLAMA_MAX_LOADED_MODELSが制御する内容
以下は、2026年8月時点の現在のOllamaリリースにおけるデフォルト値です。下に示すログ行を使って、自分の環境の値を確認してください。
OLLAMA_NUM_PARALLELは、1つの読み込み済みモデルが同時に処理できるリクエスト数です。デフォルトは1で、リクエストは1件ずつ処理されます。OLLAMA_MAX_LOADED_MODELSは、同時にメモリ上へ常駐できる異なるモデルの数です。デフォルトは0です。この場合、Ollamaが値を選択します。GPUごとに3モデル、GPUのないマシンでは3モデルです。OLLAMA_MAX_QUEUEは、待機キューに入れておけるリクエスト数です。デフォルトは512です。キューが満杯の状態で到着したリクエストは、直ちに拒否されます。
最悪時のメモリ使用量は、最初の2つの値の積になります。4スロットずつ使用する読み込み済みモデルが2つある場合、KV cacheのスロット割り当ては合計8個になり、すべてが同時に常駐します。Ollamaはこの状態を満たそうとします。単一GPUのマシンでは、通常、1つのモデルを保持してスロットを割り当てるほうが適しています。計算量が暗算できる範囲に収まるためです。
並列スロットごとにVRAMが必要になる理由
Ollamaがモデルを読み込むと、個別のrunnerプロセスを起動します。ここで重要なのは、渡される2つの引数です。-cはrunnerがKV cache用に確保するコンテキスト全体で、-npは並列シーケンス数です。Ollamaは-cを、リクエストごとのコンテキスト長にスロット数を掛けた値に設定します。runnerはその合計値をスロット間で均等に分割するため、各リクエストには指定したコンテキスト長が割り当てられます。
これが制約のすべてであり、並列化が無料ではない理由です。リクエストごとのコンテキスト長を変えずにスロット数を1から4にすると、KV cacheには4倍の容量が必要になります。スロット間で共有される容量はなく、アイドル状態のスロットの割り当てを使用中のスロットへ貸し出すこともできません。分割はrunnerの起動時に固定されるためです。
設定したつもりの値ではなく、実際の値を確認できます。
journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"この行には、-cと-npを含むrunnerの完全なコマンドラインが表示されます。変数を設定した後も-npが1なら、その設定はserverに渡っていません。次のセクションでその理由を説明します。
モデルの重みとKV cacheの合計がVRAMに収まらない場合、Ollamaは一部のレイヤーをsystem RAMへ移し、それらをCPUで実行します。CPU上のレイヤーはGPU上のレイヤーより大幅に遅いため、最初に開始した単一リクエストも含め、すべてのリクエストが遅くなります。そのため、並列性を上げるとスループットが向上せず、低下する場合があります。
ollama psPROCESSOR列が100% GPUと表示される場合は、全体がVRAMに収まっています。35%/65% CPU/GPUのような分割表示は、モデルの一部がCPU上で実行されていることを示します。SIZE列にはKV cacheが含まれるため、スロット数を増やしてモデルを再読み込みすると値も増加します。OLLAMA_NUM_PARALLELを増やして再起動し、1件のリクエストを送信した後、もう一度ollama psを実行してください。変更によるメモリ使用量を推測ではなく実測できます。
コンテキスト長とスロット数は掛け合わされるため、同時に決める必要があります。4スロットで大きなコンテキストを設定すると、大きなコンテキストが4つ必要になります。モデルのnum_ctxコンテキストウィンドウも調整している場合は、2つの設定を一度に1つだけ変更してください。そうしないと、どちらがGPUメモリを使い切ったのか判断できません。
これらの変数を再起動後も維持する方法
Linux では、Ollama は systemd サービスとして実行されます。シェルで export OLLAMA_NUM_PARALLEL=4 を実行しても何も変わりません。systemd は独自の環境でサービスを起動するため、シェルの環境を認識しないからです。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 プロセスへ固定されるためです。上記の再起動ですべてがアンロードされるため、次のリクエストでは新しい設定でモデルが再ロードされ、ロード時間が1回発生します。その後、モデルが常駐する時間を制御する設定は別にあり、リクエスト間で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
waitttfb はストリームの最初のバイトを受信するまでの時間です。最初のストリームチャンクに最初のトークンが含まれるため、最初のトークンまでの時間(TTFT)に近い値になります。
並列処理。 すべてのリクエストで ttfb が同程度になり、total も同時に増加します。実行中のスロット間で GPU を共有するため、単独で実行する場合より各応答は遅くなりますが、1 分あたりに完了する応答数は増えます。OLLAMA_NUM_PARALLEL を増やしたときに得られるのは、この状態です。
キュー待ち。 最初のリクエストはすぐに応答し、後続のリクエストでは大きな ttfb の後に通常の生成が始まります。この待ち時間はモデルによるものではなく、キューによるものです。チャット画面を見ているユーザーには、長い無表示時間の後、通常の速度でテキストが表示されます。開始は遅いものの、その後は速いという形状は、過負荷の GPU ではなくキューが存在することを示します。
拒否。 クライアントはほぼ即座に http=503 を受け取り、本文は次のようになります。
{"error":"server busy, please try again. maximum pending requests exceeded"}このメッセージは、リクエストの到着時点でキューが満杯だったことを示します。VRAM の容量やモデルの状態を示すものではありません。
明確な制限が 1 つあります。Ollama はキューの深さを公開していません。ollama ps と /api/ps エンドポイントが報告するのはロード済みのモデルであり、待機中のリクエストではありません。そのため、クライアント側で最初のバイトを受信するまでの時間を監視してキューを測定するか、前段にあるコンポーネントで 503 応答を数えます。
小さい MAX_QUEUE が適切な設定になりやすい理由
512 のキューは十分な大きさに見えますが、スロットが 1 つしかない場合は、ほとんど役に立ちません。リクエスト 300 は、完了までに 299 回の生成処理を待つことになります。最短でも数分かかります。すべての HTTP クライアントは、それよりはるか前に諦めます。そのため、呼び出し元にはクライアント側のタイムアウトだけが表示され、原因は分かりません。監視もアラートを発報できません。
キューは、クライアントのタイムアウト時間内にサーバーが処理できる量を目安に設定してください。上限を超えたリクエストは、代わりに即時に 503 になります。503 は有用です。リバースプロキシは再試行でき、クライアントはバックオフでき、ダッシュボードは件数を集計でき、人間も内容を確認できます。値は、自分の環境で測定した結果から決めてください。1 回の生成に約 10 秒かかり、クライアントの待機時間が 60 秒なら、その時間内に 1 スロットあたり約 6 リクエストを処理できます。それより大幅に深いキューを設定しても、タイムアウトが増えるだけです。
Ollama の前段にキューを置くタイミング
組み込みキューは先入れ先出し(FIFO)で、呼び出し元を区別しません。1 台のサーバーと 1 つのアプリケーション間で通信するだけなら、これで十分です。インフラを追加すると、障害要因が増えるだけです。次のいずれかに該当する場合は、前段の仕組みを検討します。
- 優先度が必要な場合。対話型チャットがバッチ要約ジョブの後ろで待たされないようにします。Ollama のキューには優先度がないため、バッチ処理を外部で保留し、少しずつ投入する必要があります。
- 公平性が必要な場合。1 つのクライアントだけでキューを埋められるため、他のクライアントが 503 を受ける可能性があります。
- 再起動後も処理を維持する必要がある場合。キューはサーバーのメモリ上にあります。Ollama を再起動すると、待機中のリクエストはすべて失われます。
- バックオフ付きの本格的なリトライが必要で、後から確認できる場所に記録したい場合。
軽量な構成はリバースプロキシです。nginx では、limit_conn で同時接続数を制限し、limit_req でクライアントごとの到着レートを制限できます。そのため、上限を超えたリクエストはプロキシで拒否され、Ollama のキューには到達しません。より大規模な構成では、データベースを前段に置いたジョブキューと、Ollama を呼び出すワーカーを使います。リクエストをプロセスの再起動後も保持する必要がある場合は、この構成が適しています。実際のトラフィックに合わせたサイズ設計は別途必要です。同時利用ユーザー向けの self hosted LLM の計画では計算方法を説明し、VPS 上で Ollama を実行するでは、これらの変数が前提とする基本インストールを扱います。
正直に言えば、別のサーバーが必要な場合
調整だけでは超えられない制限があります。Ollama はモデルの読み込み時に、KV cache を固定サイズの同じスロットへ分割します。アイドル状態のスロットのメモリを、処理中のスロットで使用することはできません。また、モデルをアンロードしない限り、スロット数も変更できません。この設計は、1 人の利用者、少人数のチーム、またはコーディングエージェントに適しています。
多数のユーザーが同時に利用するために設計されたサーバーは、動作が異なります。必要に応じて KV cache を小さなページ単位で割り当て、到着したリクエストを実行中のバッチに追加します。そのため、メモリは固定分割ではなく、実際の需要に応じて使用されます。1 台の GPU で多数のユーザーを同時に処理することが目的なら、このアーキテクチャの違いは OLLAMA_NUM_PARALLEL の値よりも重要です。Ollama と vLLM の比較で、その判断を行います。ただし、原則だけで切り替えてはいけません。別のサーバーは運用負荷が高く、利用者が数人程度であれば、組み込みの動作が適切な選択です。
自分のスループットと最初のトークンまでの時間を測定する
公開されている tokens per second の値は、別の GPU、モデル、量子化設定、コンテキスト長、プロンプトで測定されたものです。これらは使用環境と一致しないため、読んだ数値は大まかな目安として扱い、実際に使用するマシンで測定してください。
Ollama は、すべてのレスポンスの最後の JSON オブジェクトにタイミング情報を返します。eval_count は生成されたトークン数、eval_duration はその生成にかかった時間をナノ秒で示します。
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))}'まず 1 スロットで実行し、次に実際に想定する concurrency で実行して、ユーザーの満足度を左右する 2 つの値を比較します。最初のトークンまでの時間と、リクエストごとの tokens per second です。スロットを追加すると、リクエストごとのスループットは必ず低下します。重要なのは、ユーザーが許容できる範囲を超えて低下するかどうかです。ローカル LLM で tokens per second を測定するでは、実行間でプロンプトを一定に保つ方法を含め、この測定方法を詳しく説明しています。
寛大なキューを持つ公開エンドポイントは DoS 攻撃の標的になります
OLLAMA_HOST=0.0.0.0:11434 を設定すると、API はすべてのインターフェースで待ち受けます。Ollama には組み込みの認証機能がありません。デフォルトのキューを使用する公開エンドポイントは、見つけたユーザーからの待機リクエストを 512 件まで受け付けます。攻撃者は、長いプロンプトを送信するだけで、ほとんどコストをかけずにそのキューを埋められます。ログインも、レート制限も、課金も必要ありません。その間、正規のユーザーには 503 応答が返るか、長い待ち時間が発生し、マシンは継続的に負荷がかかった状態になります。
リスナーは loopback に限定し、SSH トンネルまたはプライベートネットワーク経由で接続してください。または、手前に認証とレート制限を配置してください。Ollama API エンドポイントのセキュリティ確保では、両方の方法を説明しています。その後でキューを調整してください。キューの長さは容量の設定であり、セキュリティ対策にはならないためです。
FAQ
2 回目の Ollama リクエストは、なぜ 1 回目が終わるまで待機するのですか?
OLLAMA_NUM_PARALLEL のデフォルト値が 1 だからです。読み込み済みのモデルは一度に 1 件のリクエストだけを処理し、残りは順番に待機します。待機中のリクエストは HTTP 接続を開いたまま保持し、スロットが空くまでバイトを送信しません。そのため、クライアント側からはモデルの処理が遅い場合と同じように見えます。判別のポイントは時間経過の形です。長い停止の後に最大速度でテキストが届くならキューです。最初のトークンから少しずつ届くなら、モデルの処理が遅い状態です。systemd の drop-in でスロット数を増やし、サービスを再起動してください。
「server busy, please try again. maximum pending requests exceeded」は何を意味しますか?
これは Ollama のキューあふれエラーで、HTTP ステータス 503 とともに返されます。待機中のリクエスト数が OLLAMA_MAX_QUEUE に達しました。デフォルト値は 512 です。そのため、新しいリクエストはキューに追加されず拒否されました。メモリエラーでもモデルエラーでもありません。キューを増やすだけでは、同じ拒否が発生するまでの待ち時間が長くなるだけです。実際の対策は、VRAM に余裕がある場合はスロットを増やすこと、受信負荷を下げること、または手前にキューを置いて再試行と優先順位付けを行うことです。
OLLAMA_NUM_PARALLEL を増やすと Ollama は高速になりますか?
いいえ。同時に実行できるリクエスト数は増えますが、1 件ずつ実行する場合より各リクエストの処理は遅くなります。同じ GPU を共有するためです。また、Ollama はコンテキスト長にスロット数を掛けた合計コンテキストで runner を起動するため、KV cache も増加します。その結果が VRAM に収まらなくなると、Ollama は一部のレイヤーを CPU に移します。競合のない単一リクエストも含め、すべてのリクエストが遅くなります。変更後に ollama ps を確認し、PROCESSOR 列が引き続き 100% GPU と表示されることを確認してください。
これらの変数を変更した後、Ollama を再起動する必要はありますか?
はい。サーバーは起動時に変数を読み込みます。また、実行中のモデルは、起動時に runner プロセスへ設定されたスロット数を使い続けます。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 列にも提供する最長コンテキスト分の余裕が残る最後の値で止めてください。その設定で、実際の同時実行数における最初のトークンまでの時間と 1 秒あたりのトークン数を測定します。リクエスト単位の速度が利用者の許容範囲を下回る場合は、1 段階戻してください。