Load Balancing LLMs : Stratégies Avancées pour le Cache de Préfixes

Temps de lecture : 4 min
Points clés à retenir
- Cache : Le routage naïf annule les gains du cache de préfixes (jusqu’à -90% de coût token).
- Routage : Les stratégies avancées (Radix tree, événements KV) préservent l’efficacité à l’échelle.
- Architecture : La dissociation préfill/decode est critique pour les longues séquences (>100K tokens).
Pourquoi le Load Balancing Classique Échoue avec les LLMs
Je vois souvent cette erreur en consulting : traiter le load balancing des LLMs comme celui d’une API REST. Concrètement, le cache de prompts change tout. Dans mes benchmarks pour GymLog, un cache hit pouvait réduire le TTFT de 80% et les coûts de tokens de 70%. Mais avec un simple round-robin sur N réplicas, la probabilité de tomber sur le réplica avec le bon cache précalculé est de 1/N. Plus vous scalez, plus votre taux de cache hit s’effondre. C’est le paradoxe de la scalabilité LLM.
Le Pipeline d’Inférence Moderne : Plus Qu’une Forward Pass
Quand je configure vLLM ou TensorRT pour un client, le processus est toujours le même. La requête HTTP arrive, le tokenizer transforme le prompt en IDs. Ensuite, le moteur batch les requêtes et calcule les fameux tenseurs Key/Value (KV). La première passe (prefill) génère le premier token, puis la boucle auto-régressive commence.
Plus précisément, pour chaque nouveau token, les caches KV sont mis à jour. C’est là que les techniques comme Paged Attention ou le Prefix Caching entrent en jeu. Elles évitent de recalculer des préfixes communs. Imaginez un chatbot : chaque message envoie toute l’historique. Sans cache KV, vous payez le prefill à chaque fois. C’est comme recompiler tout le code source à chaque modification mineure.
Stratégies de Routage : Du Simple au Précise
Avec des instances homogènes, vous avez plusieurs options. La plus basique est le cache-aware routing. Je l’ai implémenté dans un workflow n8n pour router des requêtes GPT. Le principe ? Un arbre Radix par instance. Pour une nouvelle requête, on cherche l’instance avec le plus long préfixe correspondant dans son arbre. On route là-bas et on insère le nouveau prompt dans l’arbre.
Mais cette approche a un défaut majeur : le routeur et les moteurs se désynchronisent. Le routeur peut penser qu’un cache existe alors que le moteur l’a évincé par pression mémoire. Inversement. Résultat : mauvaise route, cache manqué, tout est recalculé. C’est pour ça qu’on passe au préfixe cache-aware routing précis.
Dans cette version avancée, le routeur écoute les événements de cache KV émis par les moteurs. Il a une vue en temps réel. Oui, il doit tokenizer le prompt avant le matching, mais c’est négligeable face au gain. Pour scaler horizontalement ce layer de routage, on peut utiliser Redis ou une architecture mesh avec des CRDTs. Chaque routeur a une copie synchronisée de l’état global.
Dissociation Préfill/Decode : Quand et Pourquoi
Ici, on touche à l’intensité arithmétique. Le stage prefill (sans batching) est compute-bound. Il a besoin de TFLOPs. Le stage decode (génération token par token) est memory-bound, même avec du batching, à cause des updates incessantes du cache KV. Il a besoin de bande passante mémoire.
Concrètement, pour des séquences très longues (disons 100K tokens en entrée, 1K en sortie), il est intéressant de dissocier. Des workers spécialisés font le prefill, d’autres le decode. Mais le transfert du cache KV entre les deux est critique. Il faut des technologies comme RDMA, NCCL ou Mooncake TE. La bande passante reste inférieure à la VRAM GPU, donc il y a un overhead.
Plus précisément, pour des ISL courts, oubliez la dissociation. Un worker decode peut tout gérer. J’implémente toujours un seuil dynamique qui bascule entre les modes. C’est comme choisir entre une voiture de ville et un 4×4 : ça dépend du terrain.
L’Avenir : Cache Partagé et Limites Actuelles
La prochaine étape, sur laquelle bosse l’industrie, est un layer de cache partagé accessible par tous les réplicas, probablement sur un pool DRAM CPU haute performance. Ainsi, n’importe quel réplica pourrait servir un cache hit, peu importe qui l’a calculé. Le défi ? La latence. Déplacer des tenseurs KV sur le réseau est bien plus lent que la VRAM locale, même avec RDMA.
En attendant que cette latence soit viable pour la production, le routage par affinité de session et le prefix-aware routing restent l’état de l’art pragmatique. Comme dans Ghost in the Shell, l’information doit être au plus près de l’unité de traitement pour être efficace.
Note : Les métriques de performance (TTFT, coûts) varient selon la configuration. Les outils cités (vLLM, SGLang) le sont à titre informatif. Ce contenu est fourni « tel quel » pour un usage éducatif.

Développeur full-stack depuis 25 ans, je suis passé du PHP des années 2000 aux stacks modernes (Next.js, React Native, IA). J’accompagne entrepreneurs et créateurs dans leurs projets digitaux avec une approche pragmatique : du code aux résultats concrets.