How a Release Failed
Autor
Marcus HeldHi,
Nach 9 Stunden stand die Entscheidung fest: Wir müssen zurückrollen.
Der erste Release seit fast 1,5 Jahren war gescheitert.
Und dabei lief es so gut. Die minutiöse Vorbereitung der letzten Wochen hatte sich ausgezahlt. Alles lief nach Plan. Die notwendigen Änderungen an den VMs verliefen wie erwartet. Die große Migration war nach einer Stunde Laufzeit erfolgreich durchgelaufen. Die neuen Contentfiles konnten erfolgreich mit dem neuen System deployed werden. Die neue CD Pipeline lief zum ersten Mal auf Production – und war erfolgreich.
Es dauerte zwar, aber um 13:00 Uhr war die neue Version online.
Es lief zu gut.
Noch war die Maintenance-Page geschaltet.
Und wir begannen, das System zu testen. Automatisierte Tests wurden ausgeführt, und der neue Content wurde getestet. Smoketests wurden durchgeführt.
Ich schaute mit den Entwicklern auf die Logs. Und da war etwas Komisches:
WARNING: Possible connection leak detected.
Die Warnung war kein Einzelfall.
Sie war hundertfach in den Logs.
Haben wir ein Problem?
An sich sieht das System gut aus. Niemand berichtet von einem Fehler. Die Tests laufen durch. Niemand berichtet von Timeouts oder unerwartetem Verhalten. Alles ist ruhig.
Also ein Blick ins Monitoring:
Wenn Connection Leaks im Log zu sehen sind, dann sollten wir viele aktive Verbindungen im Pool haben. Hikari hat eine MBean registriert. Auf die können wir zugreifen. Aber… alles ist gut. Wir haben nie mehr als eine Verbindung offen.
Was ist hier also los?
Woher kommt der Leak?
Ein weiterer Blick ins Log enthüllt die Übeltäter: die 3rd-party API. Die Authentifizierung der API benötigt einen RPC-Call auf einen anderen Service. Und dieser blockiert. Und wir halten die Datenbankverbindung offen.
Das können wir verifizieren!
Was passiert, wenn wir hier Last erzeugen? Ein Entwickler hat noch einen Lasttest, der 100 Clients simulieren kann.
Und tatsächlich.
Kaum läuft er an: Das System wird unbenutzbar. Unser Connectionpool ist sofort erschöpft.
Verdammt. Das hätten wir vorhersehen können.
Was können wir machen?
Einen Umbau kriegen wir heute nicht mehr hin. Das Risiko ist zu groß.
Wie viele Requests pro Sekunde haben wir live auf der API? Ungefähr drei pro Sekunde. Was wäre, wenn wir den Connectionpool so groß machen, dass er das abdeckt? Der TCP-Timeout liegt bei 60 Sekunden. Also: 60 x 3 = 180. Sagen wir, wir erhöhen den Pool auf 500. Dann haben wir etwas Puffer.
Und wir würden uns Zeit erkaufen. Für den richtigen Fix.
Also los.
Konfiguration ändern. Deployen. Alles sieht gut aus. Das System ist da.
Nächster Lasttest.
Mist.
Die Anwendung ist wieder unbenutzbar. Wir haben nur 100 offene Verbindungen. Aber die Datenbank spielt nicht mit. 100% CPU-Auslastung.
Es ist 16 Uhr.
Fällt noch jemandem etwas ein? Wir könnten im Apache ein Rate-Limiting auf die API einstellen. Er dürfte aber nur einen parallelen Call zulassen.
Das ist unrealistisch. Es macht die API praktisch unbenutzbar.
Wir könnten die API abschalten. Das geht aber nicht. Der finanzielle Schaden wäre zu hoch.
Was, wenn wir die alte Version neben der neuen deployen?
Die API ist kompatibel. Es gab keine Änderungen. Wir könnten die API auf die alte Anwendung routen.
Vorstellbar, dass das funktioniert. Aber haben wir alles bedacht? Das haben wir nie getestet. Und unsere Infrastruktur ist dafür nicht ausgelegt. Das Risiko ist zu hoch.
Das wars.
So können wir nicht online gehen.
Es ist 16:30 Uhr.
Wir sind gescheitert.
Wir rollen zurück.
Nach 9 Stunden – haben wir die alte Version wieder am Laufen.
Dann wird der Whisky aufgemacht.
Sind wir gescheitert?
Ja.
Aber es war auch ein Erfolg.
Es war klar, dass es nach so langer Zeit ein Kraftakt wird. Ich hatte mit wesentlich mehr Problemen gerechnet, bis die Anwendung überhaupt wieder online ist.
Und das war kein Problem. Wir haben bewiesen, dass wir wissen, wie die Anwendung zu halten ist. Wir wissen, wie wir sie deployen. Und all unsere Änderungen aus den letzten Monaten waren erfolgreich.
Dass wir auf den letzten Metern einen solchen Fehler finden, ist ärgerlich. Doch es ist nicht die Zeit, im Selbstmitleid zu versinken. Wir werden den Fehler ausmerzen. Der Fix wird nicht schwer. Und dann probieren wir es wieder. Wir werden es schaffen. Wir werden den Fuß durch die Tür kriegen.
Und dann können wir nach vorne blicken. Dann können wir dafür sorgen, nie wieder in eine solche Lage zu kommen.
Ich freue mich drauf!
Rule the Backend,
~ Marcus