Quantas requisições simultâneas seu LLM na VPS aguenta? Como configurar batching, fila e medir tokens por segundo

configuração de requisições simultâneas LLM VPS com batching e fila
Resposta rápida

Descobrir quantas requisições simultâneas LLM VPS aguenta não é questão de tabela pronta, é configuração mais medição. No vLLM tu define o teto de concorrência com max_num_seqs, o contexto por requisição com max_model_len e o KV cache através de gpu_memory_utilization. No Ollama, o controle vem de OLLAMA_NUM_PARALLEL e OLLAMA_MAX_QUEUE. Depois de configurar, mede: no vLLM com vllm bench serve (TTFT, throughput, TPOT, ITL) e no Ollama pelos campos de timing da API. Número de terceiro em hardware diferente não serve pro teu caso

Fala aí, beleza? Aquele modelo que voava sozinho na tua VPS, respondendo lisinho enquanto só tu usava, engasga feio quando cinco pessoas apertam enter ao mesmo tempo

E isso não é bug, é comportamento esperado de um servidor de inferência que ninguém configurou pra concorrência

A questão "qual VPS aguenta rodar meu modelo" é uma pergunta de DIMENSIONAMENTO DE HARDWARE pra uma sessão: cabe na VRAM, roda numa velocidade aceitável, beleza

Esta pauta aqui é outra pergunta: capacidade de ATENDIMENTO concorrente

É a diferença entre "cabe" e "atende um time". Tem parâmetro próprio, tem fila, tem métrica própria e tem jeito certo de medir

Bora entender?

O que muda quando chega a segunda requisição ao mesmo tempo

A intuição errada é imaginar o servidor como uma fila de banco: atende o primeiro, termina, chama o próximo

Não é assim que funciona

O servidor moderno de inferência agrupa requisições em ITERAÇÕES do scheduler. A cada passo ele decide quais sequências vão avançar juntas, e requisições novas entram no meio do agrupamento em vez de esperar as anteriores acabarem inteiras

Isso é o batching contínuo

Que KV cache é esse?

Toda sequência em andamento guarda estado na memória da GPU, o KV cache

E aqui mora o acoplamento que quebra a cabeça de quem tá começando: a necessidade de KV cache é função de quantas sequências tu quer em paralelo E do quanto de contexto cada uma pode usar

Ou seja, os três parâmetros que tu vai mexer no vLLM (número de sequências, comprimento de contexto e fração de memória pré-alocada) não são independentes

Eles disputam o MESMO recurso

No vLLM, a documentação aponta o PagedAttention como o mecanismo de gerenciamento de memória que, junto com técnicas de scheduler como o batching, sustenta o throughput

Os dois níveis de concorrência do Ollama

O Ollama descreve a concorrência em dois níveis, e confundir os dois é erro clássico

  • Entre modelos carregados: vários modelos ficam na memória ao mesmo tempo, se houver RAM de sistema (CPU) ou VRAM (GPU) disponível
  • Dentro de um mesmo modelo: um modelo já carregado processando várias requisições em paralelo

São controles diferentes, com variáveis de ambiente diferentes. Já volto neles

Hospedagem que aguenta seu projeto crescer
Hospedagem recomendada

Hospedagem que aguenta seu projeto crescer

Hospedagem rápida, painel simples, backups automáticos e suporte 24/7 em português.

O vocabulário que tu vai ver o resto do post inteiro

Antes de configurar qualquer coisa, precisa saber o que tá olhando:

Métrica O que é
TTFT (Time to First Token) Quanto tempo até o primeiro token aparecer pro usuário
TPOT (Time per Output Token) Tempo por token de saída
ITL (Inter-token Latency) Latência entre tokens
Output token throughput Tokens de saída por segundo
Request throughput Requisições por segundo

Guarda esses nomes, porque eles são literalmente o que o benchmark do vLLM cospe na tela

E são eles que decidem se tua configuração ficou boa ou ruim, não o "feeling" de rodar um prompt e achar rápido

Antes de mexer na concorrência: o que você precisa ter pronto

Esse post assume que o modelo JÁ está de pé

Se tu ainda tá no passo anterior, de escolher máquina e subir o serviço, resolve isso primeiro: lá a pergunta é de hardware, aqui é de configuração

Checklist do que precisa estar na mão:

  • Modelo servido na VPS com vLLM ou Ollama
  • Acesso ao servidor pra editar variáveis de ambiente (Ollama) ou flags de inicialização (vLLM)
  • Dependências de benchmark do vLLM instaladas, se tu for medir nessa stack
pip install "vllm[bench]"

Duas coisas importantes antes de sair mexendo

Primeira: mudar esses parâmetros exige reiniciar o servidor. Não é hot reload, não é config que tu troca com o serviço no ar

Segunda, e essa é a que pega geral: MEDE ANTES

Se tu não tem o número de partida, tu não tem como saber se o ajuste melhorou ou piorou. Vai ficar no achismo, e achismo em benchmark é só opinião com terminal aberto

Tome cuidado com isso

Como configurar concorrência no vLLM: max_num_seqs, contexto e KV cache

A ordem importa aqui, porque cada parâmetro come memória do próximo

  1. Defina max_num_seqs, o teto real de concorrência

Esse parâmetro define o número máximo de sequências processadas em uma única iteração do scheduler

Traduzindo: é quantas requisições o servidor consegue ter avançando ao mesmo tempo

O default mudou entre versões: era 256 no vLLM V0 e passou pra 1024 no V1

vllm serve SEU_MODELO --max-num-seqs 64

O erro comum deste passo: subir max_num_seqs achando que é só "liberar mais usuários". Sem KV cache pra sustentar essas sequências, tu só empurra o problema pra frente, porque o tamanho do KV cache é o que limita quantas sequências concorrentes o vLLM consegue processar antes de estourar a memória

  1. Defina max_model_len, o teto de tokens por requisição

Esse limita o comprimento máximo de contexto do modelo, contando tokens de ENTRADA mais tokens GERADOS na mesma requisição

É prompt + saída somados, não só o prompt

vllm serve SEU_MODELO --max-num-seqs 64 --max-model-len 8192

O erro comum deste passo: pedir contexto gigante "por garantia" e derrubar a concorrência sem perceber. Como a necessidade de KV cache é função de max_num_seqs E max_model_len, contexto folgado demais rouba o espaço que você queria usar pra atender mais gente

  1. Ajuste gpu_memory_utilization

Esse define a fração da memória da GPU pré-alocada pelo engine, indo de 0.0 a 1.0, com default 0.9

E essa fração é exatamente o que determina o tamanho do KV cache

vllm serve SEU_MODELO \
  --max-num-seqs 64 \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.9

Então é aqui que o triângulo fecha: gpu_memory_utilization define o KV cache, e o KV cache é o recurso disputado por max_num_seqs e max_model_len

Mexeu num, os outros dois sentem

O erro comum deste passo: tratar os três como configurações separadas em abas diferentes da cabeça. Eles são um sistema só

  1. Ajuste max_num_batched_tokens conforme o OBJETIVO

Esse parâmetro define o máximo de tokens processados em uma única iteração, funcionando como orçamento de tokens por passo do scheduler

O default é 2048, e a doc do vLLM aponta esse valor como otimizado pra ITL, a latência entre tokens

E recomenda valores maiores que 2048 quando o objetivo é throughput

vllm serve SEU_MODELO --max-num-batched-tokens 4096

Repara que subir esse número não é "destravar performance", é uma ESCOLHA

Latência entre tokens boa (resposta fluindo suave pro usuário) ou volume total de tokens saindo do servidor? Dificilmente tu maximiza os dois ao mesmo tempo

O erro comum deste passo: subir o orçamento de tokens num caso de uso interativo e estranhar que a resposta ficou "mais travadinha" pro usuário final

  1. Entenda o chunked prefill antes de culpar a máquina

O chunked prefill quebra prefills grandes em pedaços e agrupa eles junto com requisições que já estão em decode

A política é clara: DECODE TEM PRIORIDADE

O scheduler agenda todas as requisições pendentes de decode antes de agendar prefill, e o prefill que não couber no orçamento de max_num_batched_tokens é fatiado

Isso explica um comportamento que parece esquisito: quem já tá recebendo tokens continua recebendo, enquanto quem acabou de chegar com um prompt enorme espera um pouquinho mais pro primeiro token

Não é lentidão aleatória, é política de agendamento

O erro comum deste passo: interpretar TTFT alto em prompt gigante como "VPS fraca" quando é o orçamento de tokens por iteração conversando com a prioridade de decode

Como configurar concorrência no Ollama: OLLAMA_NUM_PARALLEL e OLLAMA_MAX_QUEUE

No Ollama o controle é por variável de ambiente, o que deixa tudo mais simples de setar e MAIS FÁCIL de esquecer que existe

  1. OLLAMA_NUM_PARALLEL: requisições paralelas por modelo

Define o número máximo de requisições paralelas que cada modelo processa ao mesmo tempo

O FAQ oficial atual documenta o default como 1

Lê de novo: UM

export OLLAMA_NUM_PARALLEL=4

O erro comum deste passo: montar um produto com vários usuários em cima de um servidor que, na configuração de fábrica, processa uma requisição por vez naquele modelo

  1. Faça a conta de memória antes de subir esse número

A documentação do Ollama é explícita: a RAM necessária escala pelo PRODUTO OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH

O exemplo é da própria doc: um contexto de 2K com 4 requisições paralelas resulta em 8K de contexto e alocação adicional de memória

Então paralelismo não é de graça, ele multiplica contexto

É a mesma lógica do KV cache do vLLM, só que exposta de um jeito diferente

O erro comum deste passo: subir OLLAMA_NUM_PARALLEL sem revisar o contexto, e aí a memória some sem explicação aparente

  1. OLLAMA_MAX_QUEUE: a fila quando o servidor tá ocupado

Essa define o número máximo de requisições que o servidor enfileira quando está ocupado, antes de RECUSAR novas requisições

O default é 512

export OLLAMA_MAX_QUEUE=512

E quando estoura? O servidor responde com HTTP 503, indicando servidor sobrecarregado

Esse 503 é informação valiosa, não é só erro chato: é o teu servidor avisando exatamente onde bateu o teto

O erro comum deste passo: inflar a fila achando que resolve. Fila maior não processa mais rápido, ela só troca "erro na cara do usuário" por "usuário esperando muito tempo". Às vezes o 503 honesto é melhor

  1. OLLAMA_MAX_LOADED_MODELS: quantos modelos ficam na memória

Define o máximo de modelos carregados simultaneamente, desde que caibam na memória disponível

O default é 3 × número de GPUs, ou 3 na inferência em CPU

export OLLAMA_MAX_LOADED_MODELS=2

E aqui tem um comportamento que confunde MUITO na hora do debug: se não houver memória suficiente pra carregar um novo modelo enquanto outros já estão carregados, o Ollama enfileira TODAS as novas requisições até que o novo modelo possa ser carregado

O espaço vai liberando conforme modelos anteriores ficam ociosos e são descarregados

O erro comum deste passo: ver requisições paradas na fila e sair mexendo em OLLAMA_NUM_PARALLEL, quando o problema real era memória pra carregar mais um modelo

Como medir: benchmark com vllm bench serve e os campos de timing do Ollama

Agora a parte que separa configuração de ACHISMO

Medindo no vLLM

O vLLM traz comandos de benchmark no próprio CLI: vllm bench latency, vllm bench serve e vllm bench throughput

Pra carga concorrente de serving online, o que interessa é o vllm bench serve: o servidor roda com vllm serve e o cliente roda vllm bench serve

Dois processos, duas pontas

# terminal 1: servidor
vllm serve SEU_MODELO

# terminal 2: cliente de benchmark
vllm bench serve --request-rate 10 --max-concurrency 32

As flags que moldam o padrão de carga, segundo a doc:

  • --request-rate: requisições por segundo alvo, ou inf pra buscar throughput máximo
  • --burstiness: variabilidade do tráfego, via distribuição Gamma
  • --max-concurrency: limita o número de requisições concorrentes em aberto

A sacada é usar essas três pra IMITAR o teu tráfego real, não pra gerar o número mais bonito possível

Tráfego de produto não chega em ritmo constante de metrônomo, ele chega em rajada. Por isso --burstiness existe

O que ler na saída:

Campo Pra que serve
Mean / Median / P99 TTFT (ms) Quanto o usuário espera pelo primeiro token, incluindo o pior caso
Request throughput (req/s) Requisições atendidas por segundo
Output token throughput (tok/s) Volume de tokens saindo do servidor
TPOT Tempo por token de saída
ITL Latência entre tokens

Repara no P99 de TTFT

A média engana: dá pra ter média linda e uma fatia dos usuários esperando um tempão. O P99 é quem conta essa história

O erro comum deste passo: rodar o benchmark com carga de uma requisição só e concluir que a VPS "aguenta". Requisição única não testa scheduler, não testa fila e não testa KV cache sob pressão

Medindo no Ollama

Aqui o caminho documentado é diferente: as respostas da API do Ollama trazem campos de medição de desempenho embutidos

São eles: total_duration, load_duration, prompt_eval_count, prompt_eval_cached_count, prompt_eval_duration, eval_count e eval_duration

Detalhe que já derrubou muita conta errada: os valores de tempo vêm em NANOSSEGUNDOS

Esses campos são retornados por endpoints incluindo /api/generate, /api/chat e /api/embed

curl http://localhost:11434/api/generate -d '{
  "model": "SEU_MODELO",
  "prompt": "Explique o que e batching continuo",
  "stream": false
}'

Com eval_count (tokens gerados) e eval_duration (tempo de geração) tu deriva os tokens por segundo do TEU ambiente

E é isso que vale: número do teu hardware, do teu modelo, da tua configuração

O erro comum deste passo: pegar tokens por segundo de um post aleatório, com outra GPU, outra quantização e outro tamanho de contexto, e usar como meta. Comparação de hardware diferente não é benchmark, é folclore

Quantos usuários seu cenário pede: time interno, produto com picos e lote

Não existe configuração universal porque não existe carga universal

O que existe é: qual métrica o TEU cenário precisa otimizar

Time interno, poucos usuários

Aqui a prioridade é TTFT baixo e ITL confortável

São poucas pessoas, cada uma quer sentir a resposta começando rápido e fluindo. Throughput total é secundário, ninguém tá processando volume

É o cenário onde o orçamento de tokens por iteração otimizado pra ITL faz mais sentido

Produto exposto, tráfego irregular

Esse é o mais traiçoeiro

O tráfego chega em rajada, e o que quebra a experiência não é a média, é a CAUDA: o P99 de TTFT e o comportamento da fila quando o pico bate

Aqui tu precisa simular a rajada antes dela acontecer de verdade, com --burstiness e --max-concurrency no vllm bench serve

E no Ollama, saber exatamente quando começa o 503 é parte do dimensionamento, não um acidente

Vale lembrar que rajada também expõe outras camadas da infra. Se tua base de usuários tá longe da máquina, a escolha do datacenter da VPS entra na conta da latência percebida junto com o TTFT do modelo

Processamento em lote

Ninguém tá olhando a tela esperando token aparecer

A prioridade vira output token throughput: quantos tokens de saída por segundo a máquina consegue cuspir no total

É o cenário onde a doc do vLLM recomenda orçamento de tokens por iteração maior que 2048

Resumindo o raciocínio:

Cenário Métrica principal O que ajustar com esse objetivo
Time interno TTFT e ITL Orçamento de tokens por iteração voltado a ITL
Produto com picos P99 de TTFT e fila Simular com --burstiness e --max-concurrency, revisar fila
Lote Output token throughput Orçamento de tokens por iteração maior

Sinais de que sua VPS estourou o limite de concorrência

Sintoma, causa configurável e prevenção. Sem adivinhação

Sintoma: HTTP 503 no Ollama

Causa: a fila encheu. O Ollama responde 503 indicando servidor sobrecarregado quando requisições demais são enviadas

Onde olhar: OLLAMA_MAX_QUEUE (default 512) e OLLAMA_NUM_PARALLEL (default 1 no FAQ atual)

Prevenção: revisar o paralelismo por modelo ANTES de inflar a fila, lembrando que RAM escala pelo produto de paralelismo por contexto

Sintoma: requisições enfileiradas e paradas, sem 503

Causa provável: memória insuficiente pra carregar um novo modelo enquanto outros já estão carregados. Nesse caso o Ollama enfileira todas as novas requisições até liberar espaço, o que acontece conforme modelos anteriores ficam ociosos e são descarregados

Onde olhar: OLLAMA_MAX_LOADED_MODELS (default 3 × número de GPUs, ou 3 em CPU)

Prevenção: limitar quantos modelos distintos o servidor precisa manter vivos ao mesmo tempo

Sintoma: erro de memória ao subir o vLLM com contexto e concorrência altos

Causa: o triângulo do KV cache. A necessidade de KV cache é função de max_num_seqs e max_model_len, e o tamanho disponível é determinado por gpu_memory_utilization

Prevenção: mexer num parâmetro por vez e medir. Se precisa de mais concorrência, alguma coisa precisa ceder: contexto por requisição ou memória alocada

Sintoma: TTFT alto com throughput até que bom

Causa: orçamento de tokens por iteração e chunked prefill. O scheduler prioriza decode, agenda todas as pendentes de decode antes do prefill, e fatia o prefill que não couber no orçamento de max_num_batched_tokens

Prevenção: se o cenário é interativo, lembrar que o default de 2048 é otimizado pra ITL e que subir esse orçamento é uma escolha por throughput

Ou seja: throughput bom com TTFT alto pode ser exatamente a configuração fazendo o que tu pediu

Pra ver IA aplicada ao código na prática

Pra quem quer expandir o uso de IA no dia a dia de desenvolvimento além da infraestrutura, este vídeo do canal mostra uma skill que faz a IA ler seu código e desenhar a arquitetura sozinha

Conclusão

Capacidade concorrente não sai de tabela pronta

Sai de duas coisas: CONFIGURAÇÃO (os parâmetros certos, entendendo que eles disputam o mesmo recurso) e MEDIÇÃO (número do teu ambiente, não de um post com hardware diferente)

No vLLM tu tem max_num_seqs como teto de concorrência, max_model_len como teto de tokens por requisição, gpu_memory_utilization definindo o KV cache e max_num_batched_tokens como orçamento por iteração

No Ollama tu tem OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE, OLLAMA_MAX_LOADED_MODELS e a conta de memória que multiplica paralelismo por contexto

Próximo passo é simples e chato do jeito certo: roda o benchmark na tua própria VPS ANTES e DEPOIS de cada ajuste

Registra TTFT e tokens por segundo em cada rodada, muda um parâmetro por vez

Em duas ou três iterações tu vai saber, com número na mão, quantos usuários simultâneos tua máquina atende de verdade

E se a conclusão for que o gargalo não é configuração e sim hardware, aí a conversa volta pro dimensionamento: vale olhar o dimensionamento dos planos de VPS com o número real do teu benchmark em mãos, e não no chute

Bora medir? 🙂

até o próximo post!

Perguntas frequentes

Qual a diferença entre max_num_seqs e max_num_batched_tokens no vLLM?

max_num_seqs limita quantas sequências o scheduler processa em uma iteração, ou seja, o teto de concorrência. max_num_batched_tokens limita quantos tokens no total cabem nessa mesma iteração, funcionando como orçamento de tokens por passo, com default de 2048, valor que a documentação aponta como otimizado para ITL. São dois limites diferentes disputando o mesmo passo do scheduler.

OLLAMA_NUM_PARALLEL alto sempre melhora o atendimento simultâneo?

Não necessariamente. O default é 1, e a documentação do Ollama mostra que a RAM necessária escala pelo produto OLLAMA_NUM_PARALLEL vezes OLLAMA_CONTEXT_LENGTH. Subir o paralelismo sem memória sobrando esbarra no mesmo problema de recurso disputado que acontece no KV cache do vLLM.

O que acontece quando o Ollama recebe mais requisições do que consegue enfileirar?

O Ollama enfileira as requisições até o limite de OLLAMA_MAX_QUEUE, cujo default é 512. Quando esse teto estoura, o servidor responde com erro HTTP 503 indicando que está sobrecarregado.

Rodar dois modelos ao mesmo tempo no Ollama reduz a concorrência de cada um?

Pode reduzir, porque são dois níveis de concorrência disputando a mesma memória: modelos carregados simultaneamente (controlado por OLLAMA_MAX_LOADED_MODELS, default 3 vezes o número de GPUs, ou 3 em CPU) e requisições paralelas dentro de cada modelo. Se não houver memória pra carregar um novo modelo, o Ollama enfileira as novas requisições até liberar espaço.

Como simular tráfego real de vários usuários ao medir throughput no vLLM?

O vllm bench serve tem as flags –request-rate para definir requisições por segundo alvo, –burstiness para simular variabilidade via distribuição Gamma e –max-concurrency para limitar requisições concorrentes em aberto. Combinadas, elas aproximam o benchmark de um padrão de uso real em vez de disparar tudo de uma vez.

Quais campos da resposta do Ollama mostram o tempo gasto em cada requisição?

A API do Ollama retorna total_duration, load_duration, prompt_eval_count, prompt_eval_cached_count, prompt_eval_duration, eval_count e eval_duration, todos em nanossegundos. Esses campos aparecem em endpoints como /api/generate, /api/chat e /api/embed, e servem pra medir desempenho sem depender de ferramenta externa.




Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

Blog | Mais populares