Ollama: NUM_PARALLEL e MAX_QUEUE spiegati
La seconda richiesta attende o riceve HTTP 503? Scopri come OLLAMA_NUM_PARALLEL e OLLAMA_MAX_QUEUE gestiscono la coda e perché ogni slot usa VRAM.
Cosa accade alla seconda richiesta a Ollama mentre viene generata la prima
La concorrenza di Ollama è determinata da tre variabili d'ambiente e, nella configurazione predefinita, un modello caricato gestisce una richiesta alla volta. La seconda richiesta non viene rifiutata e non riceve una risposta parziale. Rimane in coda finché non si libera uno slot, quindi viene elaborata alla velocità normale.
Una richiesta in arrivo può avere tre esiti. Può iniziare subito in uno slot libero. Può rimanere in coda. Oppure, se la coda è già piena, il server può rifiutarla con HTTP 503. L'esito dipende da OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE e OLLAMA_MAX_LOADED_MODELS.
La configurazione predefinita è prudente. Per questo, quando non c'è alcun problema, un secondo utente può segnalare che il server si è "bloccato". Aggiungere slot richiede due righe di configurazione. Il limite principale è la memoria. Ogni slot parallelo richiede una propria cache di chiavi/valori (KV cache), cioè l'area di memoria in cui il modello conserva i token già elaborati. Se si aggiungono slot senza aumentare la VRAM (memoria video della GPU), una risposta lenta può trasformarsi in un caricamento non riuscito.
Che cosa controllano OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE e OLLAMA_MAX_LOADED_MODELS
Questi sono i valori predefiniti nelle versioni attuali di Ollama ad agosto 2026. Controlla i valori del tuo sistema invece di fare affidamento su quelli riportati qui, usando la riga del log mostrata più avanti.
OLLAMA_NUM_PARALLELindica quante richieste può gestire contemporaneamente un modello caricato. Il valore predefinito è 1, quindi le richieste vengono servite una alla volta.OLLAMA_MAX_LOADED_MODELSindica quanti modelli diversi rimangono residenti contemporaneamente. Il valore predefinito è 0: Ollama sceglie automaticamente tre modelli per GPU e tre modelli su una macchina senza GPU.OLLAMA_MAX_QUEUEindica quante richieste possono rimanere in attesa. Il valore predefinito è 512. La richiesta che arriva quando la coda è piena viene rifiutata immediatamente.
La memoria massima richiesta è il prodotto dei primi due valori. Due modelli caricati con quattro slot ciascuno richiedono otto allocazioni di slot per la KV cache, tutte residenti contemporaneamente, e Ollama proverà a soddisfare questa richiesta. Su una macchina con una sola GPU, di solito è preferibile mantenere un solo modello caricato e assegnargli più slot, perché il calcolo resta semplice.
Perché ogni slot parallelo consuma VRAM
Quando Ollama carica un modello, avvia un processo runner separato. In questo caso sono importanti due argomenti: -c indica il contesto totale per cui il runner alloca una cache KV, mentre -np indica il numero di sequenze parallele. Ollama imposta -c moltiplicando la lunghezza del contesto per richiesta per il numero di slot. Il runner divide quindi questo totale in parti uguali tra gli slot, così ogni richiesta riceve comunque la lunghezza del contesto specificata.
Questo è l'intero vincolo e spiega perché il parallelismo non è gratuito. Passare da uno slot a quattro richiede una cache KV quattro volte più grande, a parità di contesto per richiesta. Gli slot non condividono nulla e la quota di uno slot inattivo non viene assegnata a uno slot occupato, perché la suddivisione viene fissata all'avvio del runner.
Puoi leggere i valori effettivi invece di quelli che intendevi impostare:
journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"Quella riga contiene l'intera riga di comando del runner, inclusi -c e -np. Se -np è 1 dopo aver impostato la variabile, l'impostazione non raggiunge il server. La sezione successiva spiega il motivo.
Se i pesi del modello e la cache KV non rientrano nella VRAM, Ollama sposta alcuni layer nella RAM di sistema e questi vengono eseguiti dalla CPU. I layer eseguiti dalla CPU sono molto più lenti di quelli eseguiti dalla GPU, quindi ogni richiesta diventa più lenta, inclusa la singola richiesta con cui hai iniziato. Aumentare il parallelismo può quindi ridurre il throughput invece di aumentarlo.
ollama psLa colonna PROCESSOR mostra 100% GPU quando l'intero modello rientra nella memoria disponibile. Un valore suddiviso come 35%/65% CPU/GPU indica che una parte del modello viene eseguita dalla CPU. La colonna SIZE include la cache KV, quindi aumenta quando incrementi il numero di slot e ricarichi il modello. Aumenta OLLAMA_NUM_PARALLEL, riavvia, invia una richiesta ed esegui di nuovo ollama ps: in questo modo misuri il costo in memoria della modifica invece di stimarlo.
La lunghezza del contesto e il numero di slot si moltiplicano, quindi devono essere scelti insieme. Un contesto ampio con quattro slot equivale a quattro contesti ampi. Se stai anche regolando la finestra di contesto num_ctx del modello, modifica un solo parametro alla volta. In caso contrario, non saprai quale dei due ha esaurito la memoria della GPU.
Come impostare queste variabili in modo che persistano dopo un riavvio
Su Linux, Ollama viene eseguito come servizio systemd. Eseguire export OLLAMA_NUM_PARALLEL=4 nella shell non modifica nulla, perché systemd avvia il servizio con il proprio ambiente e non vede quello della shell. Usare un file drop-in.
sudo systemctl edit ollama.serviceAggiungere quanto segue nell'editor che si apre:
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MAX_QUEUE=32"Quindi ricaricare la configurazione e riavviare il servizio:
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environmentsystemctl show mostra ciò che systemd passerà al processo. Se la variabile non è presente, il file drop-in non è stato salvato oppure è stato saltato daemon-reload. Verificare anche dal server stesso:
journalctl -u ollama --no-pager | grep "server config" | tail -1All'avvio, Ollama registra l'intero ambiente su una riga il cui messaggio è server config. Questa mappa rappresenta il valore effettivo. È il modo più rapido per verificare se una variabile è stata applicata.
Un modello già caricato mantiene il numero di slot con cui è stato avviato, perché il valore viene fissato nel processo runner all'avvio. Il riavvio precedente scarica tutto. La richiesta successiva ricarica quindi il modello con la nuova impostazione e sostiene il tempo di caricamento una sola volta. Per quanto tempo il modello rimane residente dopo il caricamento è un controllo distinto, descritto in mantenere un modello Ollama caricato tra le richieste.
Come appaiono al client le richieste servite, accodate e rifiutate
Invia più richieste contemporaneamente e misurane i tempi. Questo comando esegue otto richieste streaming in parallelo e stampa lo stato e le tempistiche di ciascuna:
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 è il tempo al primo byte dello stream. È vicino al tempo al primo token (TTFT), perché il primo blocco trasmesso contiene il primo token.
Servite in parallelo. Ogni richiesta restituisce un valore simile di ttfb e total aumenta contemporaneamente per tutte. La GPU viene condivisa tra gli slot in esecuzione. Di conseguenza, ogni risposta è più lenta rispetto all'esecuzione singola, ma vengono completate più risposte al minuto. Questo è il comportamento che si ottiene aumentando OLLAMA_NUM_PARALLEL.
Accodate. Le prime richieste ricevono rapidamente una risposta, mentre quelle successive mostrano un valore elevato di ttfb, seguito da una generazione normale. L'attesa è dovuta alla coda, non al modello. In una finestra di chat l'utente vede una lunga pausa senza contenuti, quindi il testo viene visualizzato alla velocità normale. Questo andamento, lento all'avvio e poi rapido, indica una coda più che una GPU sovraccarica.
Rifiutate. Il client riceve http=503 quasi immediatamente e il corpo della risposta è:
{"error":"server busy, please try again. maximum pending requests exceeded"}Il messaggio indica che la coda era piena quando è arrivata la richiesta. Non fornisce informazioni sulla VRAM né sul modello.
C'è un limite importante: Ollama non pubblica la profondità della coda. ollama ps e l'endpoint /api/ps mostrano i modelli caricati, non le richieste in attesa. Per questo è necessario misurare la coda dal lato client, monitorando il tempo al primo byte, oppure contare le risposte 503 restituite dal componente che si trova davanti al servizio.
Perché un valore MAX_QUEUE più basso è spesso l'impostazione migliore
Una coda di 512 richieste sembra ampia, ma con un solo slot è quasi inutile. La richiesta 300 resta in attesa dietro 299 generazioni completate. Nel migliore dei casi, l'attesa dura diversi minuti. Qualsiasi client HTTP va in timeout molto prima. Il chiamante vede quindi un timeout lato client, che non fornisce informazioni sulla causa e non offre al monitoraggio alcun evento utile da segnalare.
Impostate la coda su un valore corrispondente, approssimativamente, al numero di richieste che il server riesce a completare entro il timeout del client. Le richieste oltre questo limite ricevono invece immediatamente un errore 503. Un errore 503 è utile: un reverse proxy può riprovare, un client può applicare un backoff, una dashboard può conteggiarlo e una persona può leggerlo. Calcolate il valore sulla base delle vostre misurazioni. Se una generazione richiede circa dieci secondi e il client attende sessanta secondi, ogni slot può completare circa sei richieste entro questo intervallo. Una coda molto più profonda produrrebbe soltanto timeout.
Quando mettere una coda davanti a Ollama
La coda integrata è FIFO (first in, first out) e non considera chi invia la richiesta. Per un'applicazione che comunica con un solo server è sufficiente; aggiungere altra infrastruttura introdurrebbe soltanto ulteriori modalità di errore. È opportuno usare un componente a monte quando si verifica una delle condizioni seguenti.
- È necessaria una priorità. Una chat interattiva non dovrebbe attendere dietro a un processo batch di riepilogo. La coda di Ollama non supporta priorità, quindi i processi batch devono essere trattenuti all'esterno e inviati gradualmente.
- È necessaria l'equità. Un singolo client può riempire la coda da solo, causando quindi risposte 503 per tutti gli altri.
- È necessario che il lavoro sopravviva a un riavvio. La coda risiede nella memoria del server. Se si riavvia Ollama, tutte le richieste in attesa vengono eliminate.
- Sono necessari nuovi tentativi reali con backoff, registrati in un sistema che sia possibile consultare in seguito.
La soluzione più semplice è un reverse proxy. In nginx, limit_conn limita il numero di connessioni simultanee e limit_req limita il tasso di arrivo per client, quindi il proxy rifiuta le richieste in eccesso prima che raggiungano la coda di Ollama. La soluzione più complessa è una coda di job con un database davanti a un worker che chiama Ollama. È la scelta necessaria quando le richieste devono sopravvivere al riavvio di un processo. Dimensionare questa soluzione per il traffico reale richiede un'analisi dedicata: pianificare un LLM self-hosted per utenti simultanei illustra i calcoli, mentre eseguire Ollama su un VPS descrive l'installazione di base presupposta da queste variabili.
Quando la scelta corretta è un server diverso
Esiste un limite che non puoi superare modificando la configurazione. Ollama suddivide la KV cache in slot uguali e fissi quando carica il modello. La memoria di uno slot inattivo non può essere utilizzata da uno slot occupato e il numero di slot non può cambiare senza scaricare il modello. Questo design è adatto a una persona, a un piccolo team o a un agente di coding.
I server progettati per molti utenti simultanei funzionano in modo diverso. Allocano la KV cache in piccole pagine su richiesta e aggiungono le richieste in arrivo a un batch già in esecuzione. In questo modo la memoria segue la domanda effettiva anziché una suddivisione fissa. Se l'obiettivo è gestire molti utenti concorrenti su una GPU, questa differenza architetturale conta più di qualsiasi valore di OLLAMA_NUM_PARALLEL. Il confronto tra Ollama e vLLM è il punto in cui prendere questa decisione. Non passare a un'altra soluzione per principio: un server diverso richiede più attività operative e, se il traffico proviene da poche persone, il comportamento integrato è la scelta corretta.
Misurare il proprio throughput e il tempo al primo token
I valori pubblicati in token al secondo provengono dalla GPU, dal modello, dalla quantizzazione, dalla lunghezza del contesto e dal prompt utilizzati da qualcun altro. Nessuno di questi elementi corrisponde necessariamente alla configurazione in uso. Considera quindi ogni valore come una semplice indicazione e misura direttamente la macchina che esegue il servizio.
Ollama restituisce i tempi nell'oggetto JSON finale di ogni risposta. eval_count indica il numero di token generati e eval_duration il tempo impiegato per generarli, espresso in nanosecondi.
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))}'Esegui il comando con un solo slot, quindi ripetilo usando il livello di concorrenza previsto in produzione. Confronta i due valori che determinano la soddisfazione degli utenti: il tempo al primo token e i token al secondo per richiesta. Il throughput per richiesta diminuisce sempre quando aumenti il numero di slot. La domanda è se diminuisce oltre il limite accettabile per gli utenti. Misurare i token al secondo con un LLM locale descrive il metodo in maggiore dettaglio, incluso come mantenere invariato il prompt tra le esecuzioni.
Un endpoint pubblico con una coda ampia è un bersaglio per gli attacchi di negazione del servizio
L'impostazione OLLAMA_HOST=0.0.0.0:11434 espone l'API su tutte le interfacce e Ollama non dispone di autenticazione integrata. Un endpoint aperto con la coda predefinita accetta 512 richieste in attesa da chiunque lo individui. Riempire quella coda costa quasi nulla a un attaccante: prompt lunghi, nessun accesso, nessun rate limiting e nessun costo. I tuoi utenti ricevono quindi risposte 503 o devono attendere a lungo, mentre la macchina rimane occupata per tutto il tempo.
Mantieni il listener sull'interfaccia di loopback e raggiungilo tramite un tunnel SSH o una rete privata, oppure configura autenticazione e rate limiting davanti all'endpoint. Protezione di un endpoint API Ollama tratta entrambe le opzioni. Configura la coda solo dopo avere completato questa parte, perché la lunghezza della coda è un'impostazione di capacità e non protegge il servizio.
FAQ
Perché la seconda richiesta a Ollama attende il completamento della prima?
Perché OLLAMA_NUM_PARALLEL è impostato su 1 per impostazione predefinita. Un modello caricato elabora quindi una richiesta alla volta e le altre restano in attesa in ordine. La richiesta in attesa mantiene aperta la connessione HTTP e non invia byte finché non si libera uno slot. Dal lato client, questo comportamento è identico a quello di un modello lento. Il segnale distintivo è l'andamento dei tempi: una lunga pausa seguita da testo alla massima velocità indica una coda, mentre un flusso lento fin dal primo token indica un modello lento. Aumenta il numero di slot con un drop-in di systemd e riavvia il servizio.
Che cosa significa "server busy, please try again. maximum pending requests exceeded"?
È l'errore di overflow della coda di Ollama, restituito con stato HTTP 503. Il numero di richieste già in attesa ha raggiunto OLLAMA_MAX_QUEUE, che per impostazione predefinita è 512. La richiesta più recente è stata quindi rifiutata invece di essere aggiunta alla coda. Non è un errore di memoria e non è un errore del modello. Aumentare la coda fa soltanto attendere più a lungo i client prima dello stesso rifiuto. Le correzioni effettive sono aumentare il numero di slot, se la VRAM disponibile lo consente, ridurre il carico in ingresso oppure usare una coda a monte in grado di ritentare le richieste e assegnare loro una priorità.
Aumentare OLLAMA_NUM_PARALLEL rende Ollama più veloce?
No. Consente di eseguire più richieste contemporaneamente, ma ciascuna richiesta è più lenta rispetto all'esecuzione isolata perché tutte condividono una sola GPU. Inoltre moltiplica la KV cache, perché Ollama avvia il runner con un contesto totale pari alla lunghezza del contesto moltiplicata per il numero di slot. Se il risultato non entra più nella VRAM, Ollama sposta alcuni layer sulla CPU e tutte le richieste diventano più lente, anche una singola richiesta senza concorrenza. Dopo la modifica, controlla ollama ps e verifica che la colonna PROCESSOR contenga ancora 100% GPU.
Devo riavviare Ollama dopo aver modificato queste variabili?
Sì. Il server le legge all'avvio e un modello in esecuzione mantiene il numero di slot definito nel processo runner al momento dell'avvio. Modifica il drop-in con sudo systemctl edit ollama.service, quindi esegui sudo systemctl daemon-reload e sudo systemctl restart ollama. Verifica con systemctl show ollama --property=Environment, quindi controlla la riga server config in journalctl -u ollama, che elenca l'ambiente effettivamente caricato dal server.
Quanti slot paralleli devo impostare?
Inizia da 1 e aumenta il valore di un'unità alla volta. Dopo ogni modifica, riavvia Ollama, invia una richiesta per caricare il modello ed esegui ollama ps. Fermati all'ultimo valore per cui PROCESSOR contiene ancora 100% GPU e la colonna SIZE mantiene margine sufficiente per il contesto più lungo che gestisci. A quel valore, misura il tempo al primo token e i token al secondo con la concorrenza reale. Riduci quindi il valore di un'unità se la velocità per richiesta è scesa al di sotto del livello accettabile per gli utenti.