Bei Galadrim sind wir es gewohnt, mit vielen verschiedenen Web-Sprachen und Frameworks zu arbeiten. Auch wenn jedes Team und jeder Entwickler seine Vorlieben hat, sind wir überzeugt, dass die Wahl des am besten geeigneten Tools für das Projekt die beste Lösung ist.
In diesem Sinne haben wir zahlreiche Backends in TypeScript und Python -unseren gängigsten Stacks- aber auch in Go, Rust, PHP oder C#. Mit der Zeit haben wir uns gefragt, ob es echte Leistungsunterschiede zwischen diesen Sprachen und einigen ihrer jeweiligen Frameworks im Rahmen unserer Projekte gibt. Wann und wie sollte eine Technologie einer anderen vorgezogen werden?
Um diese Frage zu beantworten, haben wir einen internen Benchmark durchgeführt, der 4 populäre Sprachen vergleicht, Go, Rust, Python und JavaScript für ein typisches Webprojekt, eine REST-API für ein Mini-Soziales Netzwerk.
Hier ist unser Erfahrungsbericht.
I. Grafana K6, ein modernes Lasttest-Tool
Um diesen Benchmark durchzuführen, haben wir verwendet Grafana K6, ein Open-Source-Tool, in Go geschrieben und entwickelt von Grafana Labs das mit Tools wie JMeter, das auf der JVM (Java) basiert, konkurriert.
Was die Sache ändert
Einfach zu bedienen : Für die Verwendung in der CLI konzipiert, ist K6 sehr einfach zu bedienen und die Testszenarien sind einfache Skripte JavaScript (oder TypeScript). Jeder Entwickler im Team kann die Tests ohne spezielle Schulung lesen, schreiben und warten.
Leistung und Effizienz : Da es in Go geschrieben ist, verbraucht K6 sehr wenig Speicher und ist sehr leistungsstark. Eine einzige Standardmaschine kann somit Tausende von virtuellen Benutzern simulieren, wo andere Tools einen ganzen Cluster benötigen würden.
Intégration CI/CD : Als skriptfähiges CLI-Tool integriert es sich nativ in Ihre Pipelines (GitHub Actions, GitLab CI, etc.), um Performance-Regressionstests zu automatisieren.
Wie funktioniert es?
K6 orchestriert VUs (Virtual Users). Jeder VU verhält sich wie ein Benutzer, der einem vordefinierten Skript folgt, das unbegrenzt wiederholt wird:
Er führt HTTP-Anfragen (oder WebSocket, gRPC) aus.
Er überprüft die Antworten (Status 200, Inhalt des JSON...).
Er hält Pausenzeiten (sleep) ein, um ein realistisches menschliches Verhalten zu simulieren.
Das Tool aggregiert die Ergebnisse anschliessend in Echtzeit und liefert wesentlich relevantere Metriken als ein einfacher «Durchschnitt», um die von den Nutzern wahrgenommene Latenz zu verstehen. Eine interessante Metrik ist das 95. Perzentil oder p95, das dem Wert entspricht, bei dem 95% der beobachteten Latenzen darunter und 5% darüber liegen.
II. Das Testprotokoll: ein Mini-Soziales Netzwerk
Damit die Ergebnisse relevant sind, haben wir einen Anwendungsfall simuliert, der repräsentativ für die Projekte ist, die wir für unsere Kunden entwickeln: ein Mini-Sozialnetzwerk. Unsere Test-Backends müssen daher die folgenden Funktionen implementieren:
Authentifizierung : Login, Abruf des aktuellen Profils.
Benutzerverwaltung : Erstellung, Auflistung, Profilbearbeitung.
Post-Verwaltung : Veröffentlichung, Feed-Lesen, Löschen.
Funktionen eines sozialen Netzwerks : Kommentare, likes / unlikes.
Technisches Umfeld
Wir wollten auch die Verwendung von Ökosystem-spezifischen Tools so weit wie möglich einschränken aus zwei Gründen: um die Tests nicht mit zusätzlichen Abhängigkeiten zu belasten und um das Einschleppen von Verzerrungen beim Leistungsvergleich zu vermeiden.
Zu diesem Zweck haben wir uns entschieden, von einer einfachen OpenAPI-Datei auszugehen, die die API beschreibt, und anschliessend die Routen in jeder Sprache minimalistisch zu implementieren, ohne ORM oder JSON-Mapping-Tools zu verwenden. Wir haben unsere Datenbank-Manipulationsanfragen direkt in SQL geschrieben, damit jedes Backend genau dieselbe Anfrage mit derselben Basis auf dieselbe Weise ausführt.
Die Tests wurden auf einem MacBook Pro M3 (36 GB RAM) mit Docker-Containern durchgeführt, die auf 4 CPUs und 8 GB RAM pro Backend begrenzt waren. Die unten genannten absoluten Werte für Anfragen pro Sekunde (RPS) sind nicht wörtlich zu nehmen, sondern eher miteinander zu vergleichen, da sie von Ihrer Konfiguration abhängen.
Das Testszenario jeder VU
Unser Test-Workflow beschränkt sich nicht darauf, eine Route zu spammen, er simuliert den vollständigen Weg eines Benutzers:
Administrator-Login und Erstellung eines neuen Benutzers.
Login des neuen Benutzers.
Veröffentlichung eines Posts.
Lesen des Feeds.
Hinzufügen eines Kommentars und like auf einen Post.
Löschen der Daten (Bereinigung).
Wir haben die Last variiert von 50 VUs à 1000 VUs gleichzeitigen VUs, um zu sehen, wann die Backends zusammenbrechen.
Unten finden Sie ein Ausführungsbeispiel für Express (Bun, 1000 VUs).
III. Die Erkenntnisse
RPS-Vergleich über alle Szenarien
P95-Antwortzeit pro Szenario
Rohleistung: das Duell Go vs Rust
Wenn Sie die reine Performance für Systeme mit sehr hohem Traffic suchen, spielt sich das Duell zwischen Go und Rust. Auf der Skala unserer Tests gibt es keinen klaren Gewinner und beide Sprachen erreichen ähnliche Leistungen (> 20 000 RPS). Diese Sprachen glänzen auch durch ihre Widerstandsfähigkeit unter hoher Last mit p95-Werten um 85ms, weit unter den 200ms, die im Rahmen dieses Tests akzeptiert wurden.
Go (mit Fiber) : Seine Einfachheit und sein Management von Goroutinen machen es zu einem Effizienzmonster für Web-APIs.
Rust (mit Axum) : Mit sehr solider Performance bietet Rust auch unübertroffene Speichersicherheits- und Stabilitätsgarantien trotz einer komplexeren Einarbeitung.
Verdict : Wenn Sie Rohleistung benötigen, sind Go und Rust eine solide Wahl. Während der erste auf die Entwicklungserfahrung Wert legt, glänzt der zweite bei der Erstellung robuster Systeme.
Entwicklungsgeschwindigkeit: Python vs JavaScript (Node/Bun)
Für die Mehrheit der Projekte (MVP, Startups, interne Tools) überwiegt die Entwicklungsgeschwindigkeit oft die Rohleistung. Tatsächlich ist die gewählte Programmiersprache selten der limitierende Faktor für die Performance eines Backends im Vergleich zur Optimierung der Architektur, der Datenbank und der Netzwerk- oder System-Eingaben/Ausgaben.
Python (FastAPI) : Einfach zu handhaben, mit einer prägnanten und klaren Syntax, hervorragend für Data, zeigt es bei starker Belastung Leistungsgrenzen auf. Darüber hinaus hat Python schnell einen erheblichen Einfluss auf den serverseitig verwendeten Speicher und ist daher nicht unbedingt für Anwendungen mit hohen Hardware-Anforderungen geeignet (z.B. eingebettete Anwendungen). In unseren Tests hält es die «mittlere» Last gut aus, beginnt aber unter starker Last (500+ gleichzeitige Nutzer) zu versagen, mit einem p95 von 420ms für 1 000 VUs. Es ist ein ausgezeichneter Kompromiss zwischen Produktivität und Performance, solange der Traffic angemessen bleibt (~7 000 RPS).
JavaScript (Node vs Bun) : Node.js ist die beliebteste JavaScript-Laufzeitumgebung und basiert auf der V8-Engine von Google. Bun ist eine neuere JavaScript-Laufzeitumgebung und basiert auf der JavaScript-Engine von Apple. JavaScript (aber auch TypeScript) ist eine Programmiersprache, die die Entwicklung von Web-Anwendungen ermöglicht. Es hat den enormen Vorteil, client- und serverseitig ausgeführt werden zu können, was die Entwicklung von Full-Stack-Webanwendungen mit einer einzigen Sprache ermöglicht. Dies beinhaltet die Möglichkeit, gemeinsamen Code zwischen Client und Server zu teilen (business logic, validation de données, types, etc.), aber auch nur eine einzige Sprache für die Anwendungsentwicklung zu verwenden und zu beherrschen. Mit rund 10 000 RPS, die in beiden Fällen erreicht wurden, bietet das JavaScript-Ökosystem eine solide Performance, während ein p95 von ~170ms im Worst-Case-Szenario beibehalten wird.
Verdict : Wenn Sie ein eher Full-Stack-Team haben, ist JavaScript/TypeScript eine sehr solide Option, um hervorragende Leistungen zu erzielen, ohne die Sprache wechseln zu müssen. Für die reine Backend-Nutzung oder Data Science mit schneller Iteration ist Python eine sehr gute Alternative, erfordert aber eine robustere Architektur (caching, horizontal scaling) und mehr Aufmerksamkeit bei der Code-Optimierung, um vergleichbare Leistungen zu erzielen.
Wenn Sie diese Tests reproduzieren möchten, finden Sie hier den Link zum GitHub dieses Benchmarks!