Rustls: Kontinuierliche Benchmarking-Fallstudie


Was ist Rustls?

Rustls ist eine moderne Transport Layer Security (TLS)-Bibliothek, die in Rust geschrieben ist, mit dem Ziel, nicht-speichersichere Alternativen wie OpenSSL zu ersetzen. Das TLS-Protokoll wird verwendet, um sichere Kommunikationen bereitzustellen, typischerweise zwischen einem Webserver und einem Client. TLS hieß früher Secure Socket Layer (SSL). Es stellt sicher, dass die zwischen den beiden Parteien übertragenen Daten verschlüsselt sind und vor Lauschangriffen oder Manipulationen geschützt sind. Daher ist es für eine TLS-Bibliothek wie Rustls sowohl schnell als auch sicher zu sein von wesentlicher Bedeutung.

🐰 Das s in https bedeutet, dass Sie TLS verwenden, um diese Seite anzusehen!

Benchmarking von Rustls

Der erste Commit von Rustls wurde vom Projekterfinder Joseph Birr-Pixton am 02. Mai 2016 gemacht, wobei die erste erfolgreiche TLS-Verbindung erst am 27. dieses Monats stattfand. Bis September führte er bereits Benchmarks für Rustls durch. Mit erheblichen Leistungsverbesserungen in der Tasche, führte er im Juli 2019 einen direkten Benchmark-Vergleich zwischen Rustls und OpenSSL durch.

Die Ergebnisse dieses Benchmark-Vergleichs waren:

  • Rustls war 15% schneller beim Senden von Daten.
  • Rustls war 5% schneller beim Empfangen von Daten.
  • Rustls war 20-40% schneller beim Aufbau einer Client-Verbindung.
  • Rustls war 10% schneller beim Aufbau einer Server-Verbindung.
  • Rustls war 30-70% schneller beim Wiederaufbau einer Client-Verbindung.
  • Rustls war 10-20% schneller beim Wiederaufbau einer Server-Verbindung.
  • Rustls verbrauchte weniger als die Hälfte des Speichers von OpenSSL.

Im Jahr 2023 hat die Internet Security Research Group die Leistungsbemessung des Rustls-Projekts finanziert und das generierte einen aktualisierten direkten Benchmark-Vergleich zwischen Rustls und OpenSSL. Obwohl diese aktualisierten Ergebnisse informativ für das Rustls-Projekt sowohl in Bereichen der Stärke als auch in Bereichen zur Verbesserung waren, ist das größte Leistungsproblem nun die Gewährleistung, dass neuer Code keine Leistungseinbußen verursacht.

Kontinuierliches Benchmarking für Rustls

Um Leistungseinbußen zu erkennen, bevor sie veröffentlicht werden, hat das Rustls-Projekt beschlossen, in Kontinuierliches Benchmarking zu investieren.

Kontinuierliches Benchmarking ist eine Softwareentwicklungspraxis, bei der Teammitglieder ihre Arbeit häufig benchmarken, normalerweise führt jede Person mindestens täglich Benchmarks durch - was zu mehreren Benchmarks pro Tag führt. Jeder Benchmark wird von einem automatisierten Build verifiziert, um Leistungsrückgänge so schnell wie möglich zu erkennen. Viele Teams stellen fest, dass dieser Ansatz zu einer signifikanten Reduzierung der Leistungsrückgänge führt und ermöglicht es einem Team, leistungsfähige Software schneller zu entwickeln.

Die kontinuierliche Benchmarking-Lösung des Rustls-Projekts besteht aus zwei Hauptkomponenten:

  • CI Bench: Ein angepasstes Benchmarking-Harness, das speziell für das Ausführen von Benchmarks in CI entwickelt wurde
  • Bench Runner: Ein angepasster, bare-metal kontinuierlicher Benchmarking-Server und zugehörige GitHub App

Rustls CI Bench

CI Bench ist ein erstklassiges Gerüst für kontinuierliche Benchmarking. Es führt den genau gleichen Benchmark in zwei verschiedenen Modi aus: Instruktionszählmodus und Wanduhrenmodus. Dies wird mit Hilfe einer genialen benutzerdefinierten asynchronen Laufzeit erreicht. Im Instruktionszählmodus ist die I/O tatsächlich immer noch blockierend. Im Hintergrund werden Aufgaben in einer einzigen Abfrage abgeschlossen. Dann, im Wanduhrenmodus, ist die I/O wirklich nicht blockierend. Dies ermöglicht die Simulation von gemeinsam genutzten, im Speicher vorhandenen Puffern. Der Server und der Client werden abwechselnd abgefragt. Auf diese Weise ermöglicht CI Bench das Eliminieren von Störgeräuschen und Nicht-Determinismus in ihren Benchmarks.

Rustls hat sich dafür entschieden, CPU-Instruktionen mithilfe von cachegrind zu verfolgen. Diese Entscheidung richtete sich nach der kontinuierlichen Benchmarking-Lösung des Rust-Compilers. Instruktionszahlen bieten eine sehr konsistente Möglichkeit, zwei Versionen derselben Software zu vergleichen. Dies macht es ideal für kontinuierliche Benchmarking. Es ist jedoch nicht möglich, die tatsächlichen Laufzeitkosten einer Erhöhung der Instruktionszahl abzuschätzen. Ein Anstieg der Instruktionen um 10% führt nicht unbedingt zu einer Leistungssteigerung der Laufzeit um 10%. Ein signifikanter Anstieg der Instruktionen bedeutet jedoch wahrscheinlich, dass es einen Anstieg der Laufzeitleistung gibt. Aus diesem Grund misst CI Bench auch die Wandzeit.

Die Wandzeit ist das, was dem Rustls-Projekt wirklich wichtig ist. Die Messung von Instruktionszahlen ist nur ein nützlicher Proxy. Benchmarking auf Basis von Instruktionszählung kann Änderungen nicht differenzieren, die die gleiche Anzahl von Instruktionen verwenden, aber zu völlig unterschiedlichen Wandzeitleistungen führen. Zum Beispiel könnte ein neuer Algorithmus zufällig genau die gleiche Anzahl von Anweisungen haben, aber doppelt so langsam laufen.

Rustls Bench Runner

Der Rustls Bench Runner ist ein benutzerdefinierter kontinuierlicher Benchmarking-Server. Er ist dafür ausgelegt, auf einem Bare-Metal-Host zu laufen, und erhält Ereignisse von einer begleitenden GitHub-App über Webhooks. Bei jedem Push auf den Haupt Zweig, führt der Bench Runner sowohl die Anweisungszähler als auch die Wall-Time-Benchmarks aus. Die Ergebnisse werden lokal gespeichert und an das Rustls Projekt auf Bencher unter Verwendung der Bencher API gesendet.

Immer wenn ein Pull-Request genehmigt wird oder ein Kommentar mit @rustls-benchmarking bench von einem Rustls-Maintainer hinterlassen wird, wird die Benchmarking-Suite ausgeführt. Der Bench Runner erhält einen Webhook von GitHub, zieht den Code für den Pull-Request, führt die Anweisungszähler-Benchmarks aus, führt die Wall-Time-Benchmarks aus, vergleicht die Ergebnisse des Pull-Requests mit den Ergebnissen des Ziel-Haupt-Zweigs, und postet dann die Ergebnisse als Kommentar zum Pull-Request. Der Bench Runner verwendet ein Delta Interquartile Range Modell als statistischen Schwellenwert, um zu ermitteln, ob eine Performance-Regression eingetreten ist. Ergebnisse, die diese Schwelle überschreiten, werden im Pull-Request-Kommentar hervorgehoben.

Bare-Metal-Server

Um eine Auflösung von 1% bei ihren Wandzeit-Benchmarks zu erreichen, investierte das Rustls-Projekt in einen speziell konfigurierten, dedizierten kontinuierlichen Benchmarking-Server. Im Gegensatz zu den meisten modernen CI-Läufern ist dieser Server nicht flüchtig. Das bedeutet, dass für jeden Durchlauf die gleiche zugrundeliegende Server-Hardware und das gleiche Betriebssystem verwendet werden. Es gibt keine Virtualisierung.

Der Bare-Metal-Server wurde speziell konfiguriert, um die konsequentesten Ergebnisse zu erzielen. Die Frequenzskalierung (Intel’s TurboBoost) und das simultane Multithreading (Intel’s Hyper-Threading) wurden beide im BIOS deaktiviert. Die CPU-Skalierung ist auf performance eingestellt. Die Adressraumlayout-Randomisierung (ASLR) und der nicht maskierbare Interrupt (NMI) Watchdog sind beide deaktiviert, indem kernel.randomize_va_space=0 und kernel.nmi_watchdog=0 in sysctl.conf eingestellt werden. Der Bare-Metal-Server wird von OHVcloud gehostet.

Ehrenvitrine

  • PR #1640: Eine der ersten Anwendungen der Rustls kontinuierlichen Benchmarking-Integration zur Evaluierung des Übergangs von write_vectored zu write. Diese Änderung verbesserte die Rustls Send-Richtung Übertragungs-Benchmarks in einigen Fällen um fast 20%.
  • PR #1730: Leistungsregressionen gefunden, wenn die Reihenfolge der TLS ClientHello-Erweiterungen zufällig geändert wurde. Dies führte zu einer weiteren Entwicklungsiteration und der Nutzung eines effizienteren Ansatzes.
  • PR #1834: Half dabei, schnell zu validieren, dass eine kritische Sicherheitskorrektur keine Leistungsregression einführte. Dies ermöglichte dem Team, sich auf die schnelle Freigabe mehrerer Sicherheitsgepatchter Versionen zu konzentrieren.

Abschluss

Aufbauend auf den Grundlagen, die vom Projektinitiator gesetzt wurden, hat Adolfo Ochagavía eine beeindruckende kontinuierliche Benchmarking-Lösung für das Rustls-Projekt entwickelt. Dazu gehören ein angepasster Benchmarking-Harness, der sowohl Instruktionszähl- als auch Wand-Zeit-Benchmarks für denselben Test ausführt, ein individueller Benchmark-Runner, eine individuelle GitHub-App und ein spezieller, dedizierter Bare-Metal-Server. Es ist eine der beeindruckendsten, auf ein spezifisches Projekt ausgerichteten kontinuierliche Benchmarking-Lösungen, die es gibt. Wenn Ihr Projekt die Zeit und Ressourcen hat, eine maßgeschneiderte kontinuierliche Benchmarking-Lösung zu erstellen und zu warten, setzt das Rustls-Projekt einen hohen Standard, den man anstreben kann.

Ein ganz besonderer Dank geht an Adolfo Ochagavía für die Überprüfung dieser Fallstudie. Seine Blog-Posts über Kontinuierliches Benchmarking für Rustls und Rustls-Leistung waren die Grundlage für deren Inhalt.

Bencher: Kontinuierliches Benchmarking

🐰 Bencher

Bencher ist eine Suite von kontinuierlichen Benchmarking-Tools. Hatten Sie jemals eine Performance Regression, die Ihre Nutzer beeinflusste? Bencher hätte das verhindern können. Bencher ermöglicht es Ihnen, Leistungsregressionen vorher zu erkennen und zu verhindern, bevor sie in die Produktion gelangen.

  • Ausführen: Führen Sie Ihre Benchmarks lokal oder in CI mit Ihren bevorzugten Benchmarking-Tools aus. Das bencher CLI umfasst einfach Ihr vorhandenes Benchmark-Harness und speichert die Ergebnisse.
  • Verfolgen: Verfolgen Sie die Ergebnisse Ihrer Benchmarks im Laufe der Zeit. Überwachen, abfragen und grafisch darstellen der Ergebnisse mit der Bencher Web Konsole auf Basis des Quellzweigs, Testbetts und Maßnahme.
  • Auffangen: Fangen Sie Leistungsregressionen in CI ab. Bencher verwendet modernste, anpassbare Analysen, um Leistungsregressionen zu erkennen, bevor sie in die Produktion gelangen.

Aus denselben Gründen, warum Unit Tests in CI laufen, um Feature Regressionen zu verhindern, sollten Benchmarks in CI mit Bencher ausgeführt werden, um Leistungsregressionen zu verhindern. Performance-Bugs sind Fehler!

Beginnen Sie damit, Leistungsregressionen in CI aufzufangen - probieren Sie Bencher Cloud kostenlos aus.

🤖 Dieses Dokument wurde automatisch von OpenAI GPT-4 generiert. Es ist möglicherweise nicht korrekt und kann Fehler enthalten. Wenn Sie Fehler finden, öffnen Sie bitte ein Problem auf GitHub.