Ollama: NUM_PARALLEL e MAX_QUEUE na prática
Entenda por que a segunda solicitação espera ou recebe HTTP 503, como OLLAMA_NUM_PARALLEL e OLLAMA_MAX_QUEUE controlam a fila e o custo de VRAM.
O que acontece com a segunda solicitação do Ollama enquanto a primeira está a ser gerada
A simultaneidade do Ollama é definida por três variáveis de ambiente e, por predefinição, um modelo carregado atende uma solicitação de cada vez. A segunda solicitação não é recusada nem recebe uma resposta parcial. Fica numa fila até haver um slot livre e, depois, é executada à velocidade normal.
Uma solicitação recebida tem três destinos possíveis. Pode iniciar imediatamente num slot livre. Pode ficar à espera na fila. Ou a fila pode já estar cheia e o servidor recusá-la com HTTP 503. O resultado depende de OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE e OLLAMA_MAX_LOADED_MODELS.
A predefinição é segura. Também explica por que motivo um segundo utilizador pode dizer que o servidor "bloqueou" quando não há nenhum problema. Adicionar slots requer uma alteração de duas linhas. O problema está na memória. Cada slot paralelo precisa da sua própria cache de chaves/valores (cache KV), o bloco de memória que um modelo mantém para os tokens que já processou. Adicionar slots sem aumentar a VRAM (memória de vídeo da GPU) transforma uma resposta lenta numa falha ao carregar o modelo.
O que OLLAMA_NUM_PARALLEL, OLLAMA_MAX_LOADED_MODELS e OLLAMA_MAX_QUEUE controlam
Estes são os valores predefinidos nas versões atuais do Ollama em agosto de 2026. Consulte os valores do seu sistema em vez de confiar neste número, usando a linha do log apresentada mais abaixo.
OLLAMA_NUM_PARALLELindica quantos pedidos um modelo carregado processa simultaneamente. O valor predefinido é 1, portanto os pedidos são processados um após o outro.OLLAMA_MAX_LOADED_MODELSindica quantos modelos diferentes permanecem carregados ao mesmo tempo. O valor predefinido é 0, o que significa que o Ollama escolhe: três modelos por GPU e três numa máquina sem GPU.OLLAMA_MAX_QUEUEindica quantos pedidos podem permanecer à espera. O valor predefinido é 512. O pedido que chega quando a fila está cheia é rejeitado imediatamente.
A memória máxima necessária é o produto dos dois primeiros valores. Dois modelos carregados com quatro slots cada representam oito alocações de slots de cache KV, todas residentes ao mesmo tempo, e o Ollama tentará satisfazer essa necessidade. Numa máquina com uma única GPU, normalmente é melhor manter um modelo carregado e atribuir-lhe slots, porque o cálculo continua a ser fácil de fazer mentalmente.
Por que cada slot paralelo consome VRAM
Quando o Ollama carrega um modelo, inicia um processo runner separado. Dois dos argumentos que passa são relevantes aqui: -c é o contexto total para o qual o runner aloca uma cache KV, e -np é o número de sequências paralelas. O Ollama define -c como o comprimento de contexto por pedido multiplicado pelo número de slots. Depois, o runner divide esse total uniformemente pelos slots, para que cada pedido continue a receber o comprimento de contexto solicitado.
Essa é a restrição completa e é por isso que o paralelismo não é gratuito. Passar de um slot para quatro exige quatro vezes mais cache KV com o mesmo contexto por pedido. Nada é partilhado entre os slots e a parte de um slot inativo não é cedida a um slot ocupado, porque a divisão é fixa quando o runner arranca.
Pode consultar os valores reais em vez dos valores que pretendia definir:
journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"Essa linha contém a linha de comandos completa do runner, incluindo -c e -np. Se -np for 1 depois de definir a variável, a configuração não está a chegar ao servidor, e a próxima secção explica porquê.
Se os pesos do modelo e essa cache KV não couberem na VRAM, o Ollama move algumas camadas para a RAM do sistema e essas camadas são executadas no CPU. As camadas no CPU são muito mais lentas do que as camadas na GPU, por isso cada pedido fica mais lento, incluindo o único pedido que iniciou. Aumentar o paralelismo pode, portanto, reduzir o débito em vez de o aumentar. Com um modelo suficientemente grande, os pesos determinam a situação antes de qualquer cálculo de slots, razão pela qual alojar por conta própria algo do tamanho do Kimi K3 é uma questão de quantas placas tem, e não de quantos slots define.
ollama psA coluna PROCESSOR mostra 100% GPU quando tudo cabe. Uma divisão como 35%/65% CPU/GPU significa que parte do modelo está a ser executada no CPU. A coluna SIZE inclui a cache KV, por isso aumenta quando aumenta o número de slots e volta a carregar o modelo. Aumente OLLAMA_NUM_PARALLEL, reinicie, envie um pedido e execute ollama ps novamente: esse é o custo de memória da alteração, medido em vez de estimado. Se essa medição indicar que o modelo já não cabe, lembre-se de que os pesos são a outra metade do mesmo orçamento, e passar de uma compilação fp16 para q8 ou q4 muitas vezes liberta mais VRAM do que o custo do slot que estava a tentar adicionar.
O comprimento do contexto e o número de slots multiplicam-se, por isso têm de ser escolhidos em conjunto. Um contexto grande com quatro slots corresponde a quatro contextos grandes. Se também estiver a ajustar a janela de contexto num_ctx do seu modelo, altere apenas um dos dois de cada vez; caso contrário, não saberá qual deles ocupou a placa.
Como definir estas variáveis para que persistam após um reboot
No Linux, o Ollama é executado como um serviço systemd. Executar export OLLAMA_NUM_PARALLEL=4 na sua shell não altera nada, porque o systemd inicia o serviço com o seu próprio ambiente e nunca vê a sua shell. Use um ficheiro drop-in.
sudo systemctl edit ollama.serviceAdicione isto no editor que abrir:
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MAX_QUEUE=32"Depois, recarregue e reinicie:
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environmentsystemctl show mostra o que o systemd vai fornecer ao processo. Se a sua variável não aparecer aí, o drop-in não foi guardado ou daemon-reload não foi executado. Confirme também no próprio servidor:
journalctl -u ollama --no-pager | grep "server config" | tail -1O Ollama regista todo o seu ambiente no arranque, numa linha cuja mensagem é server config. Esse mapa é a fonte de verdade. É a forma mais rápida de esclarecer se uma variável entrou em vigor.
Um modelo que já esteja carregado mantém a quantidade de slots com que foi iniciado, porque o valor fica definido no processo runner no arranque. O reinício acima descarrega tudo. Assim, o pedido seguinte volta a carregar o modelo com a nova configuração e suporta o tempo de carregamento uma vez. Durante quanto tempo um modelo permanece residente depois disso é um controlo separado, explicado em manter um modelo Ollama carregado entre pedidos.
O que é servido, fica em fila ou é recusado no cliente
Envie vários pedidos ao mesmo tempo e cronometre-os. Isto executa oito pedidos de streaming em paralelo e apresenta o estado e os tempos de cada um:
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 é o tempo até ao primeiro byte do stream. É próximo do tempo até ao primeiro token (TTFT), porque o primeiro bloco enviado contém o primeiro token.
Servidos em paralelo. Cada pedido apresenta um ttfb semelhante, e total aumenta para todos ao mesmo tempo. A GPU é partilhada entre os slots em execução. Por isso, cada resposta é mais lenta do que seria isoladamente, mas são concluídas mais respostas por minuto. Este é o regime que obtém quando aumenta OLLAMA_NUM_PARALLEL.
Em fila. Os primeiros pedidos respondem rapidamente. Os seguintes apresentam um ttfb elevado, seguido de uma geração normal. A espera é causada pela fila, não pelo modelo. Um utilizador que observa uma janela de chat vê uma longa pausa sem texto e, depois, texto à velocidade normal. Este padrão, lento no início e rápido depois, é característico de uma fila, não de uma GPU sobrecarregada.
Recusados. O cliente recebe http=503 quase imediatamente, e o corpo é:
{"error":"server busy, please try again. maximum pending requests exceeded"}Essa mensagem significa que a fila estava cheia quando o pedido chegou. Não fornece qualquer informação sobre a VRAM nem sobre o modelo.
Há uma limitação importante: o Ollama não publica a profundidade da fila. ollama ps e o endpoint /api/ps apresentam os modelos carregados, não os pedidos em espera. Por isso, meça a fila no lado do cliente, monitorizando o tempo até ao primeiro byte, ou conte as respostas 503 no componente que estiver à frente.
Por que um MAX_QUEUE menor costuma ser a melhor configuração
Uma fila de 512 parece generosa, mas, com um único slot, é quase inútil. O pedido 300 fica atrás de 299 gerações concluídas. Isso demora vários minutos, na melhor das hipóteses. Qualquer cliente HTTP desiste muito antes disso. O chamador recebe um timeout do lado do cliente, que não informa a causa e não fornece ao monitoramento nada que possa gerar um alerta.
Defina a fila com um tamanho aproximado do que o seu servidor consegue processar dentro do timeout do cliente. Assim, o excesso transforma-se imediatamente em 503. Um 503 é útil: um reverse proxy pode tentar novamente, o cliente pode aplicar backoff, um dashboard pode contabilizá-lo e uma pessoa pode interpretá-lo. Calcule o valor com base nas suas próprias medições. Se uma geração demora cerca de dez segundos e o cliente aguarda sessenta, então cerca de seis pedidos por slot podem ser concluídos dentro desse intervalo. Uma fila muito mais profunda do que isso apenas produz timeouts.
Quando colocar uma fila à frente do Ollama
A fila incorporada funciona no modelo first in, first out (FIFO) e não sabe quem está a fazer cada pedido. Para uma aplicação a comunicar com um único servidor, isso é suficiente. Adicionar infraestrutura apenas introduziria mais pontos de falha. Considere colocar algo à frente quando uma destas condições se aplica.
- Precisa de prioridades. Um chat interativo não deve ficar à espera atrás de um trabalho de resumo em lote. A fila do Ollama não tem prioridades, por isso o trabalho em lote tem de ser mantido externamente e enviado gradualmente.
- Precisa de equidade. Um cliente pode ocupar a fila sozinho e fazer com que todos os outros recebam 503.
- Precisa que o trabalho sobreviva a um reinício. A fila existe na memória do servidor. Se reiniciar o Ollama, todos os pedidos em espera são perdidos.
- Precisa de novas tentativas reais com recuo progressivo, registadas num local que possa consultar posteriormente.
A opção mais simples é um reverse proxy. No nginx, limit_conn limita as ligações simultâneas e limit_req limita a taxa de chegada por cliente. Assim, o excesso é recusado no proxy e nunca chega à fila do Ollama. A opção mais robusta é uma fila de trabalhos com uma base de dados à frente de um worker que chama o Ollama. É essa a opção adequada quando os pedidos têm de sobreviver ao reinício de um processo. Dimensionar essa solução para tráfego real é um exercício separado: planeamento de um LLM self-hosted para utilizadores simultâneos explica os cálculos, e executar o Ollama numa VPS aborda a instalação base que estas variáveis pressupõem.
Quando a resposta correta é outro servidor
Há um limite que não pode ser ultrapassado com ajustes. O Ollama divide a cache KV em slots iguais e fixos quando o modelo é carregado. A memória de um slot inativo não pode ser usada por um slot ocupado, e o número de slots não pode mudar sem descarregar o modelo. Esse desenho é adequado para uma pessoa, uma equipa pequena ou um agente de programação.
Os servidores concebidos para muitos utilizadores simultâneos funcionam de outra forma. Alocam a cache KV em páginas pequenas conforme necessário e adicionam os pedidos recebidos a um batch que já está em execução. Assim, a memória acompanha a procura real em vez de seguir uma divisão fixa. Se o objetivo é suportar muitos utilizadores simultâneos numa GPU, essa diferença de arquitetura é mais importante do que qualquer valor de OLLAMA_NUM_PARALLEL. A comparação entre Ollama e vLLM é o local certo para tomar essa decisão. No entanto, não mude apenas por princípio: outro servidor exige mais operações, e, se o tráfego vier de poucas pessoas, o comportamento integrado é a resposta correta.
Meça o seu próprio throughput e o tempo até ao primeiro token
Os valores publicados de tokens por segundo vêm da GPU, do modelo, da quantização, do tamanho do contexto e do prompt de outra pessoa. Nenhum desses parâmetros corresponde aos seus, por isso trate qualquer valor lido como uma indicação aproximada e meça a máquina que tem à sua frente.
Ollama devolve os tempos no objeto JSON final de cada resposta. eval_count é o número de tokens gerados e eval_duration é o tempo gasto a gerá-los, em nanossegundos.
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))}'Execute isso com um slot e depois novamente com a simultaneidade que espera realmente utilizar. Compare os dois valores que determinam a satisfação dos utilizadores: o tempo até ao primeiro token e os tokens por segundo por pedido. O throughput por pedido diminui sempre que são adicionados slots. A questão é saber se diminui mais do que os seus utilizadores aceitam. Medir tokens por segundo num LLM local explica o método com mais detalhe, incluindo como manter o prompt constante entre as execuções.
Um endpoint público com uma fila generosa é um alvo de negação de serviço
Definir OLLAMA_HOST=0.0.0.0:11434 coloca a API em todas as interfaces, e o Ollama não tem autenticação integrada. Um endpoint aberto com a fila predefinida aceita 512 pedidos em espera de qualquer pessoa que o encontre. Encher essa fila custa quase nada a um atacante: prompts longos, sem início de sessão, sem limite de taxa e sem custos. Os seus utilizadores recebem respostas 503 ou esperam durante muito tempo, e a máquina fica ocupada durante todo esse período.
Mantenha o listener na interface de loopback e aceda a ele através de um túnel SSH ou de uma rede privada, ou coloque autenticação e limitação de taxa à sua frente. Proteger um endpoint da API do Ollama aborda ambas as opções. Ajuste a fila apenas depois de concluir essa configuração, porque o comprimento da fila é uma definição de capacidade e não fornece qualquer proteção.
FAQ
Por que a minha segunda solicitação ao Ollama espera que a primeira termine?
Porque OLLAMA_NUM_PARALLEL tem o valor padrão 1. Assim, um modelo carregado processa uma solicitação de cada vez e as restantes esperam pela sua vez. A solicitação em espera mantém a ligação HTTP aberta e não envia bytes até libertar-se um slot. Do lado do cliente, isto parece exatamente um modelo lento. O indicador está no padrão temporal: uma pausa longa seguida de texto à velocidade máxima indica uma fila, enquanto um fluxo lento desde o primeiro token indica um modelo lento. Aumente o número de slots com um drop-in do systemd e reinicie o serviço.
O que significa "server busy, please try again. maximum pending requests exceeded"?
Esse é o erro de overflow da fila do Ollama, devolvido com o estado HTTP 503. O número de solicitações que já estavam em espera atingiu OLLAMA_MAX_QUEUE, cujo valor padrão é 512. Por isso, a solicitação mais recente foi rejeitada em vez de ser adicionada à fila. Não é um erro de memória nem um erro do modelo. Aumentar o tamanho da fila apenas faz os clientes esperar mais tempo antes da mesma rejeição. As correções reais são aumentar o número de slots, se tiver VRAM suficiente, reduzir a carga recebida ou colocar uma fila à frente que possa repetir e priorizar as solicitações.
Aumentar OLLAMA_NUM_PARALLEL torna o Ollama mais rápido?
Não. Essa alteração permite executar mais solicitações em simultâneo, mas cada uma fica mais lenta do que ficaria se fosse executada sozinha, porque todas partilham a mesma GPU. A alteração também multiplica a cache KV, porque o Ollama inicia o runner com um contexto total equivalente ao comprimento de contexto multiplicado pelo número de slots. Se o resultado deixar de caber na VRAM, o Ollama transfere camadas para a CPU e todas as solicitações ficam mais lentas, incluindo uma solicitação única sem concorrência. Verifique ollama ps depois da alteração e confirme que a coluna PROCESSOR continua a apresentar 100% GPU.
Preciso de reiniciar o Ollama depois de alterar estas variáveis?
Sim. O servidor lê estas variáveis no arranque, e um modelo em execução mantém o número de slots definido no processo runner quando este foi iniciado. Edite o drop-in com sudo systemctl edit ollama.service e execute sudo systemctl daemon-reload e sudo systemctl restart ollama. Confirme com systemctl show ollama --property=Environment e, em seguida, verifique a linha server config em journalctl -u ollama, que lista o ambiente efetivamente carregado pelo servidor.
Quantos slots paralelos devo configurar?
Comece com 1 e aumente um passo de cada vez. Depois de cada alteração, reinicie o Ollama, envie uma solicitação para carregar o modelo e execute ollama ps. Pare no último valor em que PROCESSOR ainda apresente 100% GPU e a coluna SIZE mantenha margem suficiente para o contexto mais longo que disponibiliza. Depois, meça o tempo até ao primeiro token e os tokens por segundo com essa configuração, sob a concorrência real, e recue um passo se a velocidade por solicitação tiver descido abaixo do que os seus utilizadores toleram.