Dev News Daily ENDE

Cloudflare spart 100TB RAM, weil 90 Prozent des Hash-Rings nichts brachten

Am Anfang stand ein gewöhnliches Ticket: Der Pingora Backend Router, Cloudflares interner Load Balancer, belegte deutlich mehr Speicher als erwartet, und zwar in Strukturen von pingora-ketama — der quelloffenen Bibliothek des Hauses für konsistentes Hashing. Am Ende der Untersuchung standen über 100TB zurückgewonnener Arbeitsspeicher in der gesamten Flotte, zusätzlich zu weiteren 100TB, die das DNS-Team einen Monat zuvor freigeräumt hatte.

Konsistentes Hashing sorgt dafür, dass eine Anfrage immer beim selben Server landet, ohne dass beim Hinzufügen oder Entfernen einer Maschine alles neu verteilt werden muss. Server und Cache-Schlüssel werden auf dieselbe Zahlengerade gehasht, eine Aufgabe geht an den nächsten Server links davon. Damit die Last gleichmäßig verteilt ist, steht ein Server nicht für einen Punkt, sondern für viele — skaliert mit einem Gewicht, bei Cloudflare der Plattenplatz, weil die Arbeitslast speichergebunden ist. Die Basis lag bei 160 Punkten pro Server, multipliziert mit diesem Gewicht: für eine typische Maschine 160 × 625 = 100.000 Punkte.

Die Zahl, die niemand nachgerechnet hatte

Interessant ist nicht die Lösung, sondern was die Rechnung über den bestehenden Zustand aussagte. Der Verteilungsfehler sinkt mit der Zahl der Hash-Punkte — aber logarithmisch: Der Sprung von 10.000 auf 100.000 Punkte pro Server bringt 0,7 Prozent weniger Fehler. Neunzigtausend Punkte pro Server wurden für weniger als ein Prozent bezahlt.

Dann traf das Modell auf die Implementierung. Die saubere Mathematik geht von einem kontinuierlichen Ring aus, im Betrieb laufen 32-Bit-Hashes. In einem Rechenzentrum mit 2.048 Servern führen die Kollisionen zwischen 10.000 und 100.000 Punkten dazu, dass Beiträge zufällig wegfallen — jenseits eines bestimmten Punkts macht mehr Hashing die Verteilung also unberechenbarer statt besser. Das Team reduzierte die Punkte pro Server um 90 Prozent, ohne eine nennenswerte Verschlechterung der Balance zu messen.

Und dann der Rust-Teil

Cloudflare spart 100TB RAM, weil 90 Prozent des Hash-Rings nichts brachten
Cloudflare spart 100TB RAM, weil 90 Prozent des Hash-Rings nichts brachten — Dev News Daily

Die zweite Ersparnis steckte in der Form einer einzigen Struktur. Ein Hash-Punkt besteht aus einem 32-Bit-Hash und einem 16-Bit-Serverindex — sechs Byte Information, die der Compiler bereitwillig auffüllte. Als rohes Byte-Array mit Zugriffsfunktionen gespeichert:

struct Point([u8; 6]);
impl Point {
    fn hash(&self) -> u32 { u32::from_ne_bytes(self.0[0..4].try_into().unwrap()) }
    fn index(&self) -> u16 { u16::from_ne_bytes(self.0[4..6].try_into().unwrap()) }
}

Allein das nahm 25 Prozent des Speichers für konsistentes Hashing heraus, und beide Varianten erzeugen denselben Maschinencode. Der Umstieg lief mit beiden Ringen parallel — Routing-Entscheidungen und Origin-Traffic wurden verglichen, bis die Migration 100 Prozent erreichte. Der Speicherverlauf zeigt den Absturz an dem Tag, an dem der alte Ring endgültig abgeschaltet wurde.

Was das bedeutet

Teuer war eine Voreinstellung, die niemand neu hergeleitet hatte. 160 Punkte pro Server ist eine Zahl mit Geschichte — sie stammt aus der ursprünglichen ketama-Implementierung — und wurde mit einem Gewicht multipliziert, das sie gewaltig machte, ohne dass jemand fragte, was die zusätzlichen Punkte eigentlich einbringen. Genau dieses Muster lohnt sich im eigenen System zu suchen: eine Konstante, gewählt für eine kleine Installation, linear in eine große skaliert, verteidigt nur dadurch, dass es funktioniert.

Logarithmische Erträge sind das Warnsignal. Wo Genauigkeit mit dem Logarithmus einer Ressource wächst, ist die letzte Größenordnung fast geschenkt. Nur plottet kaum ein Team diese Kurve, weil die Einstellung nicht im heißen Pfad liegt und niemanden nachts weckt.

Die Theorie hat außerdem eine Hardware-Kante. Die Mathematik hörte genau dort auf, die Realität zu beschreiben, wo der 32-Bit-Hashraum zu kollidieren begann — das Modell war also gleichzeitig richtig und unbrauchbar, und erst die Simulation mit der echten Integerbreite zeigte, wo die Kurve kippt. Wer mit einer Formel aus einem Paper tuned, sollte prüfen, welche ihrer Annahmen die eigenen Datentypen stillschweigend verletzen.

Die Änderungen stecken bereits in der pingora-ketama-Crate hinter einem bislang nicht beworbenen Cargo-Feature: Der v2-Ring bringt das kompakte Speicherformat, eine schnellere Sortierung und die Möglichkeit, mit deutlich weniger Punkten zu laufen.