SSD Nodes Learn 🎉 VPS desde $4.99/mes
Guías Matt ConnorPor Matt Connor

Por qué tu LLM autohospedado se atasca con 5 usuarios

Con un usuario funciona, pero cinco esperan. Descubre cómo batching, caché KV, prefill y la cola determinan cuántas solicitudes atiende tu servidor LLM.

¿Por qué un LLM autohospedado se ralentiza cuando llegan más usuarios?

Un LLM autohospedado se bloquea con 5 usuarios simultáneos porque el servidor todavía genera una respuesta cada vez y los otros cuatro esperan en una cola. La documentación de Ollama es clara sobre el valor predeterminado: OLLAMA_NUM_PARALLEL es «el número máximo de solicitudes paralelas que cada modelo procesa al mismo tiempo; el valor predeterminado es 1». No hay ningún fallo. Cuatro de las cinco personas están esperando su turno.

La solución rara vez consiste en usar un servidor más potente. Consiste en utilizar un motor de servicio que procese muchas solicitudes en el mismo paso de propagación hacia delante del modelo y disponga de memoria libre suficiente para mantener las conversaciones de todos mientras lo hace. Ambas partes son importantes, pero la segunda es la que realmente establece el límite.

Las dos fases por las que pasa cada petición

Prefill lee todo el prompt de una vez y construye la caché de atención correspondiente. Todos los tokens del prompt pasan juntos por el modelo, por lo que prefill es una multiplicación de matrices grande y está limitado por el rendimiento aritmético. Decode escribe la respuesta un token cada vez. Para cada token, debe volver a leer de la memoria todos los pesos del modelo, mientras que las operaciones aritméticas realizadas sobre ese único token son mínimas. Decode está limitado por el ancho de banda de memoria.

Esta asimetría es la razón principal por la que el procesamiento por lotes funciona. La decodificación para un usuario lee, por ejemplo, 5 GB de pesos por token y deja inasignada la mayor parte de las unidades aritméticas. Si se añade una segunda petición, el motor lee los mismos 5 GB una sola vez y después calcula dos tokens con ellos. El segundo usuario apenas añade tiempo. Atender las peticiones estrictamente una tras otra desperdicia esa ventaja.

Dos valores describen lo que percibe el usuario. TTFT (tiempo hasta el primer token) es la espera en la cola más prefill. ITL (latencia entre tokens) es el intervalo entre los tokens transmitidos y depende de decode. Un servidor lento suele serlo por uno de estos valores, y las soluciones no son las mismas.

El batching estático hace que todos esperen a la respuesta más lenta

El batching estático es la versión más sencilla. Es lo que se obtiene al agrupar las solicitudes manualmente en el código de la aplicación. El motor recopila N solicitudes, las ejecuta juntas y mantiene cada slot ocupado hasta que termina la generación más larga del grupo.

Un usuario que solicita un resumen de 1,200 tokens mantiene bloqueadas en el batch cuatro respuestas de una sola línea, porque el batch no libera ningún slot hasta que termina su miembro más lento.

Esto genera dos costes. Las secuencias terminadas siguen ocupando slots sin realizar ningún cálculo útil. Por tanto, el rendimiento efectivo disminuye cuando varía la longitud de las salidas, y las longitudes de salida del chat varían mucho. Una solicitud que llega un paso después de formarse el batch espera a que se procese todo el batch antes de iniciar siquiera el prefill. Esto significa que su TTFT queda determinado por el texto largo de otro usuario.

El batching continuo admite y retira solicitudes en cada token

El batching continuo planifica cada paso de decodificación por separado. Después de cada paso, el planificador retira las secuencias que acaban de emitir su token de parada y admite las solicitudes en espera en los espacios libres. Una respuesta que termina en el paso 40 libera su espacio en el paso 40, no al final de un batch.

Esto no es algo exótico. llama-server documenta -cb, --cont-batching como «si se debe activar el batching continuo (también llamado batching dinámico; valor predeterminado: activado)», y vLLM se basa en esta idea. Ollama también atiende solicitudes en paralelo. El valor predeterminado simplemente limita el número a uno. Por eso muchas personas concluyen que su hardware no admite concurrencia, cuando en realidad es su configuración la que la desactiva.

Los resultados publicados sobre batching continuo suelen medirse en tarjetas de centros de datos que tienen capacidad de cómputo disponible y decenas de gigabytes para la caché. La tendencia de esos resultados se aplica también a su equipo. Sus valores absolutos no, y la sección sobre memoria explica el motivo.

El prefill compite con el decode por los mismos recursos de cómputo

Cuando llega una solicitud nueva mientras se están transmitiendo cuatro respuestas, primero hay que procesar su prompt con prefill, y el prefill consume mucho cómputo. Si el planificador asigna a ese prefill un paso propio, los cuatro usuarios que reciben texto en streaming no obtienen ningún token durante ese paso. Con un prompt largo, esto provoca una pausa visible en todas las ventanas abiertas. Este es el tartamudeo al que se refieren los usuarios cuando dicen que el servidor da tirones cada vez que otra persona pulsa enviar.

El prefill por fragmentos divide un prompt largo en varias partes y mezcla cada parte en el mismo paso que los procesos decode en ejecución. La guía de ajuste de vLLM explica directamente la compensación: los presupuestos de fragmentos más pequeños «logran un mejor ITL porque hay menos procesos prefill que ralenticen el decode», mientras que los valores más altos «logran un mejor tiempo hasta el primer token (TTFT), ya que permiten procesar más tokens prefill en un lote». Debe decidir qué experiencia quiere proteger: la de la persona que espera a que empiece la respuesta o la de quienes observan cómo se transmite el texto.

La longitud del prompt determina cuánto afecta este problema. Un prompt de 6,000 tokens con una respuesta de 200 tokens supone 6,000 tokens de trabajo prefill frente a 200 pasos decode. El chat con generación aumentada mediante recuperación y los prompts de sistema largos suelen llevarle a ese escenario. Por eso, el prefill deja de ser un coste insignificante y se convierte en aquello que los usuarios esperan. La caché de prefijos ayuda cuando se repite la parte larga: vLLM expone --enable-prefix-caching, que reutiliza la caché de un prefijo de prompt compartido en lugar de recalcularlo para cada solicitud.

La memoria que se agota primero es la caché KV

Cada token de cada conversación activa deja un vector de clave y un vector de valor en cada capa del modelo. Esa es la caché KV (caché de clave/valor), y permite que la fase de decodificación no tenga que volver a calcular todo el prompt para cada token nuevo. Su tamaño por token está determinado por la arquitectura del modelo: 2 (una clave y un valor) por el número de capas, por el número de cabezas de clave/valor, por la dimensión de cada cabeza y por los bytes de cada valor. Consulte esos números en config.json del modelo.

Haga el cálculo una vez y el límite dejará de ser un misterio. Un modelo 8B típico con 36 capas, 8 cabezas de clave/valor y una dimensión de cabeza de 128, que mantiene la caché en 16 bits, consume 2 36 8 128 2 bytes por token. Son 147,456 bytes, aproximadamente 144 KiB. Una conversación de 8,192 tokens necesita, por tanto, aproximadamente 1.2 GB de caché. Cinco conversaciones necesitan aproximadamente 6 GB, además de los pesos. Esa es la respuesta real a cuántos usuarios caben.

La concurrencia multiplica el contexto, y las herramientas lo indican explícitamente. La FAQ de Ollama dice: "El procesamiento paralelo de solicitudes para un modelo determinado aumenta el tamaño del contexto según el número de solicitudes paralelas. Por ejemplo, un contexto de 2K con 4 solicitudes paralelas dará como resultado un contexto de 8K y una asignación de memoria adicional." La RAM necesaria escala según OLLAMA_NUM_PARALLEL multiplicado por OLLAMA_CONTEXT_LENGTH. En llama-server, el contexto que solicita con -c se reparte entre los -np slots, por lo que aumentar por sí solo el número de slots reduce lo que puede contener cada solicitud. Consulte el contexto por slot en el log de inicio en lugar de asumirlo.

vLLM preasigna la memoria. --gpu-memory-utilization (valor predeterminado: 0.92) es "la fracción de la memoria de GPU que utilizará el ejecutor del modelo". Lo que queda después de cargar los pesos se convierte en el pool KV paginado. Cuando ese pool se queda sin espacio, el scheduler expulsa una solicitud en lugar de producir un error:

WARNING 05-09 00:49:33 scheduler.py:1057] Sequence group 0 is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space.

En el motor V1 de vLLM, el modo de preempción predeterminado es RECOMPUTE. Por tanto, una solicitud expulsada descarta su caché y vuelve a ejecutar el prefill cuando se admite de nuevo. Ese trabajo se realiza dos veces. La documentación advierte que "la preempción y el recálculo pueden afectar negativamente a la latencia de extremo a extremo". Esta línea del log es la mejor explicación de por qué un usuario desafortunado esperó mucho más que los demás mientras el promedio parecía normal. Configure disable_log_stats=False para registrar el contador acumulado o lea el contador de preempción en las métricas de Prometheus que expone vLLM.

Qué cambia con 2, 5 y 20 usuarios simultáneos

Dos usuarios. En una GPU con caché disponible, el impacto es casi imperceptible, porque el segundo flujo de decodificación se ejecuta junto al primero con muy poco tiempo adicional. En una VPS con sólo CPU y entre 4 y 8 GB de RAM no es gratis: ambos flujos comparten los mismos pocos vCPU y el mismo ancho de banda de memoria RAM. Por eso, cada usuario obtiene aproximadamente la mitad de tokens por segundo y la demanda de caché se duplica frente a un presupuesto mucho menor.

Cinco usuarios. Aquí los valores predeterminados dejan de ser suficientes y el problema empieza como una cuestión de cola. Con OLLAMA_NUM_PARALLEL en 1, cuatro personas esperan a quien haya solicitado la respuesta larga, y cada una recupera la velocidad normal cuando llega su turno. Si aumenta el número de ejecuciones en paralelo, el problema cambia: cinco ranuras con un contexto de 8K cada una requieren localizar una caché de 40K tokens. Si no cabe en la VRAM, el motor descarga capas en la RAM del sistema. Si tampoco cabe en la RAM, el equipo usa swap y los tokens por segundo se desploman.

Veinte usuarios. Veinte personas en una interfaz de chat normalmente no equivalen a veinte solicitudes simultáneas. Esto es lo más importante que debe entender antes de comprar hardware. Una persona lee una respuesta y tarda entre 20 y 60 segundos en enviar el siguiente mensaje, por lo que la mayor parte de su sesión está inactiva. Veinte agentes o veinte trabajos de resumen de documentos sí representan veinte flujos reales sin ningún tiempo de inactividad. Es una máquina diferente.

¿Sus usuarios son concurrentes o sólo han iniciado sesión?

Calcule las solicitudes en curso antes de dimensionar nada. La aritmética es sencilla: solicitudes en curso equivale a usuarios por los segundos dedicados a generar cada turno, dividido entre los segundos entre turnos.

  1. Mida primero la velocidad de su propio flujo individual, tanto el prefill como el decode. No use un valor de la tarjeta de otra persona: mida los tokens por segundo en su propio equipo y use el resultado.
  2. Estime el ciclo de actividad. Veinte usuarios de chat, 12 segundos de generación por turno y un turno cada 90 segundos dan 20 * 12 / 90, es decir, aproximadamente 2.7 solicitudes en curso.
  3. Establezca el número de slots un poco por encima de ese valor y, después, compárelo con la memoria: los slots multiplicados por el contexto de cada solicitud deben caber en los tokens de caché disponibles.
  4. Mantenga corta la cola para que el exceso falle rápido y de forma visible.

Los tokens de caché disponibles son la memoria libre después de cargar los pesos, dividida entre el coste por token de la sección anterior. Una tarjeta de 24 GB que ejecuta un modelo 8B en 16-bit utiliza aproximadamente 16 GB para los pesos y tiene unos 6 GB de caché utilizable con la utilización predeterminada, lo que permite alrededor de cinco conversaciones de 8K. Para admitir más conversaciones, reduzca el contexto de cada solicitud o almacene la caché en 8-bit (llama-server ocupa --cache-type-k q8_0). Ambas opciones aumentan la concurrencia a cambio de renunciar a algo. Conviene leer la explicación completa de ese compromiso antes de invertir dinero en hardware: cuándo un GPU VPS alcanza el punto de equilibrio frente a los tokens de API.

Cuando los valores predeterminados de Ollama dejan de ser suficientes

Aumente el número de solicitudes en paralelo mediante la unidad del servicio, porque una variable exportada en el shell no llegará a un daemon gestionado por systemd.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_CONTEXT_LENGTH=8192"
Environment="OLLAMA_MAX_QUEUE=64"
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment
ollama ps

systemctl show debe mostrar las tres variables que acaba de establecer. Si no lo hace, el archivo drop-in no se guardó y nada de lo que haga después tendrá efecto. ollama ps muestra el modelo cargado con un tamaño superior al de los pesos por sí solos, porque cuatro slots de 8,192 tokens reservan 32,768 tokens de caché además de ellos. Si la columna PROCESSOR muestra parte del modelo en la CPU cuando esperaba que todo estuviera en la GPU, significa que solicitó más caché de la que quedaba disponible en la tarjeta. Reduzca uno de los dos valores.

Conviene revisar de nuevo el valor predeterminado de la cola. Ollama pone en cola hasta OLLAMA_MAX_QUEUE solicitudes y «el valor predeterminado es 512». Después de ese límite, responde «con un error 503 que indica que el servidor está sobrecargado». Una cola de 512 solicitudes en un equipo que procesa cuatro a la vez es una promesa que no puede cumplir, porque el cliente que ocupa la posición 300 agotará el tiempo de espera mucho antes de que llegue su turno. Una cola corta devuelve un error que la aplicación puede reintentar o notificar. Esto es preferible a mostrar un indicador de espera que nunca termina.

Pruébelo en condiciones reales. Envíe dos solicitudes al mismo tiempo desde dos terminales y observe ambas. Si la segunda no produce ninguna salida hasta que termina la primera, el ajuste de paralelismo no se aplicó.

Cuándo un motor de inferencia real empieza a compensar

vLLM compensa la configuración adicional cuando tiene una GPU con margen disponible y más de unas cuatro solicitudes realmente en curso. Su planificador trabaja por token, su caché está paginada para reutilizar los fragmentos libres y convierte la VRAM disponible en concurrencia en lugar de dejarla inactiva. En agosto de 2026, la instalación y el inicio documentados requieren dos comandos:

uv pip install vllm --torch-backend=auto
vllm serve Qwen/Qwen2.5-1.5B-Instruct
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "Qwen/Qwen2.5-1.5B-Instruct",
        "messages": [{"role": "user", "content": "Say hello."}]
    }'

Una respuesta que contiene una matriz choices indica que el servidor está activo y que el modelo se ha cargado. Durante la carga, los dos parámetros importantes son --max-num-seqs, el «número máximo de secuencias que se procesan en una sola iteración», y --max-num-batched-tokens, el «número máximo de tokens que se pueden procesar en una sola iteración». El primero limita la concurrencia. El segundo establece el presupuesto de prellenado por bloques descrito anteriormente.

Con menos de unas cuatro solicitudes en curso, o en cualquier equipo sin una GPU compatible, vLLM añade complejidad y ofrece pocos beneficios. Requiere una tarjeta de clase CUDA y reserva la mayor parte de la memoria al iniciar, lo que no es una buena elección en un VPS de 4 a 8 GB. En ese caso, la opción adecuada es un modelo más pequeño, con un contexto más corto y una cola bajo su control. diferencias entre Ollama y vLLM como motores de inferencia explica la elección en detalle, y ejecutar Qwen 3 8B en un VPS muestra qué recursos exige un modelo de tamaño medio antes de añadir un solo usuario más.

El batching continuo aumenta el rendimiento total y normalmente también mejora la latencia mediana, porque una petición en cola empieza antes. La latencia de cola evoluciona en sentido contrario, y esa parte rara vez se menciona.

Cada secuencia adicional en un paso añade algo de trabajo, por lo que el ITL aumenta para todos a medida que se llena el batch. El prefill de una nueva petición ocupa una parte de un paso que, de otro modo, habrían usado los usuarios con streaming. Bajo presión de caché, el planificador interrumpe tareas, lo que devuelve una petición a medio generar al inicio de su prefill.

Una interfaz de chat muestra las colas, no los promedios. Un stream que se pausa durante dos segundos a mitad de una frase parece roto, aunque el tiempo total hasta completar la respuesta sea bueno. Mida el TTFT p95 y el ITL p95 con la carga prevista, y trate la media de tokens por segundo como una cifra de capacidad, no como una descripción de la experiencia.

El ajuste práctico se deriva de esto. Limite la concurrencia ligeramente por debajo de lo que permite la memoria, para que el motor nunca tenga que interrumpir tareas. Una cola corta y predecible es mejor que un batch profundo que genere inestabilidad, porque un usuario que espera cuatro segundos y después recibe un stream fluido estará más satisfecho que uno que empieza al instante y sufre dos pausas.

Qué comprobar cuando funciona lento

Cada usuario está en condiciones normales, pero la espera es larga. Eso es una cola, no un problema de velocidad. Compruebe primero el ajuste de paralelismo. El modelo responde correctamente, una solicitud cada vez.

Ollama devuelve HTTP 503. La cola está llena. El equipo está realmente al límite de capacidad o OLLAMA_MAX_QUEUE está configurado con un valor bajo a propósito para descartar carga, que es precisamente su función.

Los tokens por segundo se desploman bajo carga en un equipo con CPU. Ejecute vmstat 1 mientras ocurre. Si las columnas si y so tienen valores distintos de cero, el equipo está usando swap. Por eso los pesos se leen del disco con cada token. Ningún cambio de configuración resuelve esto. Reduzca el tamaño del modelo o el número de slots.

Uno de cada diez usuarios espera mucho más que los demás. Busque preempted en el registro de vLLM. La causa habitual es la expulsión preventiva y su recomputación. Esto significa que la caché está sobredimensionada para la longitud de contexto permitida.

El TTFT es deficiente incluso cuando el servidor está inactivo. Eso es un problema de prefill, no de concurrencia. Los prompts largos requieren tiempo real antes de mostrar el primer token. Revise el tamaño del prompt y la caché de prefijos antes de revisar el hardware.

FAQ

¿Por qué mi LLM autoalojado se ralentiza cuando lo usa una segunda persona?

En la mayoría de los casos no se ralentiza. Se pone en cola. Ollama se distribuye con OLLAMA_NUM_PARALLEL establecido en 1, por lo que la segunda solicitud espera a que la primera emita su token final. Distinga ambos casos midiendo el flujo de salida de un usuario mientras otro espera: si la velocidad de tokens por segundo es normal cuando empieza, tiene una cola y aumentar el número de solicitudes paralelas lo corrige. Si ambos flujos funcionan a la mitad de velocidad, realmente están compartiendo el ancho de banda de memoria y ese es un límite del hardware.

¿Cuántos usuarios simultáneos puede atender una GPU pequeña?

Cuente la memoria, no los usuarios. Primero los pesos y después la caché KV, cuyo coste por token y por conversación activa es 2 veces el número de capas por el número de cabezas de clave/valor por la dimensión de la cabeza por el número de bytes. Un modelo 8B típico, con 36 capas, 8 cabezas de clave/valor y una dimensión de cabeza de 128, consume aproximadamente 144 KiB por token en 16 bits, por lo que una conversación de 8,192 tokens necesita aproximadamente 1.2 GB. Una tarjeta de 24 GB que aloje ese modelo en 16 bits tendrá unos 6 GB disponibles para la caché. Esto equivale aproximadamente a cinco conversaciones con el contexto completo, o a más conversaciones si reduce el contexto.

¿El batching continuo hace que la respuesta de cada usuario sea más lenta?

La latencia mediana suele mejorar porque las solicitudes dejan de esperar a que termine todo un lote. La latencia de cola empeora. Cada secuencia adicional añade trabajo a cada paso de decodificación, la fase prefill de una nueva solicitud ocupa parte de un paso que correspondía a los usuarios que reciben el flujo y una solicitud interrumpida debe ejecutar prefill dos veces. Mida la latencia p95 entre tokens, no la media, porque una ventana de chat hace visibles las pausas de una forma que los promedios pueden ocultar.

¿Debo aumentar OLLAMA_NUM_PARALLEL o cambiar a vLLM?

Aumente primero el número de solicitudes paralelas. No tiene coste y requiere un solo archivo que puede sustituirse directamente. Esto corrige el caso habitual en el que cuatro personas esperan en cola detrás de una respuesta larga. La memoria es el límite: las solicitudes paralelas multiplican el contexto que debe mantener, así que compruebe si algunas capas pasan a la CPU. Cambie a vLLM cuando tenga una GPU con VRAM disponible y más de unas cuatro solicitudes realmente activas, porque a partir de ese punto la caché paginada y la planificación por token ofrecen más beneficios de los recursos que consumen.

¿Más núcleos de CPU solucionarán un servidor LLM lento?

No en la parte que más perciben los usuarios. La decodificación lee todo el modelo desde la memoria para cada token, por lo que está limitada por el ancho de banda de la RAM. Los núcleos adicionales dejan de ayudar cuando se satura ese ancho de banda. La fase prefill sí escala con los núcleos, por lo que tener más núcleos reduce el tiempo hasta el primer token en prompts largos. En una VPS de 4 a 8 GB, la restricción principal suele ser la capacidad de memoria. La solución efectiva suele ser un modelo más pequeño o un contexto más corto, no más vCPU.

#vllm#ollama#batching#throughput#self-hosted-ai