Benchmarks

Mesures nouvelles, prises le 18 octobre 2026 sur la machine décrite plus bas, de deux bibliothèques de cache en processus avec protocole single-flight : gateway_cache (Go) et cpp-cache (C++20). Ce ne sont ni les tests de 2023 de l’architecture complète décrits dans 100K requêtes par seconde ni du trafic de production : elles mesurent chaque bibliothèque seule, sous charge synthétique. La procédure générale est dans Comment nous mesurons ; le protocole, les scripts et les données brutes, dans simylresearch/simyl-benchmarks.

En trois conclusions

  1. Le single-flight fonctionne dans les deux bibliothèques. Au démarrage à froid, 64 travailleurs demandant 100 clés non calculées ont produit exactement 100 appels au backend dans les deux cas : personne ne recalcule ce qu’un autre est déjà en train de calculer.
  2. Sur le chemin des succès, cpp-cache va plus vite et consomme moins de mémoire. Avec un travailleur, il traite environ 3,7 millions de requêtes par seconde contre 1,8 million pour gateway_cache ; de 4 à 16 travailleurs, les deux se stabilisent autour de 1,6 à 2,1 millions, avec un p99 plus bas et entre un tiers et la moitié de la mémoire pour cpp-cache.
  3. Quand le backend domine, la bibliothèque ne compte plus. Avec des échecs fréquents et un backend de 1 ou 2 ms, les deux restent entre environ 19 000 et 24 000 requêtes par seconde : c’est le backend qui fixe le débit, et un cache en processus n’y change rien.

Ce que ces chiffres ne montrent pas est plus bas, dans « Ce qu’ils montrent et ce qu’ils ne montrent pas » : ni réseau, ni sérialisation, ni autre matériel.

Ce qui a été mesuré

BibliothèqueLangageSource mesurée
gateway_cacheGogithub.com/geniussportsgroup/gateway_cache/v3 v3.1.0 (MIT)
cpp-cacheC++20lrleon/cpp-cache 5bfaf38 + lrleon/Aleph-w d37658b (MIT), téléchargés par hash
  • Une trace de 4 000 000 de requêtes par scénario, générée avec une graine fixe et une distribution de Zipf, que les deux bibliothèques rejouent à l’identique.
  • W travailleurs parcourent la trace depuis des positions différentes ; chaque requête appelle l’opération « obtenir ou calculer » avec la clé sous forme de chaîne.
  • Le backend simulé compte ses appels et dort pendant la latence du scénario ; le temps réellement dormi est publié (« backend réel »).
  • Latence par requête dans un histogramme log-linéaire (résolution ≈ 6 %) ; débit = requêtes terminées par seconde, tous travailleurs confondus.
  • Préchauffage non mesuré, 10 s mesurées (3 s au démarrage à froid), 3 répétitions en alternant les bibliothèques. Chaque cellule est la médiane ; la plage min.–max. du débit montre la variabilité. Les percentiles p99,9 et le maximum de chaque exécution sont dans le RESULTS.md du dépôt.

Où et quand

  • Machine : AMD Ryzen 7 PRO 7840U w/ Radeon 780M Graphics (8 cœurs, 16 fils, L3 16 Mio) ; 58,5 Gio de mémoire ; Ubuntu 24.04.5 LTS, noyau 6.8.0-146-generic. Ordinateur portable avec le profil d’énergie « balanced » et le gouverneur powersave (amd-pstate-epp), branché sur secteur.
  • Outils : Go 1.24.4 ; GCC 13.2.0 ; CMake 3.28.3. Harnais au commit 2614b33.
  • Date : 18 octobre 2026. Durée totale du protocole : 501 s ; 42 exécutions (14 configurations par 3 répétitions), avec 0 erreur dans les données brutes.
  • C’est un portable en usage normal, pas un serveur isolé : la variabilité entre répétitions est publiée sous forme de plage. Les chiffres ne s’extrapolent ni à un autre matériel ni à du trafic réel.

Résultats

Succès : débit selon le nombre de travailleurs

100 000 clés qui tiennent dans le cache, backend sans coût, TTL de 60 s et préchauffage de 4 s pour parcourir toute la trace : le chemin des succès et la contention du verrou de 1 à 16 travailleurs.

BibliothèqueTravailleursRequêtes/s (médiane)Min.–max.p50 µsp99 µsAppels au backendBackend réel µsRSS Mo
cpp-cache13 729 6303 525 642–3 767 2260,10,90051,4
gateway_cache11 825 1781 808 629–1 933 3270,41,900122
cpp-cache42 074 3451 846 801–2 149 4830,613,80051,5
gateway_cache41 628 1521 530 965–1 696 6790,565,500138
cpp-cache82 145 8591 827 492–2 265 0281,821,50051,6
gateway_cache81 673 0451 594 018–1 677 3530,513900140
cpp-cache161 907 8961 786 557–2 120 2103,653,20051,7
gateway_cache161 673 7971 540 942–1 682 2240,427900154

Échecs avec éviction LRU

1 000 000 de clés, Zipf 0,8, capacité de 10 000, backend de 1 ms, 16 travailleurs : un trafic dominé par les échecs, avec une éviction LRU constante. Les appels au backend comparés aux échecs montrent combien d’échecs simultanés sur une même clé ont été regroupés.

BibliothèqueTravailleursRequêtes/s (médiane)Min.–max.p50 µsp99 µsAppels au backendBackend réel µsRSS Mo
cpp-cache1619 61619 616–19 6231 0491 049150 8751 05824,0
gateway_cache1618 81118 706–18 8381 0491 180144 5821 10152,3

Démarrage à froid avec 64 travailleurs

100 clés, distribution uniforme, 64 travailleurs, backend de 50 ms, sans préchauffage : tous demandent des clés que personne n’a calculées. Avec le single-flight, le backend est appelé exactement 100 fois ; sans lui, jusqu’à 64 fois par clé.

BibliothèqueTravailleursRequêtes/s (médiane)Min.–max.p50 µsp99 µsAppels au backendBackend réel µsRSS Mo
cpp-cache643 011 2862 888 972–3 043 9992,918810050 06021,5
gateway_cache642 548 6682 538 227–2 597 7070,341010050 30269,8

Clés chaudes et froides avec un TTL de 1 s

200 000 clés, Zipf 1,0, backend de 2 ms, TTL de 1 s, 16 travailleurs : les deux bibliothèques renouvellent le TTL à chaque succès, si bien que les clés populaires n’expirent pas et que celles demandées moins d’une fois par seconde sont recalculées. Un mélange de succès de quelques microsecondes et de recalculs de 2 ms.

BibliothèqueTravailleursRequêtes/s (médiane)Min.–max.p50 µsp99 µsAppels au backendBackend réel µsRSS Mo
cpp-cache1624 06024 041–24 0970,92 03277 4152 06142,2
gateway_cache1621 86621 770–21 8672,72 22871 8422 20871,8

Ce qu’ils montrent et ce qu’ils ne montrent pas

  • Le single-flight fonctionne dans les deux bibliothèques. Au démarrage à froid, 64 travailleurs demandant 100 clés non calculées ont produit exactement 100 appels au backend dans les deux cas ; la latence maximale (≈ 51 ms) correspond à l’attente d’un seul appel de 50 ms.
  • Chemin des succès. Avec un travailleur, cpp-cache traite environ 3,7 millions de requêtes par seconde et gateway_cache environ 1,8 million. De 4 à 16 travailleurs, les deux se stabilisent (≈ 1,9 à 2,1 millions et ≈ 1,6 à 1,7 million) : le verrou global de chacune limite la montée en charge. Sous contention, la médiane de cpp-cache monte à 3,6 µs alors que celle de gateway_cache reste à 0,4 µs, mais le p99 de cpp-cache avec 16 travailleurs est de 53 µs contre 279 µs. Mémoire résidente avec 100 000 entrées : ≈ 52 Mo contre 122 à 154 Mo.
  • Quand le backend domine. Avec un million de clés, une capacité de 10 000 et un backend de 1 ms, les deux atteignent ≈ 19 000 requêtes/s avec 16 travailleurs : le débit est fixé par travailleurs ÷ (proportion d’échecs × latence du backend), pas par le cache. Les appels au backend égalent les échecs dans les deux cas : avec autant de clés distinctes, deux travailleurs échouent rarement en même temps sur la même clé, si bien que le single-flight n’intervient presque pas.
  • Clés chaudes et froides. Avec un TTL de 1 s et un backend de 2 ms, les deux restent à ≈ 22 000 à 24 000 requêtes/s : les recalculs des clés froides dominent et le p99 des deux est celui du backend lui-même (≈ 2 ms).
  • Variabilité. Dans les scénarios de succès, l’écart entre répétitions atteint 10 à 25 % selon le cas : c’est un portable en usage. Dans les scénarios dominés par le backend, l’écart est inférieur à 1 %.
  • Ce qu’ils ne montrent pas. Ni couche HTTP, ni sérialisation, ni réseau, ni trafic réel ; rien sur un autre matériel. Les latences simulées sont de 1 ms ou plus parce que time.Sleep en Go arrondit les valeurs inférieures à ≈ 1 ms. Les chiffres de 2023 (100K requêtes/s de l’architecture complète) sont une mesure différente et ne se comparent pas à ceux-ci.

Reproduire

git clone https://github.com/simylresearch/simyl-benchmarks
cd simyl-benchmarks
scripts/run.sh

Les prérequis sont dans le README du dépôt. Données brutes de cette mesure : results/2026-10-18-ryzen7-pro-7840u/raw/results.jsonl ; environnement complet : results/2026-10-18-ryzen7-pro-7840u/environment.json.

Vous voulez une mesure de ce type pour votre système, avant et après un changement ? Demandez l’appel exploratoire