El funcionamiento de los servicios de producción requiere saber qué ocurre en su interior, pero añadir métricas no es gratis. En una presentación publicada por InfoQ, Brian Martin, cofundador de IOP Systems, explica que la diferencia entre una implementación y otra puede convertir la actualización de un contador de una operación que cuesta unos 5 nanosegundos en otra que supera 1 microsegundo. Con los histogramas, la diferencia puede pasar de unos 7 nanosegundos a decenas de microsegundos cuando los hilos compiten.
La idea central de la presentación no es elegir una biblioteca concreta de Rust, sino tratar la instrumentación como parte del diseño del rendimiento. Una métrica situada en una ruta que se ejecuta millones de veces amplifica cualquier pequeño coste, mientras que la ausencia de medición dificulta diagnosticar la lentitud, los incidentes de producción y las mejoras de rendimiento.
Empieza por comprender el tipo de datos y el coste de actualizarlo
Martin distingue tres tipos principales de métricas: el contador, que normalmente no disminuye, como el número de solicitudes; el indicador instantáneo que representa un valor actual, como la profundidad de la cola; y el histograma, que describe la distribución de los valores, como los tiempos de respuesta. Esta distinción es importante porque cada tipo requiere operaciones diferentes, y los histogramas proporcionan información que un único contador total no ofrece.
En los casos más sencillos, atomic fetch_add resulta adecuado para los contadores enteros. En cambio, los bucles de comparación e intercambio, o CAS, normalmente necesitan reintentar cuando varios hilos compiten por la misma ubicación. Una parte importante del coste procede de sincronizar las líneas de memoria caché entre los núcleos. La presentación proporciona mediciones realizadas en una máquina AWS Graviton con 32 unidades virtuales de procesamiento: el límite teórico de procesamiento alcanzó unos 119 millones de solicitudes por segundo con una actualización atómica de bajo coste, frente a unos 23 millones cuando se utilizó una implementación de mayor coste con Prometheus.
Reduce la contención mediante la partición por procesador
Cuando todos los hilos comparten un único contador, la línea de memoria caché se mueve continuamente entre los núcleos. Martin propone crear, en su lugar, un contador independiente para cada procesador, de modo que las operaciones de escritura sean prácticamente no contenciosas, y sumar los valores al leerlos. Este enfoque aumenta ligeramente el coste de lectura, pero protege la ruta de escritura activa, que se repite con cada solicitud.
También hay que prestar atención al fenómeno de false sharing. Tener contadores lógicamente independientes no basta si se colocan en una misma línea de memoria caché: el tamaño de la línea es de 64 bytes, lo que significa que ocho contadores de tipo 64-bit pueden quedar juntos. Por ello, la presentación recomienda agrupar y rellenar los contadores para que ocupen líneas de memoria separadas. Según las cifras mostradas, el rendimiento teórico puede pasar de unos 119 millones de solicitudes por segundo con el contador atómico a unos 6.400 millones de solicitudes por segundo al utilizar una partición adecuada.
Diseña los histogramas para la ruta de actualización
El coste de un histograma comienza con la determinación del intervalo al que pertenece el valor. La búsqueda lineal dentro de una lista de intervalos es la opción más sencilla y más lenta, mientras que la búsqueda binaria reduce el número de comparaciones, aunque sigue dependiendo del número de intervalos. La alternativa más rápida es la indexación directa, que calcula el número del intervalo a partir del valor en lugar de buscarlo.
Esta indexación implica ciertos compromisos. La división en rangos lineales es rápida, pero puede producir un error relativo considerable con valores pequeños. La indexación logarítmica conserva mejor el error relativo, aunque el cálculo del logaritmo en sí resulta costoso. Martin presenta el uso de rangos exteriores basados en Log2, con subintervalos que ajustan la precisión, como en HDR Histogram y H2Histogram. En una prueba no atómica, determinar el intervalo y actualizarlo tardó unos 2,65 nanosegundos en HDR Histogram y unos 2,15 nanosegundos en H2Histogram.
¿Cuándo es aceptable la consistencia aproximada?
El coste del histograma no depende únicamente del método de indexación. Algunas aplicaciones realizan varias operaciones atómicas en cada operación, utilizan CAS para sumar los valores o imponen un bloqueo para obtener una instantánea coherente. La presentación señala que algunas implementaciones superaron los 2 microsegundos, e incluso llegaron a decenas de microsegundos con 32 núcleos, mientras que la implementación basada en indexación directa y una única actualización atómica se aproximó más al coste de un contador.
La alternativa es la consistencia aproximada: algunos intervalos pueden cambiar mientras se lee el histograma, pero la diferencia entre dos lecturas consecutivas sigue siendo útil cuando las métricas ya son aproximadas por naturaleza. No se trata de una regla general; los sistemas que necesitan una instantánea completamente coherente pueden preferir la sincronización pese a su coste.
La lectura editorial de certi.news
En la práctica, lo que cambia es que la decisión de añadir métricas debe incluir la arquitectura de actualización, no solo los nombres de las métricas. El contador atómico, la partición por procesador y la indexación directa pueden hacer que la instrumentación sea utilizable dentro de rutas sensibles, mientras que los histogramas sincronizados o ampliables dinámicamente pueden imponer un coste elevado bajo presión. La presentación no ofrece una receta única válida para todas las bibliotecas o servicios; muestra que la flexibilidad, la posibilidad de utilizar la biblioteca en otros proyectos, la consistencia y el rendimiento son objetivos parcialmente enfrentados. Por ello, conviene probar la implementación real con los niveles de contención y el volumen de procesamiento previstos, en lugar de basarse en el nombre de la biblioteca o en el resultado obtenido en un escenario sin competencia.
Martin también presenta el uso de eBPF mediante el proyecto Rezolus para obtener métricas precisas del núcleo de Linux, incluido el planificador, las rutas de llamadas al sistema y la pila TCP, sin modificar el código del núcleo. La cuestión abierta sigue siendo cuánta precisión y consistencia se necesitan en cada caso, y si el coste de lectura o de agregación de las partes seguirá siendo aceptable al ampliar el sistema.