Rustls : Étude de cas sur le benchmarking continu


Qu’est-ce que Rustls ?

Rustls est une bibliothèque moderne de Transport Layer Security (TLS) écrite en Rust, avec l’objectif de remplacer des alternatives non sécurisées en mémoire telles qu’OpenSSL. Le protocole TLS est utilisé pour fournir des communications sécurisées, typiquement entre un serveur web et un client. TLS était précédemment appelé Secure Socket Layer (SSL). Il garantit que les données transmises entre les deux parties sont chiffrées et sécurisées contre l’écoute ou la falsification. Par conséquent, il est essentiel pour une bibliothèque TLS comme Rustls d’être à la fois rapide et sécurisée.

🐰 Le s dans https signifie que vous utilisez TLS pour consulter cette page !

Benchmarking Rustls

Le premier commit de Rustls a été fait par le créateur du projet Joseph Birr-Pixton le 02 mai 2016, avec la première connexion TLS réussie n’ayant pas eu lieu avant le 27 de ce même mois. En septembre, il benchmarkait déjà Rustls. Avec des améliorations de performance substantielles à son actif, il a fait une comparaison de benchmark tête-à-tête de Rustls vs OpenSSL en juillet 2019.

Les résultats de cette comparaison de benchmark étaient :

  • Rustls était 15% plus rapide pour envoyer des données.
  • Rustls était 5% plus rapide pour recevoir des données.
  • Rustls était 20-40% plus rapide pour établir une connexion client.
  • Rustls était 10% plus rapide pour établir une connexion serveur.
  • Rustls était 30-70% plus rapide pour reprendre une connexion client.
  • Rustls était 10-20% plus rapide pour reprendre une connexion serveur.
  • Rustls utilisait moins de la moitié de la mémoire d’OpenSSL.

En 2023, le Groupe de Recherche sur la Sécurité Internet a financé le benchmarking des performances du projet Rustls, et cela a généré une mise à jour de la comparaison de benchmark tête-à-tête de Rustls vs OpenSSL. Bien que ces résultats mis à jour aient été instructifs pour le projet Rustls, tant sur les domaines de force que sur ceux à améliorer, la principale préoccupation en matière de performance est maintenant de garantir que le nouveau code n’introduise pas de régression de performance.

Benchmarking Continu pour Rustls

Afin de détecter les régressions de performance avant qu’elles ne soient lancées, le projet Rustls a décidé d’investir dans le Benchmarking Continu.

Le Benchmarking Continu est une pratique de développement de logiciel où les membres d’une équipe évaluent leurs travaux fréquemment, généralement chaque personne effectue des benchmarks au moins quotidiennement - conduisant à plusieurs benchmarks par jour. Chaque benchmark est vérifié par une construction automatisée pour détecter les régressions de performance le plus rapidement possible. De nombreuses équipes constatent que cette approche conduit à une réduction significative des régressions de performance et permet à une équipe de développer un logiciel performant plus rapidement.

La solution de benchmarking continu du projet Rustls se compose de deux composants principaux :

  • CI Bench : Un harnais de benchmarking personnalisé spécialement conçu pour exécuter des benchmarks dans CI
  • Bench Runner : Un serveur personnalisé de benchmarking continu en métal nu et une application GitHub compagnon

Rustls CI Bench

CI Bench est un harnais de choix pour le benchmarking continu. Il exécute le même benchmark exact dans deux modes différents : le mode de comptage d’instructions et le mode de temps réel. Ceci est accompli en utilisant un runtime asynchrone personnalisé ingénieux. Pour le mode de comptage d’instructions, l’I/O est toujours bloquant. Sous le capot, les tâches se terminent en un seul sondage. Ensuite, pour le mode de temps réel, l’I/O est vraiment non bloquant. Cela permet de simuler des tampons partagés en mémoire. Le serveur et le client sont sondés à tour de rôle. Cela permet à CI Bench d’éliminer le bruit et le non-déterminisme d’un runtime asynchrone dans leurs benchmarks.

Rustls a choisi de suivre les instructions CPU en utilisant cachegrind. Cette décision a été modelée après la solution de benchmarking continu du compilateur Rust. Le compte d’instructions fournit une manière très consistante de comparer deux versions du même logiciel. Cela le rend idéal pour le benchmarking continu. Cependant, il n’est pas possible de déduire le coût d’exécution réel d’une augmentation du nombre d’instructions. Une augmentation de 10% des instructions ne résulte pas nécessairement en une augmentation de 10% des performances d’exécution. Mais une augmentation significative des instructions signifie probablement qu’il y a une certaine augmentation des performances d’exécution. Pour cette raison, CI Bench mesure également le temps réel.

Le temps réel est la chose que le projet Rustls se soucie vraiment. Mesurer les comptes d’instructions n’est qu’un proxy utile. Le benchmarking basé sur le compte d’instructions ne peut pas désambiguïser les changements qui utilisent le même nombre d’instructions mais conduisent à des performances en temps réel très différentes. Par exemple, un nouvel algorithme peut arriver à avoir exactement le même nombre d’instructions mais fonctionner deux fois plus lentement.

Rustls Bench Runner

Le Rustls Bench Runner est un serveur de benchmarking continu personnalisé. Il est conçu pour fonctionner sur un hôte en metal nu, et il reçoit des évents d’une application GitHub associée via des webhooks. À chaque push sur la branche main, le Bench Runner exécute à la fois le comptage d’instructions et les benchmarks de temps d’exécution. Les résultats sont stockés localement et envoyés au projet Rustls sur Bencher en utilisant l’API Bencher.

Chaque fois qu’une pull request est approuvée ou qu’un commentaire contenant @rustls-benchmarking bench est laissé par un mainteneur de Rustls, la suite de benchmarking est exécutée. Le Bench Runner reçoit un webhook de GitHub, récupère le code de la pull request, exécute les benchmarks de comptage d’instructions, exécute les benchmarks de temps d’exécution, compare les résultats de la pull request aux résultats de la branche main cible, et poste ensuite les résultats en tant que commentaire sur la pull request. Le Bench Runner utilise un modèle de Plage interquartile Delta pour son seuil statistique pour déterminer si une régression de performance s’est produite. Les résultats qui dépassent ce seuil sont mis en évidence dans le commentaire de la pull request.

Serveur Bare Metal

Pour obtenir une résolution de 1% sur leurs benchmarks de temps mural, le projet Rustls a investi dans un serveur de benchmarking continu spécialement configuré, un serveur bare metal. Contrairement à la plupart des runners CI modernes, ce serveur n’est pas éphémère. C’est-à-dire, le même matériel de serveur sous-jacent et le même système d’exploitation sont utilisés pour chaque exécution. Il n’y a pas de virtualisation.

Le serveur bare metal a été spécifiquement configuré pour créer les résultats les plus cohérents possibles. Le changement de fréquence (TurboBoost d’Intel) et le multithreading simultané (Hyper-Threading d’Intel) ont tous deux été désactivés dans le BIOS. Le CPU scaling est réglé sur performance. La randomisation de l’espace d’adressage (ASLR) et le watchdog d’interruption non masquable (NMI) sont tous deux désactivés en définissant kernel.randomize_va_space=0 et kernel.nmi_watchdog=0 dans sysctl.conf, respectivement. Le serveur bare metal est hébergé par OHVcloud.

Vitrine de Trophées

  • PR #1640 : L’une des premières utilisations de l’intégration de benchmarking continu Rustls pour évaluer la transition de write_vectored à write. Cette modification a amélioré les benchmarks de transfert en direction d’envoi de Rustls de près de 20% dans certains cas.
  • PR #1730 : A découvert des régressions de performance lors de la randomisation de l’ordre des extensions ClientHello de TLS. Cela a entraîné une autre itération de développement et l’utilisation d’une approche plus efficace.
  • PR #1834 : A aidé à valider rapidement un correctif de sécurité crucial n’a pas introduit une régression de performance. Cela a permis à l’équipe de se concentrer sur la sortie rapide de plusieurs versions patchées pour la sécurité.

Conclusion

En se basant sur les fondations établies par le créateur du projet, Adolfo Ochagavía a construit une impressionnante solution de benchmarking continu pour le projet Rustls. Cela inclut un harnais de benchmarking personnalisé qui exécute à la fois des benchmarks de comptage d’instructions et des benchmarks de temps d’horloge pour le même test, un exécuteur de benchmarking personnalisé, une application GitHub personnalisée et un serveur dédié bare metal personnalisé. Il s’agit de l’une des solutions de benchmarking continu spécifiques à un projet les plus impressionnantes qui existent. Si votre projet a le temps et les ressources pour construire et maintenir une solution de benchmarking continu sur mesure, le projet Rustls fixe une barre élevée à viser.

Un très grand merci à Adolfo Ochagavía pour avoir relu cette étude de cas. Ses articles de blog sur le Benchmarking continu pour Rustls et les Performances de Rustls ont été la base de son contenu.

Bencher: Benchmarking Continu

🐰 Bencher

Bencher est une suite d’outils de benchmarking continu. Avez-vous déjà eu une régression de performance qui a impacté vos utilisateurs ? Bencher aurait pu empêcher cela de se produire. Bencher vous permet de détecter et de prévenir les régressions de performance avant qu’elles n’arrivent en production.

  • Exécuter: Exécutez vos benchmarks localement ou en CI en utilisant vos outils de benchmarking préférés. La CLI bencher enveloppe simplement votre harnais de benchmarking existant et stocke ses résultats.
  • Suivre: Suivez les résultats de vos benchmarks au fil du temps. Surveillez, interrogez et graphiquez les résultats à l’aide de la console web Bencher en fonction de la branche source, du banc d’essai et de la mesure.
  • Détecter: Détectez les régressions de performances en CI. Bencher utilise des analyses de pointe et personnalisables pour détecter les régressions de performances avant qu’elles n’arrivent en production.

Pour les mêmes raisons que les tests unitaires sont exécutés en CI pour prévenir les régressions de fonctionnalités, les benchmarks devraient être exécutés en CI avec Bencher pour prévenir les régressions de performance. Les bugs de performance sont des bugs !

Commencez à détecter les régressions de performances en CI — essayez Bencher Cloud gratuitement.

🤖 Ce document a été automatiquement généré par OpenAI GPT-4. Il peut ne pas être précis et peut contenir des erreurs. Si vous trouvez des erreurs, veuillez ouvrir une issue sur GitHub.