Rust oder Go: wo die Trennlinie wirklich verläuft
Go bringt ein Team in zwei Wochen zum Liefern, Rust in zwei Monaten. Ob sich das lohnt, entscheidet nicht der Geschmack, sondern was ihr an Latenz und Speicher zusagen müsst.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Entschieden wird nach Benchmarks, die im eigenen Dienst niemand nachrechnet
Der Ablauf ist bekannt: Ein neuer Dienst steht an, jemand bringt eine Messung mit, in der Rust um ein Vielfaches vor Go liegt, und die Diskussion ist gelaufen. In einem echten Backend geht die Zeit aber in Datenbankabfragen, Netz, Serialisierung und Warten. Ein Dienst, der acht Millisekunden in der Datenbank und vier Zehntel im eigenen Code verbringt, wird durch einen Sprachwechsel nicht schneller, er wird nur später fertig.
In die Rust-Richtung falsch entschieden kostet Kalenderzeit. Nach drei Monaten ringt ein Teil des Teams noch mit Eigentumsfragen in asynchronem Code, die Fahrpläne sind verschoben, und der Dienst tut das, was eine Go-Fassung nach sechs Wochen getan hätte. Danach hat Rust im Haus einen Ruf, und der ist schwerer zu reparieren als der Code.
In die Go-Richtung falsch entschieden kostet später und stiller. Ein Dienst mit einer harten Zusage zur Antwortzeit hat wenig Spielraum für die Rechenzeit, die der Sammler nebenher belegt, und für die Lastspitzen, bei denen viel gleichzeitig alloziert wird. Dazu kommt der Speicher: Die Laufzeitumgebung hält einen Puffer vor, und bei dreistelliger Instanzzahl steht das als Posten in der Cloud-Rechnung. Rechenarbeit in der Anfrage, etwa Bilder, Kryptografie oder große Nutzlasten, ist die dritte Stelle, an der der Abstand sichtbar bleibt.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Die Kriterien, an denen die Wahl tatsächlich hängt
Verglichen werden hier keine Messreihen aus fremden Projekten, sondern die Eigenschaften, die sich in deinem Dienst bemerkbar machen: Einarbeitung, Antwortzeit unter Last, Speicher, Rechenarbeit, Ökosystem und Lesbarkeit für den nächsten Kollegen.
Go
kleine Sprache mit Laufzeitumgebung, Garbage Collector und Goroutinen, in etwa zwei Wochen erlernbar
Rust
keine Laufzeitumgebung und kein Sammler, dafür Eigentumsregeln, die der Compiler vor dem ersten Start prüft
| Entscheidungsfrage | Go | Rust |
|---|---|---|
| Wie schnell liefert jemand, der die Sprache heute noch nicht kann? | Stärke Wer Java, C# oder Python kann, schreibt in der ersten Woche brauchbaren Go-Code. Die Sprache ist bewusst klein gehalten, und die Spezifikation liest sich an einem Nachmittag durch. | Schwäche Kompilierender Code entsteht auch hier in Tagen. Bis jemand eigene Datenstrukturen entwirft, ohne gegen die Eigentumsregeln zu laufen, vergehen erfahrungsgemäß mehrere Wochen. |
| Wie berechenbar ist die Antwortzeit unter Last? | Kommt darauf an Die Phasen, in denen der Sammler das Programm anhält, sind sehr kurz. Spürbar wird er über die Rechenzeit, die er nebenher belegt, und über Lastspitzen, bei denen viel gleichzeitig alloziert wird. | Stärke Speicher wird freigegeben, wenn der Besitzer endet. Es gibt keinen Sammler, der irgendwann läuft, und damit auch keine Schwankung aus dieser Richtung. |
| Wie viel Arbeitsspeicher belegt ein Dienst im Dauerbetrieb? | Kommt darauf an Die Laufzeitumgebung hält Halden-Speicher als Puffer vor. Ein schlanker Dienst startet trotzdem klein, bei vielen Instanzen summiert sich der Aufschlag aber sichtbar. | Stärke Ohne Laufzeitumgebung und ohne Haldenpuffer bleibt der belegte Speicher nah an dem, was die Daten tatsächlich brauchen, und er schwankt weniger. |
| Wie sieht es bei Rechenarbeit in der Anfrage aus? | Kommt darauf an Für die meisten Aufgaben schnell genug. Bei engen Schleifen über große Datenmengen bleibt Abstand, unter anderem weil du weniger Kontrolle über Speicherlayout und Kopien hast. | Stärke Übersetzt ohne Zwischenschicht auf Maschinencode, mit Kontrolle über Layout und Kopien. Rechenschleifen lassen sich mit Rayon über alle Kerne verteilen, ohne dass Datenrennen möglich werden. |
| Wie gut ist das Ökosystem für Cloud- und Betriebswerkzeuge? | Stärke Kubernetes, Docker, Terraform und Prometheus sind selbst in Go geschrieben. Clients, Operatoren und Erweiterungen für diese Welt gibt es dort zuerst und am vollständigsten. | Kommt darauf an Für HTTP-Dienste, Datenbanken, Serialisierung und Kryptografie ist die Lage gut. Bei Clients für Betriebswerkzeuge greifst du öfter zu einer Fremdbibliothek oder schreibst direkt gegen die HTTP-Schnittstelle. |
| Wie leicht liest jemand Neues den bestehenden Code? | Stärke Die Sprache lässt wenige Wege zu, die Fehlerbehandlung sieht überall gleich aus, und über Formatierung wird nicht diskutiert. | Kommt darauf an Traits, Generics und Makros geben viel Ausdruckskraft. Eine Codebasis, in der jemand davon reichlich Gebrauch gemacht hat, kostet beim Einstieg echte Zeit. |
Wie schnell liefert jemand, der die Sprache heute noch nicht kann?
Wer Java, C# oder Python kann, schreibt in der ersten Woche brauchbaren Go-Code. Die Sprache ist bewusst klein gehalten, und die Spezifikation liest sich an einem Nachmittag durch.
Kompilierender Code entsteht auch hier in Tagen. Bis jemand eigene Datenstrukturen entwirft, ohne gegen die Eigentumsregeln zu laufen, vergehen erfahrungsgemäß mehrere Wochen.
Wie berechenbar ist die Antwortzeit unter Last?
Die Phasen, in denen der Sammler das Programm anhält, sind sehr kurz. Spürbar wird er über die Rechenzeit, die er nebenher belegt, und über Lastspitzen, bei denen viel gleichzeitig alloziert wird.
Speicher wird freigegeben, wenn der Besitzer endet. Es gibt keinen Sammler, der irgendwann läuft, und damit auch keine Schwankung aus dieser Richtung.
Wie viel Arbeitsspeicher belegt ein Dienst im Dauerbetrieb?
Die Laufzeitumgebung hält Halden-Speicher als Puffer vor. Ein schlanker Dienst startet trotzdem klein, bei vielen Instanzen summiert sich der Aufschlag aber sichtbar.
Ohne Laufzeitumgebung und ohne Haldenpuffer bleibt der belegte Speicher nah an dem, was die Daten tatsächlich brauchen, und er schwankt weniger.
Wie sieht es bei Rechenarbeit in der Anfrage aus?
Für die meisten Aufgaben schnell genug. Bei engen Schleifen über große Datenmengen bleibt Abstand, unter anderem weil du weniger Kontrolle über Speicherlayout und Kopien hast.
Übersetzt ohne Zwischenschicht auf Maschinencode, mit Kontrolle über Layout und Kopien. Rechenschleifen lassen sich mit Rayon über alle Kerne verteilen, ohne dass Datenrennen möglich werden.
Wie gut ist das Ökosystem für Cloud- und Betriebswerkzeuge?
Kubernetes, Docker, Terraform und Prometheus sind selbst in Go geschrieben. Clients, Operatoren und Erweiterungen für diese Welt gibt es dort zuerst und am vollständigsten.
Für HTTP-Dienste, Datenbanken, Serialisierung und Kryptografie ist die Lage gut. Bei Clients für Betriebswerkzeuge greifst du öfter zu einer Fremdbibliothek oder schreibst direkt gegen die HTTP-Schnittstelle.
Wie leicht liest jemand Neues den bestehenden Code?
Die Sprache lässt wenige Wege zu, die Fehlerbehandlung sieht überall gleich aus, und über Formatierung wird nicht diskutiert.
Traits, Generics und Makros geben viel Ausdruckskraft. Eine Codebasis, in der jemand davon reichlich Gebrauch gemacht hat, kostet beim Einstieg echte Zeit.
Was passt wann
- Wenn der Dienst überwiegend auf Datenbank und Netz wartet und in wenigen Wochen stehen soll
- nimm Go und steck die gesparte Zeit in Tests und in die Betriebsfähigkeit.
- Wenn eine Zusage zur Antwortzeit im 99. Perzentil im Vertrag steht oder pro Anfrage gerechnet wird
- nimm Rust und plan die Einarbeitung als eigenen Posten in den Fahrplan.
- Wenn aus einem laufenden Go-Dienst nur ein rechenintensives Stück heraussticht
- lass den Dienst in Go und schreib allein dieses Stück als eigene Komponente in Rust.
Fünf Fragen, und die Sprache steht fest
- 01 Wie viel Zeit einer Anfrage verbringt dein eigener Code? Bei wenig zählt Go.
- 02 Welchen Wert muss das 99. Perzentil halten? Ohne harte Zusage bleibt es bei Go.
- 03 Wie viele Instanzen laufen dauerhaft? Erst im dreistelligen Bereich zählt der Speicher.
- 04 Steckt Rechenarbeit in der Anfrage, etwa Bilder, Krypto oder große Nutzlasten?
- 05 Wie oft wechselt das Team? Häufige Wechsel sprechen für die kleinere Sprache.
Was du danach in einer Sitzung entscheidest
Die Wahl hängt an fünf Zahlen und einer Einschätzung zum Team. Alle fünf liegen entweder schon vor oder lassen sich an einem Nachmittag messen, und danach ist die Diskussion in der Regel beendet.
Die Latenzzusage konkret machen
Nicht "muss schnell sein", sondern: welches Perzentil, welcher Wert, gemessen an welcher Stelle. Wenn im 99. Perzentil ein paar Millisekunden Luft sind, ist die Frage nach dem Garbage Collector beantwortet und Go steht.
Rechenzeit von Wartezeit trennen
Miss, welcher Anteil einer Anfrage im eigenen Code liegt und welcher im Warten auf Datenbank und Netz. Ist der eigene Anteil klein, bewegt die Sprachwahl die Gesamtzahl kaum, und die Entscheidung fällt an anderen Kriterien.
Speicher pro Instanz einrechnen
Ein Rust-Dienst kommt ohne Laufzeitumgebung und ohne Haldenpuffer aus und bleibt näher an dem, was die Daten selbst brauchen. Bei fünf Instanzen ist das Rauschen, bei mehreren hundert ist es eine Zeile im Budget, die du vorher ausrechnen kannst.
Die Nebenläufigkeit richtig lesen
Goroutinen bekommst du mit der Sprache, ohne Abhängigkeit und ohne Entscheidung. Async in Rust ist eine Bibliotheksentscheidung, in der Praxis Tokio, und sie färbt die Signaturen: Eine Funktion async zu machen zieht async bis zum Einstiegspunkt hoch.
Die Einarbeitung als Termin behandeln
In Go schreibt eine erfahrene Backend-Person in der ersten Woche Code, der ins Review kann. In Rust entsteht kompilierender Code ebenfalls in Tagen, die Entwurfsentscheidungen darüber, wem Daten gehören und wann ein Klon angebracht ist, brauchen aber Wochen an echtem Code.
Fluktuation einpreisen
Go ist bewusst klein gehalten, es gibt wenige Wege, dieselbe Sache zu schreiben, und die Formatierung ist nicht verhandelbar. Wer neu dazukommt, liest bestehenden Code in Tagen. Rust gibt dir Traits, Generics und Makros, und eine Codebasis, in der jemand davon reichlich Gebrauch gemacht hat, kostet beim Einstieg echte Zeit.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Nebenläufigkeit: Goroutinen kosten nichts, async färbt den Code
In Go startest du mit einem vorangestellten go eine Goroutine, die Laufzeitumgebung verteilt sie auf Betriebssystem-Threads, und die Verständigung läuft über Kanäle. Eine Goroutine ist billig, hunderttausend gleichzeitig sind normal. Blockierende Aufrufe sind unproblematisch, weil der Planer sie kennt und die Goroutine so lange parkt.
In Rust gibt es zwei Welten. Threads aus der Standardbibliothek sind echte Betriebssystem-Threads und die richtige Wahl für Rechenarbeit. Daneben steht async mit async fn und await, das eine Laufzeitumgebung braucht, und diese Laufzeitumgebung ist eine Bibliotheksentscheidung, in der Praxis Tokio. Async ist ansteckend: Eine asynchrone Funktion lässt sich nur aus einem asynchronen Zusammenhang heraus abwarten, deshalb zieht sich die Entscheidung durch die gesamte Aufrufkette bis nach oben.
Der Unterschied, der im Betrieb zuerst weh tut, ist ein anderer. Ein blockierender Aufruf innerhalb einer asynchronen Aufgabe belegt einen Arbeiter-Thread der Laufzeitumgebung und bringt damit fremde Aufgaben zum Stillstand, die auf demselben Arbeiter liegen. In Go parkt derselbe Aufruf einfach die Goroutine. Das ist die mit Abstand häufigste Überraschung, wenn ein Go-Team nach Rust wechselt, und der Grund, warum blockierende Arbeit dort ausdrücklich auf eigene Threads gehört.
Welche Fehlerklassen die eine Sprache abnimmt und die andere nicht
Datenrennen sind in sicherem Rust ausgeschlossen. Der Compiler prüft über Send und Sync, ob ein Wert eine Thread-Grenze überschreiten darf, und geteilter veränderlicher Zugriff ohne Sperre kommt gar nicht erst durch. In Go ist die klassische Fehlerquelle eine Map oder ein Slice, in die mehrere Goroutinen schreiben. Das übersetzt anstandslos und fällt unter Last auseinander. Der eingebaute Race Detector, den du mit go test -race einschaltest, findet es, allerdings nur, wenn ein Testlauf den betreffenden Pfad tatsächlich nimmt.
Beim Umgang mit Fehlern und mit fehlenden Werten unterscheiden sich beide ebenfalls. In Go ist der Fehler ein zusätzlicher Rückgabewert, den du mit einem Unterstrich wegwerfen kannst, und der Zugriff auf einen nil-Zeiger bricht zur Laufzeit ab. In Rust ist Result ein Typ, der eine Warnung auslöst, wenn du ihn nicht auswertest, und Option zwingt dich, den leeren Fall zu behandeln, bevor du an den Wert kommst.
Was keine der beiden Sprachen ausschließt: Verklemmungen zwischen zwei Sperren, unbegrenzt wachsende Warteschlangen, Logikfehler und blockierende Aufrufe an der falschen Stelle. Wer Rust mit "keine Nebenläufigkeitsfehler mehr" verkauft, hat die Zusage falsch wiedergegeben. Sie lautet: keine Datenrennen.
Was der Betrieb von beiden merkt
Beide liefern ein einzelnes Programm ohne Laufzeitumgebung daneben, und beide starten in Millisekunden, was für Dienste zählt, die auf null skalieren oder als kurzlebige Aufgaben laufen. Ein Detail lohnt trotzdem die Aufmerksamkeit: Ein Go-Programm ohne cgo ist standardmäßig statisch gebunden, ein Rust-Programm für Linux bindet die C-Bibliothek des Systems dynamisch ein. Wenn du ein wirklich statisches Programm für ein minimales Container-Abbild brauchst, baust du in Rust gegen das musl-Ziel, und das ist eine Zeile in der Baukonfiguration, an die man einmal denken muss.
Bei Metriken, Ablaufverfolgung und Protokollierung ist Go im Vorteil, weil die Werkzeuge dieser Welt selbst in Go geschrieben sind und die zugehörigen Bibliotheken dort zuerst erscheinen. In Rust deckt das tracing-Ökosystem denselben Bedarf ab, Anbieter-Bibliotheken kommen aber häufig später und manchmal nur als Beitrag aus der Gemeinschaft.
Die Bauzeit ist der Punkt, den Teams im Vergleich am häufigsten übersehen. Go baut schnell, das war ein erklärtes Entwurfsziel. Rust baut langsam. Bei einem mittelgroßen Projekt ist das der Unterschied zwischen einem Durchlauf von zwei Minuten und einem von einer Viertelstunde, und er wirkt bei jeder Änderung. Cargo check für die Rückmeldung beim Schreiben, eine Aufteilung in mehrere Crates und ein Zwischenspeicher für Bauartefakte im Bauserver holen einen Teil davon zurück, aber eben nur einen Teil.
Die Fälle, in denen die Frage gar nicht gestellt werden muss
Wenn das Team bereits Go schreibt und der nächste Dienst wieder eine Schnittstelle mit Datenbank dahinter ist, gibt es nichts zu entscheiden. Der Wechsel müsste sich gegen eine funktionierende Praxis rechnen, und das tut er in diesem Fall nicht.
Umgekehrt gibt es Fälle, in denen Go schlicht ausfällt. Wenn eine native Bibliothek entstehen soll, die aus Python, Node oder der JVM heraus aufgerufen wird, ist das Rust-Gebiet: Go bringt seine eigene Laufzeitumgebung mit, die Threads besitzen will, und die Grenze über cgo ist teuer und heikel. Dasselbe gilt für Software ohne Betriebssystem darunter, etwa auf einem Mikrocontroller. Und bei WebAssembly können zwar beide das Ziel bedienen, die Werkzeuge und Bibliotheken auf der Rust-Seite sind dort aber weiter.
Der dritte klare Fall ist ein sehr kleines Team mit häufigem Wechsel. Dann gewinnt die Sprache, die weniger Wege kennt, dieselbe Sache zu schreiben, und das ist Go. Diese Überlegung wiegt in der Praxis schwerer als jeder Messwert, weil sie jeden Monat wirkt und nicht nur im Lastversuch.
Dazu passende Kurse
Wenn diese Abwägung im Team ansteht und nicht jeder dieselbe Vorstellung von Rust mitbringt, sind Rust-Kurse für Backend-Teams der schnellste Weg zu einer gemeinsamen Grundlage.
Fällt die Wahl auf die kleinere Sprache, kannst du bei cmt Go von Grund auf lernen .
Wie sicher bist du beim Thema wirklich?
Lesen fühlt sich schnell nach Können an. Ein kurzer Test zeigt dir, was davon schon sitzt und wo sich ein Kurs lohnt. Kostenlos, ohne Anmeldung, mit einer Erklärung zu jeder Antwort.
Wo du genau das übst
Sehr angenehmes, gut vorbereitetes Seminar, kann ich nur empfehlen.
Häufige Fragen
Ist Rust wirklich schneller als Go?
Können wir beide Sprachen nebeneinander betreiben?
Sind Goroutinen und Rust-Aufgaben dasselbe?
Wie lange braucht ein Go-Team für den Umstieg auf Rust?
Deine Ansprechpartner
Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.
Yves Hoppe
Weiterbildung & Beratung
Hilft dir, aus dem Rust-Programm den passenden Kurs für deinen Stand zu finden.
Norbert Jansen
Beratung & Inhouse
Plant mit dir Inhouse-Trainings, die auf eure Abläufe und euren Datenbestand zugeschnitten sind.
Die Entscheidung an einem echten Dienst durchspielen
Bei cmt baust du im Rust-Kurs einen Netzwerkdienst von Grund auf und siehst dabei genau die Stellen, an denen Go dir Arbeit abnimmt und Rust dir Zusagen erlaubt.
Passt dazu
- Rust oder C++: Wann sich der Wechsel für ein bestehendes Team rechnet
- Axum, Actix Web oder Rocket: welches Rust-Framework euer Dienst braucht
- Async oder Threads: Welches Nebenläufigkeitsmodell dein Rust-Dienst braucht
- Lohnt sich Rust für euer Team? Die Rechnung mit beiden Seiten