Benchmarks

Mediciones nuevas, tomadas el 18 de octubre de 2026 en la máquina descrita abajo, de dos bibliotecas de caché en proceso con protocolo single-flight: gateway_cache (Go) y cpp-cache (C++20). No son las pruebas de 2023 de la arquitectura completa descritas en 100K peticiones por segundo ni tráfico de producción: miden cada biblioteca sola, con carga sintética. El procedimiento general está en Cómo medimos; el protocolo, los scripts y los datos crudos, en simylresearch/simyl-benchmarks.

En tres conclusiones

  1. El single-flight funciona en las dos bibliotecas. En el arranque en frío, 64 trabajadores pidiendo 100 claves sin calcular produjeron exactamente 100 llamadas al backend en ambas: nadie recomputa lo que otro ya está calculando.
  2. En el camino de acierto, cpp-cache rinde más y gasta menos memoria. Con un trabajador atiende unos 3,7 millones de peticiones por segundo frente a 1,8 millones de gateway_cache; de 4 a 16 trabajadores las dos se estabilizan en torno a 1,6–2,1 millones, con un p99 más bajo y entre un tercio y la mitad de la memoria en cpp-cache.
  3. Cuando manda el backend, la biblioteca deja de importar. Con fallos frecuentes y un backend de 1 o 2 ms, las dos quedan entre unas 19.000 y 24.000 peticiones por segundo: el rendimiento lo fija el backend, y una caché en proceso no lo cambia.

Lo que estas cifras no muestran está en «Lo que muestran y lo que no», más abajo: ni red, ni serialización, ni otro hardware.

Qué se midió

BibliotecaLenguajeFuente medida
gateway_cacheGogithub.com/geniussportsgroup/gateway_cache/v3 v3.1.0 (MIT)
cpp-cacheC++20lrleon/cpp-cache 5bfaf38 + lrleon/Aleph-w d37658b (MIT), descargados por hash
  • Una traza de 4.000.000 de peticiones por escenario, generada con semilla fija y distribución Zipf, que las dos bibliotecas reproducen idéntica.
  • W trabajadores recorren la traza desde posiciones distintas; cada petición llama a la operación «obtener o calcular» con la clave como cadena.
  • El backend simulado cuenta sus llamadas y duerme la latencia del escenario; se publica el tiempo real que durmió («backend real»).
  • Latencia por petición en un histograma log-lineal (resolución ≈ 6 %); rendimiento = peticiones completadas por segundo entre todos los trabajadores.
  • Calentamiento sin medir, 10 s medidos (3 s en el arranque en frío), 3 repeticiones alternando bibliotecas. Cada celda es la mediana; el rango mín.–máx. del rendimiento muestra la variabilidad. Los percentiles p99,9 y el máximo de cada corrida están en el RESULTS.md del repositorio.

Dónde y cuándo

  • Máquina: AMD Ryzen 7 PRO 7840U w/ Radeon 780M Graphics (8 núcleos, 16 hilos, L3 16 MiB); 58,5 GiB de memoria; Ubuntu 24.04.5 LTS, kernel 6.8.0-146-generic. Portátil con perfil de energía «balanced» y gobernador powersave (amd-pstate-epp), conectado a la corriente.
  • Herramientas: Go 1.24.4; GCC 13.2.0; CMake 3.28.3. Harness en el commit 2614b33.
  • Fecha: 18 de octubre de 2026. Duración total del protocolo: 501 s; 42 corridas (14 configuraciones por 3 repeticiones), con 0 errores en los datos crudos.
  • Es un portátil en uso normal, no un servidor aislado: la variabilidad entre repeticiones se publica como rango. Las cifras no se extrapolan a otro hardware ni a tráfico real.

Resultados

Aciertos: rendimiento según trabajadores

100.000 claves que caben en la caché, backend sin costo, TTL de 60 s y calentamiento de 4 s para recorrer toda la traza: el camino de acierto y la contención del cerrojo de 1 a 16 trabajadores.

BibliotecaTrabajadoresPeticiones/s (mediana)Mín.–máx.p50 µsp99 µsLlamadas al backendBackend real µsRSS MB
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

Fallos con desalojo LRU

1.000.000 de claves, Zipf 0,8, capacidad 10.000, backend de 1 ms, 16 trabajadores: tráfico dominado por fallos con desalojo LRU constante. Las llamadas al backend frente a los fallos muestran cuántos fallos concurrentes sobre la misma clave se agruparon.

BibliotecaTrabajadoresPeticiones/s (mediana)Mín.–máx.p50 µsp99 µsLlamadas al backendBackend real µsRSS MB
cpp-cache1619.61619.616–19.6231.0491.049150.8751.05824,0
gateway_cache1618.81118.706–18.8381.0491.180144.5821.10152,3

Arranque en frío con 64 trabajadores

100 claves, distribución uniforme, 64 trabajadores, backend de 50 ms, sin calentamiento: todos piden claves que nadie ha calculado. Con single-flight el backend se llama exactamente 100 veces; sin él, hasta 64 veces por clave.

BibliotecaTrabajadoresPeticiones/s (mediana)Mín.–máx.p50 µsp99 µsLlamadas al backendBackend real µsRSS MB
cpp-cache643.011.2862.888.972–3.043.9992,918810050.06021,5
gateway_cache642.548.6682.538.227–2.597.7070,341010050.30269,8

Claves calientes y frías con TTL de 1 s

200.000 claves, Zipf 1,0, backend de 2 ms, TTL de 1 s, 16 trabajadores: las dos bibliotecas renuevan el TTL en cada acierto, así que las claves populares no caducan y las pedidas menos de una vez por segundo se recomputan. Mezcla de aciertos de microsegundos y recomputaciones de 2 ms.

BibliotecaTrabajadoresPeticiones/s (mediana)Mín.–máx.p50 µsp99 µsLlamadas al backendBackend real µsRSS MB
cpp-cache1624.06024.041–24.0970,92.03277.4152.06142,2
gateway_cache1621.86621.770–21.8672,72.22871.8422.20871,8

Lo que muestran y lo que no

  • El single-flight funciona en las dos bibliotecas. En el arranque en frío, 64 trabajadores pidiendo 100 claves sin calcular produjeron exactamente 100 llamadas al backend en ambas; la latencia máxima (≈ 51 ms) es la espera de una sola llamada de 50 ms.
  • Camino de acierto. Con un trabajador, cpp-cache atiende unos 3,7 millones de peticiones por segundo y gateway_cache unos 1,8 millones. De 4 a 16 trabajadores las dos se estabilizan (≈ 1,9–2,1 millones y ≈ 1,6–1,7 millones): el cerrojo global de cada una limita la escalabilidad. Bajo contención la mediana de cpp-cache sube a 3,6 µs mientras la de gateway_cache se queda en 0,4 µs, pero el p99 de cpp-cache con 16 trabajadores es de 53 µs frente a 279 µs. Memoria residente con 100.000 entradas: ≈ 52 MB frente a 122–154 MB.
  • Cuando manda el backend. Con un millón de claves, capacidad de 10.000 y un backend de 1 ms, las dos rinden ≈ 19.000 peticiones/s con 16 trabajadores: el rendimiento lo fija trabajadores ÷ (fracción de fallos × latencia del backend), no la caché. Las llamadas al backend igualan los fallos en ambas: con tantas claves distintas, dos trabajadores rara vez fallan a la vez sobre la misma clave, así que el single-flight apenas interviene.
  • Claves calientes y frías. Con TTL de 1 s y backend de 2 ms, ambas quedan en ≈ 22.000–24.000 peticiones/s: las recomputaciones de las claves frías dominan y el p99 de las dos es el propio backend (≈ 2 ms).
  • Variabilidad. En los escenarios de aciertos el rango entre repeticiones alcanza el 10–25 % según el caso: es un portátil en uso. En los escenarios dominados por el backend el rango es inferior al 1 %.
  • Lo que no muestran. Ni capa HTTP, ni serialización, ni red, ni tráfico real; nada sobre otro hardware. Las latencias simuladas son de 1 ms o más porque time.Sleep de Go redondea los valores menores a ≈ 1 ms. Las cifras de 2023 (100K peticiones/s de la arquitectura completa) son una medición distinta y no se comparan con estas.

Reproducir

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

Los requisitos están en el README del repositorio. Datos crudos de esta medición: results/2026-10-18-ryzen7-pro-7840u/raw/results.jsonl; entorno completo: results/2026-10-18-ryzen7-pro-7840u/environment.json.

¿Quieres una medición así de tu sistema, antes y después de un cambio? Pide la llamada exploratoria