Ausfall vom 6. Dezember: Maßnahmen und Lösungen
Am 6. Dezember ist eingetreten, was wir immer am meisten fürchten. Um 13:23 Uhr bemerkten wir Kapazitätsprobleme auf unserer Plattform. Es stellte sich schnell heraus, dass es sich um ein schwerwiegendes Problem handelte, das in vielen Anwendungsfällen zu Ausfallzeiten führte. Es tut uns außerordentlich leid, dass wir dies zugelassen haben. Verfügbarkeit und Zuverlässigkeit sind entscheidend für den Dienst, den wir unseren Kundinnen und Kunden bieten. Deshalb arbeiten wir hart daran, dass solche Ausfälle so selten wie möglich vorkommen.

Statt Ihnen nur eine Entschuldigung anzubieten, möchten wir Ihnen jedoch einen Blick hinter die Kulissen gewähren und Ihnen genau zeigen, was wir getan haben, um das Problem so schnell wie möglich zu beheben.
Sehen wir uns ein detailliertes Post-mortem der Ereignisse an.
Chronologie der Ereignisse:
13:12 - Wir haben Vorbereitungen für die Umstellung auf eine VPC-basierte Infrastruktur ausgerollt. Dazu gehörten neue Umgebungsvariablen mit Konfigurationen, die spezifisch für die neue VPC gelten, die wir für jede Region erstellen – etwa die Subnetze, Sicherheitsgruppen und Load Balancer, zu denen Maschinen hinzugefügt werden. Darüber hinaus umfasste das Deployment Änderungen an GoInstance – einem in Go geschriebenen Tool, das das Starten und Aktivieren von Maschinen sowie deren Abschaltung verwaltet. Die Änderung stellte nicht die eigentliche Umstellung auf VPC dar, sie legte lediglich das Fundament und blieb dabei abwärtskompatibel zu unserem aktuellen Setup ohne VPC. Der Wechsel zu VPC erlaubt es uns, die Sicherheit zu verbessern und AWS-Funktionen zu nutzen, die es nur in einer VPC gibt, etwa Instanztypen mit höherer Leistung bei geringeren Kosten. Die Änderung wurde gründlich getestet, sowohl lokal als auch in der CI. Da sich die Umgebungsvariablen in der Produktion jedoch von denen in Dev oder Staging unterscheiden, konnte eine Abweichung unbemerkt durchrutschen.
13:23 - Der erste Pager-Alarm ging ein und zeigte an, dass wir mit weniger Uploader-Instanzen liefen als vorgesehen. Das Problem blieb eine Weile unbemerkt, weil das Laden einer neuen Umgebung neue Prozesse erfordert; unser Blue/Green-Deployment brauchte eine Weile, um alle aktiven Prozesse zu ersetzen.
13:26 - Emergency Response Team (ERT) alarmiert.
13:32 - Es wurde festgestellt, dass wir aufgrund ungültiger Umgebungsvariablen keine neuen Maschinen starten konnten (Abweichungen bei AMI-IDs und Namen von Sicherheitsgruppen). GoInstance verwies in einigen Fällen auf nicht existierende Werte.
13:39 - Da alte Maschinen aus der Rotation genommen wurden oder nicht mehr erreichbar waren, liefen wir nun mit einer einzigen Maschine pro Region, die die Autoscaler nicht aus der Rotation nehmen wollten.
13:40 - Das ERT behob die Abweichung und stieß einen Build an.
13:45 - Twitter und Statuspage aktualisiert.
13:49 - Der Build wurde ausgerollt.
13:51 - Aufgrund eines nicht damit zusammenhängenden Fehlers im Build-Prozess von GoInstance stellte sich heraus, dass die Änderungen nicht live gingen.
13:55 - Verwundert darüber versuchte das Team, den fehlerhaften Build vollständig zurückzurollen.
14:01 - Aufgrund desselben Fehlers aktivierte auch das Rollback die Änderungen nicht. Wie sich später herausstellte, hätte es funktioniert, wenn wir weiter zurückgerollt hätten. Zur Erklärung: Als wir vor einigen Monaten unseren Stack auf Nix umgestellt haben, haben wir einen Fehler eingeführt, durch den GoInstance nur dann neu gebaut wurde, wenn Änderungen daran zusammen mit Änderungen an anderen Teilen unseres Stacks gebündelt waren. Als wir versuchten, GoInstance zu patchen, wurden die Änderungen nicht übernommen und nicht in die Produktion ausgerollt. Das ERT brauchte einige Zeit, um das herauszufinden.
14:08 - Das ERT behob das genannte Problem in unserem Nix-Setup, und wir konnten wieder Änderungen ausrollen. Wir stießen einen weiteren Build an und rollten ihn aus.
14:17 - Sowohl die EU- als auch die US-Flotte hatten wieder ihre gewünschte Kapazität. Vor Kurzem wurde ein großer Teil des Stacks hinzugefügt, der noch nicht in unsere AMIs aufgenommen worden war, wodurch Maschinenstarts langsamer abliefen, als wir es gewohnt sind.
14:34 - Alle Dienste als wiederhergestellt bestätigt, alle zugehörigen Kundengespräche abgeschlossen, Twitter und Statuspage aktualisiert.
Welche Schritte haben wir unternommen?
-
Für alle Regionen und Maschinentypen wurden neue AMIs gebaut, sodass sich unsere Startzeiten für Maschinen wieder drei Minuten annähern
-
Der Fehler in unserem Nix-Setup wurde behoben, sodass sich Änderungen an GoInstance immer in unserem Build niederschlagen
-
Die Abweichung in unserer Umgebung wurde behoben
Zusammen haben diese Maßnahmen dafür gesorgt, dass wieder alles reibungslos läuft. Uns ist jedoch klar, dass wir künftig weitere Maßnahmen brauchen, um sicherzustellen, dass so etwas nie wieder passieren kann.
Welche weiteren Schritte werden wir unternehmen?
Im Rahmen unseres Deploys lassen wir Autoscaler Maschinen starten; das hätte den Deploy stoppen müssen, bevor Schaden entsteht. Leider stellte sich heraus, dass dieser Preflight-Test aufgrund eines nicht damit zusammenhängenden Problems auf der vorherigen Umgebung ausgeführt wurde und nicht auf der aktuell ausgerollten. Wir werden das beheben, damit dieser Test künftig zuverlässig funktioniert und Probleme wie dieses erkennen kann.
Auch andere Teile unserer automatisierten Test-Suite hätten die ungültige Umgebung erkennen können, haben aber nicht darauf geprüft, weil sich die Staging-Umgebung von der Produktionsumgebung unterscheidet. Wir prüfen derzeit, ob wir unsere Umgebungen einander angleichen können.
Es tut uns leid
Nochmals: Es tut uns sehr leid, dass wir Ihnen diese Unannehmlichkeiten bereitet haben. Hoffentlich konnte dieses Post-mortem etwas Licht darauf werfen, was genau den Ausfall verursacht hat und was wir tun, damit er nie wieder passiert. Falls Sie von diesem Ausfall betroffen waren, wenden Sie sich bitte an unser Support-Team, und wir werden versuchen, die Sache wiedergutzumachen!
