Clústeres de inferencia: vLLM Tensor Parallel, Pipeline Parallel y lo que realmente le cuesta cada uno
Un modelo de la clase 70B no cabe en una sola GPU con ninguna cuantización que deje caché KV útil. Un modelo de 405B no cabe en un solo nodo. A partir de ahí, la pregunta ya no es «qué GPU», sino «cómo reparto el modelo entre las GPU que tengo y qué me cuesta cada reparto».
Este artículo cubre las cuatro formas en que vLLM permite trocear un modelo —paralelismo de tensores, de pipeline, de expertos y de datos—, qué hace cada una con su factura de ancho de banda y cómo elegir entre ellas en la gama de Kentino (5090 conectadas por PCIe, RTX Pro 6000 Blackwell, L40, L4; sin piezas SXM con malla NVLink). Damos por hecho que ha leído I01, que sabe qué es vLLM y que ahora necesita tomar decisiones de configuración.
Las cuatro dimensiones para trocear un modelo
Todo framework de inferencia distribuida —vLLM, SGLang, TensorRT-LLM, Triton— expone alguna combinación de los mismos cuatro ejes. No son alternativas: se combinan.
| Eje | Qué divide | Comunicación por token | ¿Sensible al ancho de banda? | Impacto en la latencia |
|---|---|---|---|---|
| Paralelismo de tensores | Cada capa (fragmentos de matmul) | All-reduce por capa (×2) | Sí, mucho | Reduce la latencia |
| Paralelismo de pipeline | Capas repartidas en etapas | Activaciones en cada frontera de etapa | No, poca | Añade latencia, sube el rendimiento |
| Paralelismo de expertos | Expertos MoE entre GPU | All-to-all por capa MoE | Sí, a ráfagas | Depende del modelo |
| Paralelismo de datos | Réplicas completas, independientes | Ninguna durante la inferencia | No | Misma latencia, N× de rendimiento |
La tercera columna lo es todo. El TP grita por el bus en cada capa. El PP susurra entre dos etapas. Ese único hecho decide si mantiene el TP dentro de una máquina, si lleva el PP entre nodos y dónde cae la frontera.
Paralelismo de tensores: cómo funciona de verdad
En TP, cada matriz de pesos del transformador (QKV de atención, salida de atención, FFN de subida, FFN de bajada) se reparte entre tensor_parallel_size GPU. Cada GPU guarda un fragmento de cada capa y calcula un fragmento de cada activación. Como la atención y la FFN contienen matmuls que necesitan la activación completa reensamblada antes de la siguiente operación (softmax, SwiGLU), los resultados parciales deben combinarse. vLLM lo hace con un all-reduce al final de la atención y otro al final de la FFN: dos por bloque del transformador.
Llama 3.3 70B tiene 80 capas y un tamaño oculto de 8192. Con lotes de 32 en decodificación, cada all-reduce mueve unos 512 KB, ×160 por token generado → unos 80 MB por token a través del bus. El prefill es dramáticamente peor: un prefill de 4 K con lotes de 32 empuja del orden de 300 GB por el anillo de all-reduce en una sola pasada hacia delante.
Ese número es la razón de que al TP le encante NVLink. El NVLink de las SXM H100/B200 da 900 GB/s. PCIe Gen 5 x16 son 64 GB/s unidireccionales, 128 GB/s bidireccionales en el mejor caso, que rara vez se da en una placa de 4 GPU (las líneas suelen compartirse, véase W02). Esa diferencia de 14× a 28× aparece en los benchmarks: la eficiencia de escalado con NVLink ronda 0.92× por tarjeta y con PCIe 0.70–0.78× por tarjeta en modelos de la clase 70B.
Consecuencia práctica: el TP escala bien hasta 4 GPU en un nodo PCIe Gen 5. Más allá, el all-reduce cuesta más de lo que ahorra el paralelismo y conviene recurrir al paralelismo de pipeline.
Configuración de vLLM: tensor_parallel_size
--tensor-parallel-size N le dice al motor que reparta cada tensor de pesos entre N GPU del nodo local. Restricciones:
-
Ndebe dividir el número de cabezas de atención del modelo (Llama 70B tiene 64 cabezas → N ∈ {1, 2, 4, 8, 16, 32, 64}). - vLLM coloca los rangos de TP en el mismo nodo y da por supuesto un bus interno rápido.
- La caché KV se reparte a lo largo de la dimensión de cabezas: cada GPU guarda el equivalente a
total_heads / Ncabezas. Un TP mayor deja más margen de KV por petición.
En hardware Kentino: TP=4 en un equipo con 4× RTX 5090 o 4× RTX Pro 6000 Blackwell es el punto dulce. TP=8 funciona, pero el bus PCIe se resiente; normalmente le irá mejor TP=4 × PP=2 dentro de un equipo de 8 GPU.
Paralelismo de pipeline: la opción de «al otro lado de la sala»
El PP divide el modelo por profundidad. Con pipeline_parallel_size=2, la GPU 0 alberga las capas 0–39 de un Llama de 70B y la GPU 1 las 40–79. Una petición atraviesa la GPU 0, el tensor de activaciones viaja a la GPU 1 y esta termina la pasada hacia delante.
La comunicación es un tensor de forma (batch, seq_len, hidden_size) por cada frontera de etapa. Con lotes de 32, secuencia de 4096, tamaño oculto 8192 y FP16, eso son unos 1 GB por prefill y unos 0.5 MB por token de decodificación con lotes de 32: dos órdenes de magnitud menos que el all-reduce del TP. El PP funciona con holgura sobre 25 GbE normal o incluso 10 GbE.
La contrapartida es la latencia. Con PP=2, cada token salta entre etapas: ingenuamente, el doble de tiempo real por token. vLLM lo mitiga con microlotes: la etapa 0 empieza el siguiente microlote mientras la etapa 1 termina el actual. Con suficiente concurrencia la burbuja se cierra; con una sola petición y sin lotes, el PP es un impuesto de latencia a cambio de nada.
Configuración de vLLM: pipeline_parallel_size
--pipeline-parallel-size M divide el modelo por capas entre M grupos. Total de GPU = tensor_parallel_size × pipeline_parallel_size. Lo que indica la documentación:
- Un solo nodo, 8 GPU o menos, el modelo cabe: TP puro,
pipeline_parallel_size=1. - Varios nodos: TP dentro del nodo, PP entre nodos. Un clúster de dos nodos y 8 GPU se ejecuta con TP=4, PP=2.
- Si el número de GPU no divide limpiamente el número de cabezas: ponga TP=1 y PP=GPU. Al PP le da igual el número de cabezas. (Un equipo de 5 GPU, con una ranura perdida por una NIC, solo puede ejecutar Llama mediante PP=5).
Paralelismo de expertos: solo para MoE
Los modelos MoE (DeepSeek-V3, Mixtral, variantes Qwen-MoE) no activan todos los parámetros en cada token. Tienen capas FFN enrutadas donde solo se dispara un pequeño subconjunto de «expertos» por token; las capas densas de atención siguen siendo densas.
El paralelismo de expertos (EP) reparte los expertos entre las GPU manteniendo las capas densas bajo TP o DP. Con --enable-expert-parallel, las capas de expertos pasan de estar replicadas a estar particionadas, con uno o unos pocos expertos por GPU. El patrón de comunicación es all-to-all por capa MoE: los tokens se enrutan a la GPU que posee el experto de destino, se calculan y vuelven.
El EP genera ráfagas de ancho de banda. Es lo que hace viables los modelos MoE grandes en clústeres PCIe: un TP completo sobre un modelo con 671B activos es inviable. En despliegues Kentino, el EP solo resulta relevante para modelos de la clase DeepSeek-V3; un Llama 70B denso no se beneficia. El EP integrado en vLLM, con una compilación reciente, es el punto de entrada por defecto.
Paralelismo de datos: el eje aburrido y genial
El DP es el eje de escalado más sencillo y el más infrautilizado en la mayoría de instalaciones. Se levantan N copias idénticas del modelo, cada una en su propio conjunto de GPU (y cada conjunto puede usar a su vez TP o PP). Un balanceador reparte las peticiones a la réplica que tenga capacidad.
Lo que da el DP:
- Escalado lineal del rendimiento (N× peticiones por segundo).
- Cero comunicación entre réplicas durante la inferencia.
- Cachés KV independientes por réplica (la caché de prefijos es por réplica).
- Aislamiento de fallos trivial.
Lo que cuesta el DP:
- N× la memoria de GPU: cada réplica guarda el modelo completo.
- Ninguna reducción de latencia. Una petición concreta tarda lo que tarde en una réplica.
Si tiene un equipo con 4× RTX Pro 6000 y Llama 70B cabe con TP=4, un segundo equipo de 4× le da DP=2 × TP=4: el doble de rendimiento con la misma latencia por petición. Para cargas de chat, agentes y RAG, ese es el intercambio correcto. El parámetro --data-parallel-size de vLLM (y el más reciente modo data_parallel_deployment) lanza y gestiona las réplicas. El DP es la forma más limpia de escalar más allá de una máquina.
Combinar los ejes: la regla práctica
Elección del eje: empiece por el paralelismo más pequeño que quepa y añada DP antes que PP.
Ejemplo resuelto. Servir Llama 3.3 70B (FP8 ≈ 75 GB de pesos, más KV) con alta concurrencia:
- Un equipo con 4× RTX Pro 6000 Blackwell (4 × 96 GB = 384 GB) lo mueve con holgura bajo TP=4, dejando unos 250 GB para KV, caché de prefijos y grafos CUDA.
- Añada un segundo equipo de 4× Pro 6000. DP=2 × TP=4. Dos réplicas detrás de un enrutador. El doble de rendimiento, la misma latencia.
- ¿Llama 3.1 405B en FP8 (unos 400 GB de pesos)? En un solo equipo de 4× Pro 6000 no cabe. En dos equipos con PP=2 × TP=4 sí, y el enlace entre nodos mueve activaciones, no all-reduce. Con 25 GbE basta; con 100 GbE va cómodo.
La caché KV: la parte que todo el mundo subestima
La caché KV son los tensores acumulados de claves y valores de atención de cada token del prompt, cada token generado, cada petición simultánea y cada capa. Crece linealmente con la longitud del contexto y con la concurrencia. Llama 70B con un contexto de 8 K necesita aproximadamente 2.5 GB de caché KV por petición en FP16. Con 32 peticiones simultáneas son 80 GB: más que toda la VRAM de una 5090.
Cómo interactúa el paralelismo con la KV:
-
Con TP, la KV se reparte por cabezas de atención dentro del grupo de TP. KV por GPU =
total / tensor_parallel_size. Más TP → más margen para peticiones simultáneas. - Con PP, la KV se queda en la GPU que aloja la capa que la generó. Cada etapa es dueña de su propia KV.
- Con DP, la KV es totalmente independiente en cada réplica.
- Con paralelismo de contexto (un modo más reciente de vLLM), la KV se reparte a lo largo de la dimensión de secuencia, útil para contextos muy largos de una sola petición.
Al dimensionar una máquina, no se limite a comprobar si caben los pesos. Haga las cuentas de la KV para su concurrencia y su ventana de contexto objetivo. El fallo silencioso más habitual en vLLM en producción es que el motor expulse peticiones por presión de KV.
Enrutado de peticiones: qué se pone delante del clúster
Una instancia de vLLM se encarga de su propio agrupamiento interno (batching continuo, caché de prefijos, planificación). No enruta entre réplicas. De eso se encarga el enrutador.
| Enrutador | De qué es consciente | Cuándo usarlo |
|---|---|---|
| NGINX simple | De nada (round-robin) | Despliegues de un solo modelo, cuando gana la sencillez |
| HAProxy | De nada + comprobación de salud | Varios modelos, enrutado por cabecera |
| vLLM Router (Rust) | KV / prefijo / cola | 4 réplicas o más, cuando importa el enrutado por prefijo |
| llm-d (Kubernetes) | Todo lo anterior + EP | Flotas en K8s, MoE, desagregación de prefill y decodificación |
NGINX es la opción correcta por defecto para una instalación de 2 réplicas: round-robin, comprobaciones de salud en /health y listo. El vLLM Router (en Rust, publicado a finales de 2025) es la elección adecuada en cuanto la tasa de aciertos de la caché de prefijos domina su latencia de cola: enruta mediante hashing consistente del prefijo del prompt, de modo que las réplicas con la caché caliente siguen recibiendo las mismas conversaciones. En una carga de agentes con prompts de sistema largos y compartidos, esto puede duplicar el rendimiento efectivo frente al round-robin.
Las cuentas del ancho de banda
Referencias cruzadas: N02, N06.
| Carga de trabajo | Ancho de banda necesario | Enlace realista en Kentino |
|---|---|---|
| TP=4 dentro de un equipo (PCIe Gen 5) | 50–200 GB/s por pareja | PCIe interno del nodo |
| PP entre dos nodos, lotes de 32, decodificación | 0.05–0.2 GB/s | 10 GbE, cómodo |
| PP entre dos nodos, lotes de 32, prefill | Ráfagas de 1–4 GB/s | 25 GbE cómodo, 10 GbE justo |
| DP entre dos nodos | ~0 (solo el enrutador) | 1 GbE de gestión es suficiente |
| EP entre 8 GPU en un equipo (MoE) | 20–80 GB/s a ráfagas | Solo dentro del nodo |
| EP repartido entre 2 nodos (clase DeepSeek-V3) | 10–40 GB/s sostenidos | 100 GbE RoCE o InfiniBand |
La lectura honesta: el TP y el EP quieren quedarse dentro de una máquina. Al PP y al DP les da igual. Con un enlace entre nodos de 10–25 GbE, PP y DP van bien. En cuanto quiera TP entre nodos, está pagando InfiniBand HDR o RoCE a 200 GbE, y antes debería preguntarse si un DP sobre grupos de TP de un nodo le da el mismo resultado por la décima parte del presupuesto. Para la mayoría de despliegues del tamaño de Kentino, se lo da.
Dos recetas concretas de configuración
Receta A: un nodo, 4× RTX 5090, Llama 70B Q4 / FP8
Hardware: Kentino AI 256 Turin Dual o cualquier equipo de 4 GPU con 5090. PCIe Gen 5, sin NVLink, anfitrión AMD EPYC.
vllm serve meta-llama/Llama-3.3-70B-Instruct-FP8 \
--tensor-parallel-size 4 \
--pipeline-parallel-size 1 \
--max-model-len 8192 \
--gpu-memory-utilization 0.92 \
--enable-prefix-caching \
--max-num-seqs 64 \
--dtype auto \
--port 8000
Lo esperable: en torno a 30–40 tok/s por petición con poca concurrencia y unos 400–600 tok/s agregados con 32 peticiones simultáneas (varía según la mezcla de prompts, la tasa de aciertos de la caché de prefijos y la cuantización exacta; tómelo como una horquilla de partida). El all-reduce de PCIe Gen 5 es el cuello de botella en decodificación; el prefill escala casi linealmente.
Receta B: dos nodos, 8× RTX Pro 6000 Blackwell en total, Llama 405B FP8
Dos equipos Kentino AI, cada uno con 4× Pro 6000 (96 GB). Enlace de 100 GbE RoCE entre ellos, o 25 GbE si el presupuesto aprieta (funcionará, con un prefill algo más lento).
# Nodo 0 (cabecera):
vllm serve meta-llama/Llama-3.1-405B-Instruct-FP8 \
--tensor-parallel-size 4 \
--pipeline-parallel-size 2 \
--distributed-executor-backend ray \
--max-model-len 8192 \
--gpu-memory-utilization 0.90 \
--enable-prefix-caching \
--max-num-seqs 32
# Nodo 1 (worker, unido mediante Ray):
ray start --address=<head-ip>:6379
TP=4 dentro de cada nodo usa PCIe Gen 5 para los all-reduce. PP=2 entre nodos envía activaciones por 25/100 GbE. Con Ray como backend distribuido (el que vLLM usa por defecto para varios nodos), la cabecera coordina la planificación y el estado de la KV.
Valoración honesta del rendimiento: un 405B en FP8 repartido entre 8× Pro 6000 sobre PCIe y Ethernet se queda en unos 6–12 tok/s por petición, muy por debajo de un chasis de 8× SXM B200, pero a una fracción del capex y sin el problema de suministro de las SXM. Si su SLA es «responder en 30 s a una generación de 500 tokens», funciona. Si es «responder en 2 s», no use un 405B: use un 70B.
Lo que no ejecutamos
NVLink, NVSwitch, SXM B200, placas HGX completas: no están en la gama de Kentino. Son la respuesta correcta si tiene el presupuesto y la carga de trabajo. No son la respuesta correcta para la mayoría de nuestros clientes, que dimensionan para entre 1 y 4 flujos de agentes simultáneos o una sola plataforma robótica, no para inferencia SaaS con 1 000 usuarios. La vía PCIe es honesta sobre lo que puede y lo que no puede hacer. Un TP por debajo de 10 ms por token entre 16 GPU es otra conversación, no el clúster del que trata este artículo.
Qué hacer a continuación
Si está montando un clúster de vLLM, siga estos pasos en orden:
- Ponga por escrito el modelo y el SLA. Número de parámetros, cuantización, tok/s objetivo por petición, peticiones simultáneas objetivo y ventana de contexto objetivo. Sin esas cifras, la elección del paralelismo es una conjetura.
- Calcule pesos + KV con su concurrencia objetivo. Si solo la KV supera la VRAM libre de una GPU, necesita TP. Si los pesos superan un nodo, necesita PP.
- Empiece por el TP más pequeño que quepa. TP=2 antes que TP=4, y TP=4 antes que TP=8. Cada escalón pierde eficiencia de escalado sobre PCIe.
- Añada DP para ganar rendimiento antes de añadir PP. Dos nodos con DP casi siempre superan a un nodo dividido con PP en cargas sensibles a la latencia.
- Reserve el PP para cuando el modelo no quepa o para cubrir un número de nodos que el TP no pueda dividir limpiamente.
- Ponga un enrutador delante, aunque solo tenga dos réplicas. Para empezar basta con NGINX en round-robin; pase al vLLM Router cuando importe la tasa de aciertos de la caché de prefijos.
-
Vigile el uso de la KV, no solo el de la GPU. Un clúster al 95 % de GPU y al 100 % de KV está expulsando peticiones. El panel que quiere es
vllm_kv_cache_usage_perca lo largo del tiempo.
Continuaciones de esta serie: almacenamiento del clúster (K04), planificación (K05), gestión de fallos (K06) y el techo de PCIe como interconexión (K07). Las cuentas de red se desglosan en N02 y N06.
Esto forma parte de la Kentino Wiki, una serie de referencia sobre computación de IA, robótica y los sistemas que las conectan. Comentarios y correcciones son bienvenidos en info@kentino.com.