Rustls: Estudio de Caso de Benchmarking Continuo

Everett Pompeii

Everett Pompeii


¿Qué es Rustls?

Rustls es una biblioteca moderna de seguridad de la capa de transporte (TLS) escrita en Rust, con el objetivo de reemplazar alternativas inseguras de memoria como OpenSSL. El protocolo TLS se utiliza para proporcionar comunicaciones seguras, típicamente entre un servidor web y un cliente. TLS fue llamado previamente Secure Socket Layer (SSL). Garantiza que los datos transmitidos entre las dos partes estén encriptados y seguros contra la intercepción o manipulación. Por lo tanto, es vital que una biblioteca de TLS como Rustls sea tanto rápida como segura.

🐰 La s en https significa que estás utilizando TLS para ver esta página!

Benchmarking de Rustls

El primer commit de Rustls fue realizado por el creador del proyecto Joseph Birr-Pixton el 02 de mayo de 2016, con la primera conexión TLS exitosa no ocurriendo hasta el 27 de ese mismo mes. Para septiembre, él ya estaba haciendo benchmarking de Rustls. Con importantes mejoras de rendimiento bajo su cinturón, hizo una comparación de benchmark de cabeza a cabeza de Rustls vs OpenSSL en julio de 2019.

Los resultados de esa comparación de benchmark fueron:

  • Rustls fue 15% más rápido para enviar datos.
  • Rustls fue 5% más rápido para recibir datos.
  • Rustls fue 20-40% más rápido para establecer una conexión de cliente.
  • Rustls fue 10% más rápido para establecer una conexión de servidor.
  • Rustls fue 30-70% más rápido para reanudar una conexión de cliente.
  • Rustls fue 10-20% más rápido para reanudar una conexión de servidor.
  • Rustls usó menos de la mitad de la memoria de OpenSSL.

En 2023, el Internet Security Research Group financió el benchmarking de rendimiento del proyecto Rustls, y eso generó una actualizada comparación de benchmark de cabeza a cabeza de Rustls vs OpenSSL. Aunque estos resultados actualizados fueron informativos para el proyecto Rustls en áreas tanto de fortaleza como en áreas a mejorar, la mayor preocupación de rendimiento ahora está en garantizar que el nuevo código no introduzca una regresión de rendimiento.

Benchmarking Continuo para Rustls

Para detectar regresiones de rendimiento antes de que se publiquen, el proyecto Rustls decidió invertir en Benchmarking Continuo.

El Benchmarking Continuo es una práctica de desarrollo de software en la que los miembros de un equipo evalúan su trabajo con frecuencia, normalmente cada persona realiza evaluaciones al menos diariamente - lo que resulta en múltiples benchmarks por día. Cada evaluación de rendimiento es verificada por una construcción automatizada para detectar regresiones de rendimiento lo más rápido posible. Muchos equipos descubren que este enfoque conduce a una reducción significativa en las regresiones de rendimiento y permite a un equipo desarrollar software de alto rendimiento más rápidamente.

La solución de benchmarking continuo del proyecto Rustls consta de dos componentes principales:

  • CI Bench: Un arnés de evaluación comparativa personalizado diseñado específicamente para ejecutar benchmarks en CI
  • Bench Runner: Un servidor de benchmarking continuo en metal desnudo personalizado y una aplicación complementaria de GitHub

Rustls CI Bench

CI Bench es un arnés de primer nivel para el rendimiento continuo. Ejecuta el mismo benchmark exactamente en dos modos diferentes: modo de conteo de instrucciones y modo de tiempo de pared. Esto se logra utilizando un ingenioso runtime personalizado asíncrono. Para el modo de conteo de instrucciones, la I/O sigue siendo bloqueante. Bajo el capó, las tareas simplemente se completan en un solo sondeo. Luego, en el modo de tiempo de pared, la I/O es realmente no bloqueante. Esto permite simular buffers de memoria compartidos en la memoria. El servidor y el cliente se sondean alternativamente. Esto permite a CI Bench eliminar el ruido y la indeterminación de un runtime asíncrono en sus benchmarks.

Rustls decidió seguir las instrucciones de CPU utilizando cachegrind. Esta decisión fue modelada según la solución de rendimiento continuo del compilador Rust. El conteo de instrucciones proporciona una forma muy consistente de comparar dos versiones del mismo software. Esto lo hace ideal para el rendimiento continuo. Sin embargo, no es posible inferir el coste de tiempo de ejecución real de un aumento en el conteo de instrucciones. Un aumento del 10% en las instrucciones no necesariamente resulta en un aumento del 10% en el rendimiento de tiempo de ejecución. Pero un aumento significativo en las instrucciones probablemente significa que hay algún aumento en el rendimiento de tiempo de ejecución. Por esta razón, CI Bench también mide el tiempo de pared.

El tiempo de pared es lo que realmente le importa al proyecto Rustls. La medición de los conteos de instrucciones es solo un proxy útil. El rendimiento basado en el conteo de instrucciones no puede desambiguar los cambios que utilizan el mismo número de instrucciones pero conducen a un rendimiento de tiempo de pared extremadamente diferente. Por ejemplo, un nuevo algoritmo puede suceder que tenga exactamente el mismo número de instrucciones, pero se ejecute el doble de lento.

Rustls Bench Runner

El Rustls Bench Runner es un servidor personalizado de benchmarking continuo. Está diseñado para ejecutarse en un anfitrión de metal desnudo, y recibe eventos desde una aplicación complementaria de GitHub por medio de webhooks. En cada push a la rama main, el Bench Runner ejecuta ambos benchmarks, el conteo de instrucciones y el tiempo en el muro. Los resultados se almacenan localmente y se envían al proyecto Rustls en Bencher usando la API de Bencher.

Siempre que se aprueba un pull request o un comentario que contiene @rustls-benchmarking bench es enviado por un mantenedor de Rustls, se ejecuta la suite de benchmarking. El Bench Runner recibe un webhook de GitHub, tira del código para el pull request, ejecuta los benchmarks de conteo de instrucciones, ejecuta los benchmarks de tiempo en el muro, compara los resultados del pull request con los resultados de la rama main objetivo, y luego publica los resultados como un comentario en el pull request. El Bench Runner utiliza un modelo de Rango Interquartil Delta para su umbral estadístico para determinar si ha ocurrido una regresión de rendimiento. Los resultados que superan este umbral se resaltan en el comentario del pull request.

Servidor Bare Metal

Para obtener una resolución del 1% en sus benchmarks de tiempo de pared, el proyecto Rustls invirtió en un servidor de bare metal especialmente configurado para benchmarks continuos configuración especial del servidor. A diferencia de la mayoría de los corredores de CI modernos, este servidor no es efímero. Es decir, el mismo hardware de servidor subyacente y el sistema operativo se utilizan para cada ejecución. No hay virtualización.

El servidor bare metal ha sido configurado específicamente para crear los resultados más consistentes posibles. El escalado de frecuencia (TurboBoost de Intel) y el multihilo simultáneo (Hyper-Threading de Intel) se han desactivado en la BIOS. El escalado de CPU está configurado para performance. La Randomización del Espacio de Direcciones del Layout (ASLR) y el watchdog de Interrupción no Enmascarable (NMI) se han desactivado al establecer kernel.randomize_va_space=0 y kernel.nmi_watchdog=0 en sysctl.conf, respectivamente. El servidor bare metal está hospedado por OVHcloud.

Galería de Trofeos

  • PR #1640: Uno de los primeros usos de la integración de benchmarking continuo de Rustls para evaluar la transición de write_vectored a write. Este cambio mejoró los benchmarks de transferencia en la dirección de envío de Rustls en casi un 20% en algunos casos.
  • PR #1730: Se encontraron regresiones de rendimiento al aleatorizar el orden de las extensiones de Cliente TLS ClientHello. Esto resultó en otra iteración de desarrollo y el uso de un enfoque más eficiente.
  • PR #1834: Ayudó a validar rápidamente que una solución crítica de seguridad no introdujo una regresión de rendimiento. Esto permitió al equipo concentrarse en la liberación rápida de varias versiones con parches de seguridad.

Conclusión

Construyendo sobre la base establecida por el creador del proyecto, Adolfo Ochagavía ha desarrollado una impresionante solución de benchmarking continuo para el proyecto Rustls. Esto incluye un arnés de benchmarking personalizado que ejecuta tanto benchmarks de conteo de instrucciones como de tiempo de pared para la misma prueba, un corredor de benchmark personalizado, una aplicación de GitHub personalizada y un servidor de metal desnudo dedicado y personalizado. Es una de las soluciones de benchmarking continuo específicas de proyecto más impresionantes que existen. Si tu proyecto tiene el tiempo y los recursos para construir y mantener una solución de benchmarking continuo a medida, el proyecto Rustls establece un alto estándar a aspirar.

Un agradecimiento muy especial a Adolfo Ochagavía por revisar este estudio de caso. Sus publicaciones de blog sobre Benchmarking Continuo para Rustls y Rendimiento de Rustls fueron la base para su contenido.

Bencher: Benchmarking continuo

🐰 Bencher

Bencher es un conjunto de herramientas de benchmarking continuo. ¿Alguna vez has tenido un impacto de regresión de rendimiento en tus usuarios? Bencher podría haber evitado que eso sucediera. Bencher te permite detectar y prevenir las regresiones de rendimiento antes de que lleguen a producción.

  • Ejecutar: Ejecute sus benchmarks localmente o en CI usando sus herramientas de benchmarking favoritas. La CLI bencher simplemente envuelve su arnés de benchmarks existente y almacena sus resultados.
  • Seguir: Sigue los resultados de tus benchmarks con el tiempo. Monitoriza, realiza consultas y representa gráficamente los resultados utilizando la consola web de Bencher basándose en la rama de origen, el banco de pruebas y la medida.
  • Capturar: Captura las regresiones de rendimiento en CI. Bencher utiliza analíticas de vanguardia y personalizables para detectar regresiones de rendimiento antes de que lleguen a producción.

Por las mismas razones que las pruebas unitarias se ejecutan en CI para prevenir regresiones funcionales, los benchmarks deberían ejecutarse en CI con Bencher para prevenir regresiones de rendimiento. ¡Los errores de rendimiento son errores!

Empiece a capturar regresiones de rendimiento en CI — prueba Bencher Cloud gratis.

🤖 Este documento fue generado automáticamente por OpenAI GPT-4. Puede que no sea exacto y contenga errores. Si encuentra algún error, abra un problema en GitHub.