Preuves

Benchmarks

Les performances de la passerelle Wäg face à LiteLLM dans des conditions identiques. Cette page expose la méthode en entier et publie les mesures qu'elle a produites. Nous ne publions pas de multiplicateurs.

8 vCPU Docker, pinned coresWäg v1.0.0LiteLLM v1.104.23 runs/scenario

Comment la mesure a été faite

Tout a tourné dans Docker sur une seule machine, chaque composant épinglé à ses propres cœurs afin que rien ne se dispute le CPU.

  • Les deux passerelles se placent devant le même upstream avec une configuration de modèle identique : aucune n'a le chemin le plus facile.
  • Chaque passerelle tourne comme sa propre documentation le recommande : LiteLLM selon son guide de production, avec autant de workers que de vCPU ; Wäg avec ses réglages par défaut. Le cache de réponses est désactivé des deux côtés.
  • Les tests en boucle fermée mesurent le débit maximal. Les tests en boucle ouverte émettent à cadence fixe et comptent la latence à partir de l'instant d'envoi prévu : une passerelle qui met en file d'attente ne peut donc pas le dissimuler.
  • Chaque réponse est validée : statut, structure du corps et, pour les flux, le nombre de fragments attendu et sa terminaison. Tout le reste compte comme une erreur, jamais comme une réponse rapide.
  • Chaque scénario est exécuté trois fois et les tableaux affichent la médiane. Sans passerelle dans le chemin, la même charge atteint environ 90 000 req/s, bien au-delà des deux passerelles : les résultats sont donc limités par la passerelle, pas par le harnais.

Empreinte

Ce que coûte chaque passerelle avant de servir quoi que ce soit : mémoire au repos, temps de démarrage, taille de l'image et latence ajoutée à une requête unique face à un upstream instantané.

Mémoire après démarrage3,8 MBLiteLLM 2 302 MB
Temps de démarrage0,32 sLiteLLM 11,2 s
Image du conteneur123 MBLiteLLM 1 669 MB
Latence ajoutée, un client (p50)0,11 msLiteLLM 2,1 ms

Ce que cela signifie : La mémoire décide du nombre de réplicas qui tiennent sur un nœud, et la taille de l'image de la rapidité d'un déploiement. Avec 3,8 Mo résidents et une image de 123 Mo, Wäg tient dans un sidecar et est prêt avant l'expiration d'un health check ; 2,3 Go et 11 secondes, c'est un pod autour duquel il faut planifier.

La latence ajoutée correspond au p50 de la passerelle moins le p50 mesuré sans passerelle dans le chemin.

Avec un upstream réaliste

Un vrai modèle répond en centaines de millisecondes : des milliers de requêtes sont donc en vol simultanément. Ici l'upstream prend 300 ms et les requêtes arrivent à cadence fixe quoi que fasse la passerelle. À 2 000 req/s, environ 600 requêtes sont en cours à tout instant.

WägLiteLLM
200 ms500 ms1,00 s2,00 s5,00 s10 s20 s50 sPlancher : 300 ms d'upstream1005001,0002,000requêtes par secondeLiteLLMWäg
requêtes par secondeWäg p50Wäg p99Wäg ErreursWäg CPULiteLLM p50LiteLLM p99LiteLLM ErreursLiteLLM CPU×
100303 ms305 ms0,00%10,2%305 ms308 ms0,00%38,7%1,0×
500301 ms303 ms0,00%15,6%304 ms321 ms0,00%140,5%1,1×
1 000301 ms302 ms0,00%20,2%317 ms605 ms0,00%263,7%2,0×
2 000301 ms302 ms0,00%31,7%3,26 s28 s7,99%391,9%92×

Ce que cela signifie : C'est la forme du trafic réel : un modèle répond en centaines de millisecondes et des milliers de requêtes sont en vol. Une passerelle qui met en file d'attente transforme une réponse de 300 ms en plusieurs secondes, et personne ne le voit avant le pic. Wäg reste au plancher jusqu'à 2 000 req/s avec moins d'un tiers de son budget CPU. LiteLLM met déjà en file d'attente à 1 000 et échoue sur 8 % des requêtes à 2 000.

L'upstream seul prend 300 ms : c'est le plancher. Tout ce qui le dépasse est du temps passé en file d'attente dans la passerelle. La colonne × se lit toujours de la même façon : plus la valeur est élevée, plus Wäg est devant. C'est Wäg ÷ LiteLLM pour le débit et LiteLLM ÷ Wäg pour la latence.

Débit et latence

Boucle fermée face à un upstream instantané : le coût pur de la passerelle, sans latence de modèle derrière laquelle se cacher. Ce sont les chiffres nécessaires à un plan de capacité. Ce ne sont pas la raison de choisir un plan de contrôle.

4 vCPU, sans base de données

Clients simultanésWäg req/sWäg p99Wäg CPULiteLLM req/sLiteLLM p99LiteLLM CPU×
16 2320,27 ms63,4%4633,2 ms98,1%13×
825 7110,70 ms311,5%1 23715 ms286,1%21×
3225 0932,6 ms321,8%1 62146 ms385,1%15×
12823 63911 ms328,3%1 669111 ms396,2%14×
51222 40745 ms336,9%1 569749 ms391,6%14×

1 vCPU, sans base de données

Clients simultanésWäg req/sWäg p99LiteLLM req/sLiteLLM p99×
16 5890,35 ms4593,2 ms14×
816 5941,3 ms48426 ms34×
3215 2263,8 ms50685 ms30×
12813 26415 ms505438 ms26×

Ce que cela signifie : Cela détermine le nombre de réplicas nécessaires à un niveau de trafic, donc le coût d'exploitation de la passerelle. Pour Kubernetes, c'est le tableau à 1 vCPU qu'il faut lire : c'est l'efficacité par cœur qu'un pod obtient réellement.

Streaming, charges utiles, embeddings, bascule

4 vCPU, sans base de données. Les flux comptent 50 tokens espacés de 5 ms ; le test d'endurance envoie 200 flux par seconde de réponses d'environ 1,2 seconde pendant trois minutes.

ScénarioWägWäg p99Wäg ErreursLiteLLMLiteLLM p99LiteLLM Erreurs×
Streaming, 64 clients233286 ms0,00%179674 ms0,00%1,3×
Streaming, 256 clients911288 ms0,00%3071,09 s0,00%3,0×
64 KB conversation history, 32 clients3 58329 ms0,00%568106 ms0,00%6,3×
Embeddings (1,536 dims), 32 clients13 5584,3 ms0,00%74069 ms0,00%18×
Fallback after upstream 500, 16 clients19 8161,8 ms0,00%58462 ms0,00%34×
Soak: 200 streams/s for 3 minutes2001,27 s0,00%17620 s12,09%1,1×

Ce que cela signifie : Streaming, prompts longs, embeddings et bascule : c'est là qu'une charge de production passe son temps. Lisez les colonnes d'erreurs avant celles de débit : une requête échouée est une requête utilisateur échouée, pas une requête lente.

Le chiffre des charges de 64 Ko atteint le plafond du harnais : sans passerelle dans le chemin, la même charge atteint 3 711 req/s de corps de 64 Ko sur un cœur. La valeur de Wäg y est donc un minorant, pas un maximum.

Ce que ceci ne montre pas

Tout benchmark décrit un montage. Voici les limites de celui-ci.

  • Les valeurs absolues dépendent de l'hôte. Les deux passerelles ont tourné sur la même machine avec des cœurs épinglés : la comparaison entre elles tient, mais attendez-vous à des valeurs absolues différentes sur votre propre matériel.
  • Le harnais qui a piloté ces mesures n'est pas publié : vous ne pouvez donc pas les répéter commande par commande. La méthode ci-dessus est décrite assez précisément pour reconstruire un équivalent.
  • LiteLLM publie presque chaque semaine. Ces chiffres ont été mesurés avec v1.104.2, la version stable actuelle. Dès qu'une version modifie le chemin de transmission, nous relançons la mesure et publions ce que nous trouvons.
  • LiteLLM a été configuré d'après son guide de production, non par ses mainteneurs. Une meilleure configuration existe peut-être ; si vous en trouvez une, nous relancerons la mesure et republierons.
  • Les deux passerelles ont tourné sur une seule machine avec des cœurs épinglés. Rien ici ne mesure le comportement à travers un réseau, sous l'ordonnancement de Kubernetes ou avec des voisins bruyants.