PRODSouveräne europäische BaaS-PlattformÖffnen Sie das Dashboard →

Leistung · 10 Min. Lesezeit

Warum kein Garbage Collector die p99-Latenz ändert

Affane Daylami · Fondateur · 2. Juli 2026

Zurück zum Blog

p99 misst die langsamste Anfrage von hundert – diejenige, die Ihr SLA durchbricht, während der Durchschnitt perfekt bleibt. In einem Backend mit hohem Datenverkehr haben diese wenigen langsamen Anfragen oft eine einzige Ursache: den Garbage Collector, der das gesamte Programm unterbricht, um Speicher freizugeben. Rust hat keinen Garbage Collector. Hier ist der Mechanismus, mit veralteten Drittquellen und nicht mit einer Marketingzahl.

Dieser englische Text wurde automatisch aus dem französischen Original generiert und wurde noch nicht überprüft.
Diese Seite wurde automatisch übersetzt. Maßgeblich ist die englische Version.

Dieser Artikel stützt sich ausschließlich auf veraltete Quellen Dritter – niemals auf eine erfundene Aurabase-Chiffre. Es ist keine für unser Backend spezifische p99-Latenz enthalten. Wir schreiben unseren Anwendungskern in Rust, ohne Garbage Collector: eine Tatsache, die direkt im Code, Workspace Cargo und Axum Services überprüft werden kann. Allerdings haben wir noch keine reproduzierbare p99-Benchmark-Methodik veröffentlicht, um dies in Zahlen zu belegen. Dieser Text erklärt einen Mechanismus, kein gemessenes Ergebnis.

Das Wesentliche

  • p99 misst die langsamste Abfrage von hundert – die Stelle, an der eine Garbage Collector (GC)-Pause am meisten schmerzt, nicht im Durchschnitt (Dean & Barroso, „The Tail at Scale“, Google, 2013).
  • Ein GC unterbricht das gesamte Programm („Stop-the-World“), um ungenutzten Speicher freizugeben. Rust hat keinen GC: Speicher wird genau dann freigegeben, wenn ein Wert den Gültigkeitsbereich verlässt, was vom Compiler überprüft wird.
  • Discord dokumentierte im Jahr 2020 einen Cache-Dienst, bei dem Go mindestens alle zwei Minuten einen Garbage-Collection-Zyklus auslöste, wobei jeder Zyklus einen Anstieg der Latenz verursachte (Discord Engineering Blog).
  • Die Reduzierung einer GC-Pause erfordert jahrelange Entwicklungsarbeit, selbst bei Google: Der GB-Kollektor stieg zwischen 2015 und 2018 von 300–400 ms auf 500 µs, ohne jemals Null zu erreichen (go.dev).
  • Der Backend-Kern von Aurabase ist in Rust geschrieben, ohne Garbage Collector – im Code verifiziert. Bisher wurden keine p99-Aurabase-Latenzzahlen veröffentlicht: Dies bleibt ein Mechanismus, keine Messung.
#
Schwanzlatenz

Warum p99 nicht durchschnittlich ist

Ein Durchschnitt verbirgt das Wesentliche. Wenn 99 von 100 Anfragen in 5 ms antworten und nur eine 500 ms benötigt, bleibt der Durchschnitt niedrig. Aber jeder hundertste Benutzer muss hundertmal länger warten. Der p99 misst genau diese Anfrage: das langsamste Hundertstel, das gegen Ihr SLA verstößt, während Ihr Dashboard für die durchschnittliche Latenz grün bleibt.

Bei Google haben Jeffrey Dean und Luiz André Barroso dieses Problem in „The Tail at Scale“ (Communications of the ACM, Bd. 56, 2013) formalisiert. Ihre Beobachtung wird seitdem oft zitiert: „Vorübergehende Episoden mit hoher Latenz, die in mittelgroßen Systemen unwichtig sind, können in großem Maßstab die Gesamtleistung des Dienstes dominieren.“ Kurz gesagt: Gelegentliche Latenzepisoden, die im kleinen Maßstab vernachlässigbar sind, dominieren letztendlich die wahrgenommene Leistung eines verteilten Systems.

Ein Backend, das Tausende von Anfragen pro Sekunde verarbeitet, muss irgendwann einmal eine Anfrage senden, die während einer GC-Pause fällt. Im großen Maßstab ist dies kein ungewöhnlicher Fall. Dies ist eine statistische Gewissheit.

#
GC-Mechanik

Was ein Garbage Collector tut und warum er alles anhält

Ein Garbage Collector (GC) verfolgt kontinuierlich die lebenden Objekte eines Programms – diejenigen, auf die noch irgendwo verwiesen wird – und gibt den Speicher von Objekten frei, auf die nicht mehr zugegriffen werden kann. Diese Nachverfolgung wird als tracingbezeichnet: Der GC geht das Referenzdiagramm durch, markiert, was noch verwendet wird, und durchsucht dann den Rest.

Das Problem: Das Durchlaufen dieses Diagramms, während das Programm weiterhin neue Referenzen erstellt, führt zu inkonsistenten Ergebnissen. Die historische Antwort, die von vielen modernen GCs immer noch als letzter Ausweg verwendet wird, ist stop-the-world – das gesamte Programm pausiert während des Markierens und Scannens. Je größer der Heap, desto länger ist in der Regel die Pause: Ihre Dauer hängt von der Größe der Live-Daten ab, nicht von der aktuellen Arbeitslast.

Die meisten modernen GCs verwenden eine Generationenstrategie: Sie gehen davon aus, dass die meisten Objekte jung sterben. Aktuelle Belegungen werden daher häufig, aber schnell, in einem kleinen Speicherbereich gescannt. Objekte, die mehrere Zyklen überleben, wandern in einen größeren Bereich und werden seltener gescannt. Wenn dieser Bereich jedoch gereinigt werden muss, wächst die damit verbundene Pause mit seiner Größe. Es ist diese „große“ Unterbrechung, nicht die kleinen „kleinen“ Unterbrechungen, die das p99 eines stark frequentierten und zuteilungsstarken Dienstes dominiert.

Infos

Moderne gleichzeitige und generationsübergreifende GCs reduzieren die Häufigkeit und Dauer dieser Pausen, indem sie parallel zum Programm arbeiten. Aber fast alle von ihnen verfügen über einen „Stop-the-World“-Fallback-Mechanismus für Grenzfälle – und dessen Reduzierung erfordert jahrelange Entwicklungsarbeit. Abschnitt 04 enthält ein quantifiziertes und beschafftes Beispiel.

#
Echter Fall

Discord, 2020: Eine GC-Pause wird zum Produktionsvorfall

Im Februar 2020 veröffentlichte der Ingenieur Jesse Howarth einen Beitrag, der in der Branche zu einer Referenz geworden ist: „Warum Discord von Go zu Rust wechselt“ (Discord Engineering Blog). Der entsprechende Dienst, Read States, verwaltet den Lesestatus von Nachrichten für Millionen von Benutzern – zig Millionen Einträge pro Cache – mit Hunderttausenden Aktualisierungen pro Sekunde.

Die Diagnose ist direkt und wird im Artikel zitiert: „Go erzwingt mindestens alle 2 Minuten einen Garbage Collection-Lauf.“ Mit anderen Worten: Go löst bei diesem Dienst mindestens alle zwei Minuten einen Garbage-Collection-Zyklus aus – und jeder Zyklus führt zu einem Anstieg der Latenz, der in den Diagrammen des Teams sichtbar ist.

Das Team reduzierte zunächst die Cache-Größe, um die Spitzen auszugleichen. Der Kompromiss blieb ungünstig: weniger GC-Pausen, aber mehr Cache-Miss-Anfragen, die auf die Datenbank fallen – daher insgesamt eine Verschlechterung des p99 an anderer Stelle. Die grundlegende Lösung bestand darin, den Dienst in Rust neu zu schreiben, ohne dass ein Garbage Collector überwacht werden musste.

Der Beitrag löste eine lebhafte technische Debatte aus: Mehr als 1.580 Punkte und 642 Kommentare auf Hacker News am selben Tag seiner Veröffentlichung (4. Februar 2020) – ein Zeichen dafür, dass das Problem weit über den Discord-Fall hinausgeht.

#
Gehen Sie in die Geschichte

Drei Jahre Entwicklungsarbeit bei Google, um eine Pause von 400 ms auf 500 µs zu senken

Der Garbage Collector von Go veranschaulicht den Umfang des Aufwands, der erforderlich ist, um eine GC-Pause zu bändigen – selbst mit den Ressourcen eines engagierten Teams bei Google. Rick Hudson, technischer Leiter von Go GC, hat diese Geschichte in zwei offiziellen Go-Blogbeiträgen dokumentiert.

Vor August 2015300–400 msHistorischer Go-Sammler, vor der Neugestaltung
August 2015 · Go 1.530-40 msErster konkurrierender Kollektor, Ziel < 10 ms festgelegt
2016 · Go 1.6< 10 ms (SLO gehalten)Erstes Ziel in der Produktion erreicht
März 2017 · Go 1.8unter der MillisekundeStop-the-World-Stack-Scan wird entfernt
August 2017 · Go 1.9100-200 µs (Markierung)Neuer informeller Benchmark, der vom Team erwähnt wurde
2018 · SLO angekündigt500 µs pro ZyklusVon Rick Hudson formalisiertes Serviceziel

Quelle: „Getting to Go: The Journey of Go’s Garbage Collector“, go.dev, 12. Juli 2018; und „Go GC: Priorisierung geringer Latenz und Einfachheit“, go.dev, 31. August 2015.

Drei Jahre engagierter Arbeit haben die typische Pause um den Faktor Tausend verkürzt. Aber die Pause verschwand nie: Es handelt sich um ein Serviceziel (SLO), nicht um eine absolute Nullgarantie. Eine GC-Ablaufverfolgung muss konstruktionsbedingt von Zeit zu Zeit einen Graphen lebender Objekte durchlaufen. Die einzige einstellbare Variable ist die Häufigkeit und Dauer dieser Reise – nicht ihre Existenz.

Diese Prioritätswahl ist nicht neutral. Go zielt in erster Linie auf Netzwerkdienste und Web-Backends ab, bei denen eine Pause von mehreren hundert Millisekunden das Benutzererlebnis direkt beeinträchtigt – daher der enorme Aufwand, der in die Latenz und nicht in den reinen GC-Durchsatz investiert wird. Andere verwaltete Laufzeiten übernahmen unterschiedliche Kompromisse, die von ihren historischen Anwendungsfällen geprägt waren, bevor sie mit ihren eigenen Low-Pause-Collectors Boden gut machten. Der gemeinsame Punkt bleibt derselbe: Sie alle gehen von der GC-Verfolgung aus, also von einem Pausenmechanismus, der minimiert und niemals durch die Konstruktion beseitigt werden muss.

#
Rostmechanik

Warum Rust dieses Problem konstruktionsbedingt nicht hat

Rust reduziert GC-Pausen nicht: Es eliminiert den Mechanismus, der sie verursacht. Der Compiler verfolgt beim Kompilieren, wem der jeweilige Speicherwert gehört – das istownership. Wenn der Besitzer eines Werts den Gültigkeitsbereich verlässt, fügt Rust automatisch den Aufruf, der diesen Speicher freigibt, an derselben Stelle im Binärcode ein. Dieser Mechanismus wird als RAII (Resource Acquisition Is Initialization) bezeichnet: Die Freigabe erfolgt deterministisch und wird nicht durch einen im Hintergrund laufenden Garbage Collector geplant.

Alexandru Nedelcu, Autor eines im Scala/Rust-Ökosystem anerkannten technischen Blogs, fasst den Kompromiss in einem kürzlich erschienenen Artikel zusammen: „Der Kompromiss, den Rust eingeht, besteht in der Benutzerfreundlichkeit, gegenüber Leistung mit vorhersehbarer Latenz und Sicherheit“ (alexn.org, 21. Juli 2026). Rust tauscht einen Teil der Einfachheit des Schreibens gegen vorhersehbare Latenz ein.

Derselbe Artikel fasst zusammen, warum moderne GCs nicht immer ausreichen: „Moderne GCs versuchen, ihre Arbeit inkrementell und gleichzeitig zu erledigen, ohne das Programm zu beeinträchtigen. Aber ihre Fähigkeit ist begrenzt und greift auf einen Stop-the-World-GC-Zyklus zurück, der das gesamte Programm einfriert und so die Latenz beeinträchtigt.“

Hier ist der Mechanismus in etwa zehn Zeilen – ein allgemeines Beispiel, kein Auszug aus dem Aurabase-Code:

example.rsrust
struct Connection {
    id: u32,
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("connexion {} fermée", self.id);
    }
}

fn handle_request() {
    let conn = Connection { id: 42 };
    // ...bearbeitet die Anfrage...
} // conn verlässt hier den Gültigkeitsbereich: drop() wird ausgeführt
   // im genauen Moment, vom Compiler überprüft –
   // nicht durch einen Garbage-Collection-Zyklus.

Wichtige Nuance: Nicht alles ist kostenlos. Referenzzähltypen (Rc, Arc) verursachen bei jedem Klon und jeder Veröffentlichung geringe Kosten. Diese Kosten bleiben lokal und deterministisch. Es gibt nie eine Pause, die das gesamte Programm einfriert, während es einen Speicherheap durchläuft.

Nützliche Klarstellung für ein asynchrones Backend: Die asynchrone Rust-Laufzeit (tokio, die von allen Aurabase-Diensten verwendet wird) hat nichts mit einem Garbage Collector zu tun. Es plant kooperative Aufgaben für einen Thread-Pool, durchläuft jedoch niemals einen Live-Objektgraphen, um Speicher freizugeben. In Ökosystemen, in denen die asynchrone Laufzeit und der GC von derselben virtuellen Maschine verwaltet werden, kommt es häufig zu Verwirrung.

#
Architektonische Implikation

Was sich dadurch für ein Backend mit hohem Datenverkehr ändert

In einem Backend, das Tausende gleichzeitiger Anfragen bearbeitet, wird durch das Fehlen von GC eine Variable aus der Gleichung p99 entfernt. Es ist nicht mehr erforderlich, die Größe eines Speicher-Heaps zu bestimmen, die Generationen eines Kollektors anzupassen oder einen Zyklus zu überwachen, der zum ungünstigsten Zeitpunkt ausfallen kann. Die Latenz einer einzelnen Anfrage hängt von ihrer eigenen Arbeit ab und nicht von einem unvorhersehbaren globalen Ereignis an anderer Stelle im Programm.

Der Backend-Kern von Aurabase wendet dieses Prinzip an: Alle Dienste (aura-gateway, aura-auth, aura-db, aura-realtime, aura-storage, aura-functions, aura-ai…) sind in Rust geschrieben und in einem einzigen Cargo-Arbeitsbereichorganisiert. Dies kann direkt im Repository überprüft werden:

Cargo.tomltoml
[workspace]
resolver = "2"

members = [
    "services/aura-gateway",
    "services/aura-auth",
    "services/aura-db",
    # ...9 weitere Dienste + gemeinsam genutzte Bibliotheken
]

[workspace.dependencies]
axum = { version = "0.8", features = ["ws", "multipart", "macros"] }

Tatsächlicher Auszug aus Cargo.toml, Workspace Edition 2021, Resolver v2 – im Aurabase-Repository überprüft.

Was diese Tatsache zum jetzigen Zeitpunkt noch nicht beweist: ein für Aurabase gemessener p99-Latenzwert. Wir haben noch keine reproduzierbare Benchmark-Methodik für unser eigenes Backend veröffentlicht – dies ist eine laufende Arbeit und kein heute verfügbares Ergebnis. Das Fehlen eines Garbage Collectors ist ein im Code verifizierter Mechanismus. Dies allein ist kein Beweis für die gemessene p99-Latenz. Behalten Sie diese Unterscheidung bei allen Marketingargumenten zu diesem Thema, einschließlich unserer, im Hinterkopf – Einzelheiten zur Architektur finden Sie in unserem technischen Vergleich Aurabase vs. Supabase.

Die korrekte Messung eines p99 erfordert eine eigene Disziplin: repräsentative Lastbedingungen, über ein ausreichend breites Schiebefenster berechnete Perzentile und eine produktionsnahe Testumgebung. Die Veröffentlichung einer Zahl ohne diese Methodik ist wie die Veröffentlichung einer Marketingzahl. Genau das verweigern wir in diesem Artikel.

#
Nuance

Was das Fehlen von GC nicht löst

No-GC ist kein Zauberstab

Durch das Entfernen des Garbage Collectors wird nur eine Quelle der Tail-Latenz beseitigt – nicht alle. Ein Rust-Backend kann aufgrund von Netzwerkwartezeiten, einem gesättigten Postgres-Verbindungspool, einer umstrittenen Datenbanksperre, einer schlecht indizierten SQL-Abfrage oder einem langsamen API-Aufruf eines Drittanbieters immer noch einen verschlechterten p99 anzeigen. Der in diesem Artikel beschriebene Mechanismus beseitigt eine strukturelle Ursache. Es bietet keine Immunität gegen andere.

Bei Aurabase beispielsweise kommuniziert jeder Dienst über einen Verbindungspool (sqlx) mit Postgres und über NATS JetStreammit anderen Diensten. Ein zu kleiner Pool, ein NATS-Abonnement mit langsamer Nutzung oder eine SQL-Abfrage ohne geeigneten Index erzeugen jeweils ihre eigene Latenzspitze – unabhängig vom Fehlen eines Garbage Collectors.

Die praktische Schlussfolgerung: Das Fehlen von GC ist ein guter architektonischer Grund, ein Rust-Backend für ein p99-fähiges System zu wählen. Dies ist an sich keine Garantie für Latenz – weder bei Aurabase noch anderswo. Die Methode, auf die es ankommt, bleibt dieselbe: Messen, die Methodik veröffentlichen und dann korrigieren, was die Messungen ergeben. Wenn Sie von einem Backend mit GC migrieren, erfahren Sie in unserem Migrationsleitfaden Supabase zu Aurabase, was sich ändert und was gleich bleibt.

#
Häufig gestellte Fragen

FAQ: Garbage Collector und p99-Latenz

Garantiert das Fehlen eines Garbage Collectors einen niedrigen p99-Wert?+
Nein. Es beseitigt eine strukturelle Quelle unvorhersehbarer Pausen, aber auch andere Faktoren – Netzwerk, Verbindungspool, Datenbanksperren – beeinflussen die Endlatenz. Siehe den Abschnitt „Was kein GC nicht behebt“ oben.
Warum hat Discord seinen GC Go nicht einfach anders abgestimmt?+
Das Team hat mehrere Optimierungen ausprobiert, darunter eine Reduzierung der Cache-Größe, die in seinem Beitrag aus dem Jahr 2020 dokumentiert ist. Der Kompromiss blieb ungünstig: weniger GC-Pausen im Vergleich zu mehr Cache-Fehlern. Durch das Umschreiben in Rust wurde der Kompromiss entfernt, anstatt ihn zu verschieben.
Haben moderne GCs wie Go das Problem gelöst?+
Sie haben es massiv reduziert – Gos GC stieg zwischen 2015 und 2018 von 300-400 ms auf 500 Mikrosekunden (go.dev) – aber nicht beseitigt. Eine GC-Ablaufverfolgung behält konstruktionsbedingt einen Pausenmechanismus für Randfälle bei.
Hat Aurabase einen p99-Latenz-Benchmark veröffentlicht?+
Noch nicht. Die im Code verifizierte Tatsache ist das Fehlen eines Garbage Collectors (Rust, Workspace Cargo, Axum Services). Die gemessene p99-Latenzzahl und ihre reproduzierbare Methodik müssen noch veröffentlicht werden – wir bevorzugen keine Zahl gegenüber einer Zahl ohne Quelle.

BEREIT ZUM EINSATZ?

Ihr Backend in fünf Minuten.

Keine Kreditkarte erforderlich · 500 MB kostenlos · 50.000 MAU