Am Samstag, dem 4. April 2026, begann die AppView-Datenebene von Bluesky – das Backend, das die Lesevorgänge der Social-App bedient – Fehler zu protokollieren wie „failed to set post cache item: dial tcp: bind: address already in use“. Die Datenebene stützt sich stark auf memcached, um Last von ihrer Haupt-Scylla-Datenbank fernzuhalten, und Jim Calabro, der diensthabende Infrastruktur-Ingenieur, sah, dass die Log-Spitzen mit Einbrüchen im nutzerseitigen Traffic zusammenfielen. Das Netzwerk-Monitoring war unauffällig, sodass die Ursache über das Wochenende verborgen blieb, während der Dienst vor sich hin humpelte.

Die Grundursache war ein neuer interner Dienst, der in jener Woche deployt wurde: unter drei GetPostRecord-Anfragen pro Sekunde, aber 15.000–20.000 Post-URIs pro Stapel (normal sind 1 bis 50). Jeder RPC-Handler der Datenebene begrenzt die Nebenläufigkeit mit errgroup.SetLimit – allein diesem Endpunkt fehlte diese Zeile. Ein einzelner Aufruf erzeugte bis zu 20.000 Goroutines, die einen Sturm von memcached-Verbindungen aufbauten; sobald der Leerlauf-Pool von 1.000 Sockets überlief, sammelten sie sich in TCP TIME_WAIT an und erschöpften jeden ephemeren Port. Der Client lief in einem einzigen Rechenzentrum, und ohne Metriken pro Client verdeckten Cache-Fehler jeder Art den Verursacher.

Am Montag, dem 6. April, kippte es in eine Todesspirale: Da Millionen von memcached-Anfragen pro Sekunde fehlschlugen, versuchte Blueskys Richtlinie, jeden Fehler zu protokollieren, Millionen blockierender write(2)-Log-Schreibvorgänge pro Sekunde. Die Flut blockierender Systemaufrufe trieb die Go-Runtime von etwa 150 auf 1.500 OS-Threads und hungerte den GC in lange Stop-the-World-Pausen aus. Aggressiv abgestimmte GOGC- und GOMEMLIMIT-Einstellungen ließen die Datenebene periodisch OOM-abstürzen – etwa 30 Minuten oben, runter, und wieder von vorn. Jeder Neustart vertiefte das Loch: TIME_WAIT-Sockets verhinderten, dass der neu gestartete Prozess seinen memcached-Pool neu aufbauen konnte.

Das Montags-Pflaster war herrlich absurd: ein eigener Dialer, der für jede ausgehende Verbindung eine zufällige 127.x.y.z-Loopback-IP wählte und so den ip+port-Raum über den erschöpften Bereich hinaus erweiterte. Das stoppte die Spirale, und erst am Mittwoch fand das Team die wahre Grundursache und stellte das fehlende SetLimit(50) wieder her. Calabros öffentliche Post-Mortem-Analyse räumte zudem ein Kommunikationsversagen ein: Die Statusseite hatte einem Drittanbieter-Netzwerkanbieter die Schuld gegeben, was „es eindeutig nicht war“.

Etwa acht Stunden lang am 6. April 2026 zeitweise Ausfälle für ungefähr die Hälfte aller Bluesky-Nutzer – die schlimmste Störung der Plattform in der Zeit, die der Infrastruktur-Leiter dort erlebte

Begrenzte Nebenläufigkeit wurde durch Konvention durchgesetzt, nicht durch Struktur: Jeder Handler hatte SetLimit außer einem, und ein einziger unbegrenzter Endpunkt reichte aus, um Ressourcen auf Host-Ebene zu erschöpfen.

Der Traffic-Vertrag hatte keine Formgrenzen: Nichts wies einen Stapel mit 20.000 Elementen zurück, sodass ein unauffälliger interner Client – 3 Anfragen pro Sekunde – Millionen normale Clients als Lastquelle überragte.

Die Fehlerbehandlung verstärkte den Fehler: Das Protokollieren jedes memcached-Fehlers bei Millionen Fehlern pro Sekunde verwandelte ein Cache-Problem in eine Thread-Explosion, GC-Pausen und OOM-Abstürze.

Die Observability ging von kleinen Anfragen aus und hatte keine Metriken pro Client, sodass Fehler aus jedem Cache-Typ den einen verantwortlichen Aufrufer und den einen Endpunkt tagelang verbargen.

Neustart als Wiederherstellung war kaputt: TIME_WAIT-Sockets des toten Prozesses blockierten den neuen Prozess beim Wiederaufbau seiner memcached-Pools und verwandelten OOM-Neustarts in weitere Port-Erschöpfung.

Eine einzige unbegrenzte Goroutine-Schleife wog schwerer als jede andere Schutzmaßnahme. Nebenläufigkeitslimits müssen strukturell sein, nicht eine Gewohnheit pro Endpunkt: Der einzige Endpunkt, dem eines fehlte, wurde zum gesamten Vorfall.

Der Dienst wurde am Montag mit dem Zufalls-Loopback-Dialer stabilisiert, der entfernt wurde, sobald die eigentliche Lösung – die Wiederherstellung des Nebenläufigkeitslimits – am Mittwoch, dem 8. April, landete. Die Gesamtexposition betrug etwa acht Stunden zeitweiser Ausfälle für ungefähr die Hälfte der Nutzer. Die am 10. April 2026 veröffentlichte Post-Mortem-Analyse versprach Observability pro Client, die Erkennung von Clients, die wenige überdimensionierte Anfragen senden, und einen Wechsel von hochvolumigem Logging hin zu Prometheus-Metriken und OpenTelemetry-Tracing; sie zog zwei Tage später eine detaillierte unabhängige Analyse des Zuverlässigkeitsforschers Lorin Hochstein nach sich.

DEN BELEGEN FOLGEN

Die Quellen

  1. April 2026 Outage Post-Mortem Jim Calabro (Bluesky infrastructure engineer), pckt.blog · pckt.blog ·
  2. Thoughts on the Bluesky public incident write-up Surfing Complexity (Lorin Hochstein) · surfingcomplexity.blog ·
  3. Bluesky April 2026 Outage Post-Mortem (discussion, 141 points) Hacker News · news.ycombinator.com ·