SSD Nodes Learn 🎉 VPS desde $5.50/mês
Guias Matt ConnorPor Matt Connor

Ollama: como NUM_PARALLEL e MAX_QUEUE funcionam

Entenda quando a segunda solicitação espera ou recebe HTTP 503, como OLLAMA_NUM_PARALLEL e OLLAMA_MAX_QUEUE controlam a fila e por que cada slot consome VRAM.

O que acontece com a segunda solicitação do Ollama enquanto a primeira está a ser gerada

A concorrência do Ollama é definida por três variáveis de ambiente e, por predefinição, um modelo carregado processa uma solicitação de cada vez. A segunda solicitação não é recusada e não recebe uma resposta parcial. Fica numa fila até haver um slot disponível e, depois, é processada à velocidade normal.

Uma solicitação recebida pode ter um de três destinos. Começa imediatamente num slot livre. Fica à espera na fila. Ou a fila já está cheia e o servidor recusa a solicitação com HTTP 503. O resultado depende de OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE e OLLAMA_MAX_LOADED_MODELS.

A predefinição é segura e também explica por que um segundo utilizador pode indicar que o servidor "bloqueou" quando não há nenhum problema. Adicionar slots exige uma alteração de duas linhas. O problema está na memória. Cada slot paralelo precisa da sua própria cache de chave/valor (cache KV), o bloco de memória que o modelo mantém para os tokens já processados. Adicionar slots sem aumentar a VRAM (memória de vídeo da GPU) transforma uma resposta lenta numa falha de carregamento.

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 seus valores em vez de confiar nestes números, usando a linha do log apresentada mais abaixo.

  • OLLAMA_NUM_PARALLEL define quantos pedidos um modelo carregado processa ao mesmo tempo. O valor predefinido é 1, por isso os pedidos são processados um após o outro.
  • OLLAMA_MAX_LOADED_MODELS define 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_QUEUE define 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 é o produto dos dois primeiros valores. Dois modelos carregados com quatro slots cada correspondem a oito alocações de slots da cache KV, todas residentes ao mesmo tempo, e o Ollama tentará satisfazer essa configuração. Numa máquina com uma única GPU, normalmente é melhor manter um modelo carregado e atribuir-lhe slots, porque o cálculo continua a ser simples.

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 importantes neste caso: -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 igualmente pelos slots, para que cada pedido continue a receber o comprimento de contexto solicitado.

Essa é toda a limitação e explica por 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 é iniciado.

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. A secção seguinte explica porquê.

Se os pesos do modelo mais 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, todos os pedidos ficam mais lentos, incluindo o único pedido que iniciou. Aumentar o paralelismo pode, portanto, reduzir o throughput em vez de o aumentar.

ollama ps

A 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 eleva o número de slots e recarrega 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.

O comprimento de 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 VRAM.

Como configurar estas variáveis para persistirem 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.service

Adicione 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=Environment

systemctl 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 foi ignorado. Confirme também a partir do próprio servidor:

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

O 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 o número de slots com que foi iniciado, porque o valor fica definido no processo runner no arranque. O reinício acima descarrega tudo, para que o pedido seguinte volte a carregar o modelo com a nova configuração e suporte o tempo de carregamento uma vez. Durante quanto tempo o modelo permanece residente depois disso é um controlo separado, explicado em manter um modelo Ollama carregado entre pedidos.

Como distinguir pedidos atendidos, em fila e recusados no cliente

Envie vários pedidos ao mesmo tempo e cronometre-os. Este comando 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
wait

ttfb é 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.

Atendidos em paralelo. Todos os pedidos apresentam 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 mais respostas são concluídas por minuto. Este é o comportamento que obtém quando aumenta OLLAMA_NUM_PARALLEL.

Em fila. Os primeiros pedidos respondem rapidamente. Os pedidos seguintes apresentam um ttfb elevado, seguido de uma geração normal. A espera corresponde à fila, não ao modelo. Um utilizador que observa uma janela de chat vê uma pausa longa sem conteúdo e, depois, texto à velocidade normal. Este padrão, lento no início e rápido a seguir, indica uma fila e não uma GPU sobrecarregada.

Recusados. O cliente recebe http=503 quase imediatamente, e o corpo é:

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

Esta 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, deve medir a fila no lado do cliente, observando o tempo até ao primeiro byte, ou contar as respostas 503 no componente que estiver à frente.

Por que um MAX_QUEUE menor costuma ser a configuração mais adequada

Uma fila de 512 parece generosa, mas é quase inútil quando existe apenas um slot. A requisição 300 fica atrás de 299 gerações concluídas. Isso demora vários minutos, no melhor caso. 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 nada para o seu monitoramento alertar.

Defina a fila com um tamanho aproximado ao que o seu servidor consegue processar dentro do timeout do cliente. Assim, o excesso resulta imediatamente num 503. Um 503 é útil: um reverse proxy pode repetir a tentativa, um 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 espera sessenta, aproximadamente seis requisições por slot podem ser processadas dentro desse intervalo. Uma fila muito mais profunda do que isso apenas produz timeouts.

Quando colocar uma fila à frente do Ollama

A fila integrada funciona por ordem de chegada, primeira a entrar, primeira a sair (FIFO), e não sabe quem está a fazer o pedido. Para uma aplicação que comunica com um servidor, isso é suficiente, e adicionar infraestrutura apenas criaria mais pontos de falha. Considere colocar algo à frente quando uma destas condições se aplicar.

  • Precisa de prioridade. Um chat interativo não deve esperar 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 retido externamente e enviado gradualmente.
  • Precisa de equidade. Um cliente pode encher a fila sozinho, fazendo com que todos os outros recebam 503.
  • Precisa que o trabalho sobreviva a um reinício. A fila fica 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, por isso 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. É isso que deve usar quando os pedidos têm de sobreviver ao reinício de um processo. Dimensionar essa solução para tráfego real é um trabalho à parte: 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 assumida por estas variáveis.

Quando a resposta correta é usar outro servidor

Há um limite que não pode ser ultrapassado com ajustes. O Ollama divide o cache KV em slots iguais e fixos quando carrega o modelo. A memória de um slot inativo não pode ser usada por um slot ocupado, e a quantidade de slots não pode mudar sem descarregar o modelo. Esse projeto é 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. Eles alocam o 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 for atender 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 ponto certo para tomar essa decisão. Ainda assim, não mude apenas por princípio: operar outro servidor dá mais trabalho e, se o tráfego vier de poucas pessoas, o comportamento integrado é a resposta correta.

Meça o seu 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 elementos é igual ao seu. Trate qualquer valor lido como uma indicação aproximada e meça a máquina que tem à sua frente.

O 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 esse comando com um slot e depois com o nível de concorrência que espera utilizar. Compare as duas métricas 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 essa diminuição ultrapassa o limite 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 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 passam a receber respostas 503 ou a esperar durante muito tempo, enquanto a máquina permanece ocupada.

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 à frente dele. Proteger um endpoint da API do Ollama aborda ambas as opções. Ajuste a fila só depois de fazer isso, porque o comprimento da fila é uma definição de capacidade e não fornece proteção.

FAQ

Por que a minha segunda solicitação ao Ollama espera que a primeira termine?

Porque OLLAMA_NUM_PARALLEL tem o valor predefinido 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é ser libertada uma vaga. Do lado do cliente, isto parece um modelo lento. O indicador é o padrão temporal: uma pausa longa seguida de texto à velocidade máxima indica uma fila. Um fluxo lento desde o primeiro token indica um modelo lento. Aumente o número de vagas 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 já em espera atingiu OLLAMA_MAX_QUEUE, cujo valor predefinido é 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 a fila apenas faz os clientes esperarem mais tempo antes da mesma rejeição. As correções reais são aumentar o número de vagas, se tiver VRAM suficiente, reduzir a carga recebida ou colocar uma fila à frente que possa repetir e dar prioridade às solicitações.

Aumentar OLLAMA_NUM_PARALLEL torna o Ollama mais rápido?

Não. Isto permite executar mais solicitações em simultâneo, mas cada solicitação fica mais lenta do que ficaria se executada sozinha, porque partilham uma GPU. Também multiplica a cache KV, porque o Ollama inicia o runner com um contexto total igual ao comprimento do contexto multiplicado pelo número de vagas. Se o resultado já não couber 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 ainda apresenta 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 vagas definido no processo runner quando este foi iniciado. Edite o drop-in com sudo systemctl edit ollama.service. Em seguida, execute sudo systemctl daemon-reload e sudo systemctl restart ollama. Confirme com systemctl show ollama --property=Environment. Depois, verifique a linha server config em journalctl -u ollama, que apresenta o ambiente efetivamente carregado pelo servidor.

Quantas vagas paralelas devo configurar?

Comece com 1 e aumente o valor 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 serve. Depois, meça o tempo até ao primeiro token e os tokens por segundo com essa configuração, usando a concorrência real do seu ambiente. Reduza um passo se a velocidade por solicitação ficar abaixo do que os utilizadores toleram.

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