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
- 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.
- Sur le chemin des succès,
cpp-cacheva 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 pourgateway_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 pourcpp-cache. - 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èque | Langage | Source mesurée |
|---|---|---|
gateway_cache | Go | github.com/geniussportsgroup/gateway_cache/v3 v3.1.0 (MIT) |
cpp-cache | C++20 | lrleon/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.mddu 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èque | Travailleurs | Requêtes/s (médiane) | Min.–max. | p50 µs | p99 µs | Appels au backend | Backend réel µs | RSS Mo |
|---|---|---|---|---|---|---|---|---|
cpp-cache | 1 | 3 729 630 | 3 525 642–3 767 226 | 0,1 | 0,9 | 0 | 0 | 51,4 |
gateway_cache | 1 | 1 825 178 | 1 808 629–1 933 327 | 0,4 | 1,9 | 0 | 0 | 122 |
cpp-cache | 4 | 2 074 345 | 1 846 801–2 149 483 | 0,6 | 13,8 | 0 | 0 | 51,5 |
gateway_cache | 4 | 1 628 152 | 1 530 965–1 696 679 | 0,5 | 65,5 | 0 | 0 | 138 |
cpp-cache | 8 | 2 145 859 | 1 827 492–2 265 028 | 1,8 | 21,5 | 0 | 0 | 51,6 |
gateway_cache | 8 | 1 673 045 | 1 594 018–1 677 353 | 0,5 | 139 | 0 | 0 | 140 |
cpp-cache | 16 | 1 907 896 | 1 786 557–2 120 210 | 3,6 | 53,2 | 0 | 0 | 51,7 |
gateway_cache | 16 | 1 673 797 | 1 540 942–1 682 224 | 0,4 | 279 | 0 | 0 | 154 |
É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èque | Travailleurs | Requêtes/s (médiane) | Min.–max. | p50 µs | p99 µs | Appels au backend | Backend réel µs | RSS Mo |
|---|---|---|---|---|---|---|---|---|
cpp-cache | 16 | 19 616 | 19 616–19 623 | 1 049 | 1 049 | 150 875 | 1 058 | 24,0 |
gateway_cache | 16 | 18 811 | 18 706–18 838 | 1 049 | 1 180 | 144 582 | 1 101 | 52,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èque | Travailleurs | Requêtes/s (médiane) | Min.–max. | p50 µs | p99 µs | Appels au backend | Backend réel µs | RSS Mo |
|---|---|---|---|---|---|---|---|---|
cpp-cache | 64 | 3 011 286 | 2 888 972–3 043 999 | 2,9 | 188 | 100 | 50 060 | 21,5 |
gateway_cache | 64 | 2 548 668 | 2 538 227–2 597 707 | 0,3 | 410 | 100 | 50 302 | 69,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èque | Travailleurs | Requêtes/s (médiane) | Min.–max. | p50 µs | p99 µs | Appels au backend | Backend réel µs | RSS Mo |
|---|---|---|---|---|---|---|---|---|
cpp-cache | 16 | 24 060 | 24 041–24 097 | 0,9 | 2 032 | 77 415 | 2 061 | 42,2 |
gateway_cache | 16 | 21 866 | 21 770–21 867 | 2,7 | 2 228 | 71 842 | 2 208 | 71,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-cachetraite environ 3,7 millions de requêtes par seconde etgateway_cacheenviron 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 decpp-cachemonte à 3,6 µs alors que celle degateway_cachereste à 0,4 µs, mais le p99 decpp-cacheavec 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.Sleepen 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