Das Produktivsystem ist kaputt! Was jetzt?
tarent Blog

Das Produktivsystem ist kaputt! Was jetzt?

28.01.2021 Posted 9 Monaten ago Martin Pelzer

Kürzlich erzählte mir ein Kollege, dass in seinem Projekt ein Fehler auf dem Produktivsystem aufgetreten ist. Nach erster – der Situation nun mal innewohnender – Panik hat es das Team geschafft, den Fehler zu identifizieren und zu beheben. Trotzdem war das Team nicht zufrieden. Es kam die Frage auf, was man hätte besser machen können. Hätte man den Fehler durch ein anderes Vorgehen schneller finden und so die Ausfallzeit des Systems minimieren können? Der erste Gedanke des Teams: Gibt es denn irgendwo allgemeingültige Checklisten, die man in so einer Situation anwenden kann?

Meine erste Antwort war: Das lernt man mit der Zeit. Wenig überraschend, war diese Antwort für den Kollegen nicht so recht zufriedenstellend. Dieser Beitrag ist daher der Versuch einer besseren, ausführlicheren Antwort.

Prioritäten

Viele Entwickler haben einen Forscherdrang, lernen gerne neue Technologien kennen und verstehen gerne, wie Dinge funktionieren. Daher sollte man sich in einer Fehlersituation seiner Prioritäten klar sein: Oberstes Ziel ist, das Produktivsystem wieder ans Laufen zu bringen. Zum Erreichen dieses Ziels kann es hilfreich sein, zu verstehen, was eigentlich das Problem ist. Aber das Problemverständnis muss zu diesem Zeitpunkt zweitrangig sein. Steht das Produktivsystem, gibt es also ganz klar folgende Prioritäten:

  1. Den Produktionsbetrieb wieder herstellen.
  2. Die Problemursache finden und verstehen.

Sich dieser Prioritäten bewusst zu sein ist wichtig, um eventuell vorhandene Möglichkeiten wie Rollbacks, Einspielen eines Backups, Roll Forward usw. in Betracht zu ziehen. Für solche Wege ist es nicht zwingend notwendig, das Problem komplett durchdrungen und verstanden zu haben.

Besonders, wenn das Problem kurz nach einem Deployment auftritt, kann die Frage, ob man die letzte Änderung einfach zurückdrehen kann, eine einfache Lösung zur Behebung sein. Wurde bereits länger nicht mehr deployed, ist es wahrscheinlich besser, erst einmal herauszufinden, was los ist.

Hat man wie oben beschrieben die Möglichkeit einer schnellen Behebung, sollte man daran denken, Analysematerial zu sichern, d.h. Logs sichern, evtl. ein Speicherabbild ziehen, Screenshots machen usw., damit man im Nachgang noch in der Lage ist, die Problemursache zu analysieren und idealerweise zu verstehen. Hier muss man natürlich abwägen: braucht die Sicherung des Analysematerials länger, lässt man es evtl. lieber bleiben – es sei denn, der Fehler tritt nicht zum ersten Mal auf.

Gibt es keine einfache Möglichkeit eines Rollouts, der das Problem beheben sollte, geht es zu Schritt 2: der Fehleranalyse.

Der erste Rundumblick

In der Fehleranalyse ist es hilfreich, sich erst einmal einen schnellen Überblick zu verschaffen. Gute allgemein gültige erste Schritte sind

  • einen Blick in die Logs zu werfen,
  • den Ressourcenverbrauch des Systems zu checken und
  • das Monitoring anzusehen.

Logging

Mein erster Blick geht meist ins Log. Taucht dort eine Fehlermeldung auf? Falls ja, kann ich die Meldung spontan einordnen? Die zweite Frage ist wichtig. Denn falls ich mit der Meldung nichts anfangen kann, sollte ich an diesem Punkt noch nicht anfangen, in Recherche zu versinken. Nur wenn ich direkt erkenne, was das Problem ist, steige ich hier auch sofort in die Behebung ein. Ansonsten reicht es, erst einmal die Fehlermeldung zu notieren – wenn denn überhaupt eine im Log existiert. Wenn ich die Fehlermeldung nicht kenne, ist natürlich auch ein kurzes Googeln hilfreich – aber wirklich nur kurz. Wir sind noch dabei, uns einen Überblick zu verschaffen.

Ressourcenverbrauch

Wie sieht der aktuelle Ressourcenverbrauch des Systems aus? Hat das Gesamtsystem oder eine Komponente, z.B. die Datenbank, eine ungewöhnlich hohe CPU-Last oder einen ungewöhnlich hohen Speicherverbrauch? Gibt es noch Puffer im aktuellen Ressourcenverbrauch oder ist das System gegen ein Ressourcenlimit gestoßen und könnte das der Grund für das Problem sein?

Monitoring

Gab es vor dem Auftreten des Problems irgendwelche auffälligen Veränderungen bei den im Monitoring dargestellten Werten? Haben ungewöhnlich viele User zugegriffen? Wurden auffällig viele API-Requests gestellt? Ist die Anzahl der Datensätze in der Datenbank stark angewachsen? Laufen irgendwelche Hintergrund-Jobs bereits ungewöhnlich lange?

Nach dem ersten Rundumblick hat man in der Regel ein paar erste Aspekte, die man sich angucken kann. Im Idealfall sind daraus schon Theorien zur Fehlerursache ableitbar, aber auch einfache Auffälligkeiten, die man sich nicht erklären kann, sind es wert, untersucht zu werden, wenn man noch keine Theorie hat.

Analysevorgehen

Was macht man nun mit den zusammengetragenen Erkenntnissen, Theorien und Auffälligkeiten aus dem ersten Rundumblick? Es hilft, ein Dokument anzulegen, in dem man die Analyse live mitschreibt. Oft passiert es, dass man unterschiedliche Ansatzpunkte findet, die man nicht zeitgleich überprüfen kann. Damit diese Gedanken nicht verloren gehen und nicht weiter mentale Ressourcen belegen, ist es hilfreich, sich die wenigen Sekunden zu nehmen und die Ideen niederzuschreiben, damit man sie anschließend strukturiert nacheinander abarbeiten kann. Gerade wenn eine Fehleranalyse länger dauert, hilft ein Niederschreiben der Analyse auch dabei, einen klaren Kopf zu behalten und man verliert die Angst, ein wichtiges Indiz vergessen zu können. Habe ich Thema X eigentlich schon überprüft? War das Ergebnis von Analyse Y wirklich so, wie ich es gerade im Kopf habe? Ein Dokument gibt Struktur.

Auch im Team, d.h. wenn man nicht alleine das Problem beheben muss, hilft ein gemeinsames Dokument (kollaborative Office-Suiten wie Google Docs, Office 365 oder Wiki-Systeme mit kollaborativem Editiermodus wie Confluence helfen hier sehr). Man kann Ansätze sammeln, verteilen und Erkenntnisse werden direkt für jeden sichtbar.

Ob im Team oder alleine: Timeboxen sind eine gute Sache. Probleme zu analysieren verführt dazu, sich in Logfiles oder Google-Recherchen zu verlieren. Um das zu verhindern, sollte man sich kurze Timeboxen setzen. Am Ende der Timebox sollte man immer hinterfragen, ob einen der aktuelle Weg weiterbringt und man sollte eine kurze Abwägung treffen, ob noch andere Analyseansätze möglich wären. Mache ich mit meinem aktuellen Ansatz weiter oder wende ich mich einem anderen zu? Dabei sollte man natürlich nicht ständig herumspringen. Solange man nicht das Gefühl hat, dass die Verfolgung des aktuellen Ansatzes zu nichts führt oder unangebracht lange dauert, kann man den Ansatz ruhig weiterverfolgen. Klare Timeboxen helfen aber gerade in Stress-Situationen dabei, sich regelmäßig die Frage zu stellen, ob die aktuelle Tätigkeit noch die richtige ist.

Grundsätzlich ist bei der Fehleranalyse ein wissenschaftliches Vorgehen sinnvoll, d.h.

  • Thesen aufstellen
  • Versuchen, These zu belegen oder zu widerlegen
  • ggf. weitere Thesen aufstellen und von vorne beginnen

 

Es macht wenig Sinn, einfach ziellos durch Logs oder Google zu wühlen. Hat man gar keine Idee, ist ein Ausschlussverfahren immer gut. Ein IT-System besteht in der Regel aus mehreren Komponenten. Kann man überprüfen, dass bestimmte Komponenten korrekt laufen? Oder deuten Hinweise darauf hin, dass der Fehler in einer bestimmten Komponente liegt?

Kommunikation

Dauert die Analyse länger, hilft Kommunikation nach außen – auch wenn man das Gefühl hat, es kostet nur Zeit. Ein kurzes Status-Update der Sorte “Wir konnten den Fehler eingrenzen auf Komponente X und verfolgen gerade Ansatz Y” zeigt, dass das Team am Problem arbeitet und alles gibt, was es kann. Langes Schweigen und Ignorieren von Anfragen nach einem Status sind nicht vertrauensfördernd.

Post Mortem

Ist das Problem behoben und das System läuft wieder fehlerfrei, ist es Zeit, durchzuschnaufen. Einfach wieder zum Tagesbetrieb übergehen sollte man allerdings nicht. Eine Post-Mortem-Analyse hilft, sich besser auf das nächste Produktionsproblem vorzubereiten (und ja, das nächste Problem wird irgendwann kommen). Dabei kann man analog zu einer Scrum-Retrospektive vorgehen, fokussiert sich allerdings ganz klar auf das behobene Produktionsproblem. Wo haben wir gut agiert? Was hätten wir besser machen können? Wo in unserem System haben wir Verbesserungspotential, um solche Fehler künftig zu vermeiden? (Hätten uns zusätzliche Log-Einträge geholfen? Fehlte etwas im Monitoring?…) Eine solche Analyse kann man getrost auf den nächsten oder übernächsten Tag legen. Etwas zeitlicher Abstand hilft bei der Einschätzung. Die Analyse sollte dabei den Fokus auf die Identifizierung der Ursachen des Problems und deren künftiger Vermeidung richten. Damit dies optimal gelingt, muss eine vertrauensvolle Atmosphäre herrschen, in der alle Beteiligten offen über alle möglichen Faktoren sprechen können. Von Schuldzuweisungen sollte unbedingt abgesehen werden.

Sein IT-System auf den Fehlerfall vorbereiten

Die bisher gegebenen Tipps sind sehr allgemein – aber IT-Systeme sind nun mal auch von Projekt zu Projekt sehr unterschiedlich und das richtige Vorgehen ist immer ein wenig anders. Trotzdem gibt es einige Punkte, die man bereits im Vorfeld des Fehlers, also in seiner normalen Entwicklertätigkeit beachten sollte. Die Frage “Was machen wir eigentlich, wenn unser Produktivsystem mal abraucht?” muss bei der Entwicklung einer Software immer von Beginn an mitgedacht werden. Auch das ist ein Zeichen qualitativ hochwertiger Softwareentwicklung.

Gutes Logging

Der erste Punkt ist der Einbau von gutem Logging in seine Software. Wie oft fallen Log-Statements einfach weg, weil sie zur Umsetzung der geforderten Fachlichkeit nicht wirklich etwas beitragen und der Produktionsfehler als fernes Ding erscheint, das sowieso niemals eintreten wird?

Ich möchte ein paar grobe Regeln für gutes Logging geben:

  • Fliegt irgendwo eine Exception, sollte das irgendwo explizit geloggt werden. Kann man eine gefangene Exception im Code nicht vollständig behandeln, muss sie samt Stacktrace ins Log geschrieben werden.
  • Länger laufende Aufgaben oder per Scheduler gestartete Aufgaben sollten den Zeitpunkt ihres Starts und Endes ins Log schreiben. So hat man im Zweifelsfall die Möglichkeit, zu sehen, ob ein gestarteter Job bereits ungewöhnlich lange läuft oder ob er zum Zeitpunkt des Problems gar nicht läuft und daher als Problemursache eher nicht in Frage kommt. Es bietet sich auch an, Zwischenergebnisse zu loggen, ggf. auf niedrigeren Log-Levels. Auch das kann später helfen, den Fehler einzugrenzen.
  • Log-Meldungen sollten leicht auffindbar sein. Gleichartige Log-Meldungen (z.B. Beginn und Ende eines Scheduled Jobs) sollten das gleiche Tag oder den gleichen suchbaren Text beinhalten.
  • Sinnvolle Log-Level wählen: Bei jeder Log-Meldung sollte man sich fragen, wie dramatisch der Eintritt dieses Fehlers für das System ist. Ist die Meldung rein informativ (INFO)? Ist ein Fehler aufgetreten, aber das System kann weiterlaufen (WARNING)? Ist ein Fehler aufgetreten, der das System wahrscheinlich in einen undefinierten Zustand versetzt – z.B. die Verbindung zur Datenbank ist abgerissen (ERROR)? Gutes Logging besteht nicht nur aus dem Einbau von Log-Meldungen in den Code, sondern auch in der Vermeidung von zu viel Logging. Das Log muss verständlich und handhabbar sein.

 

Es ist sinnvoll, im Produktionsbetrieb auch ohne Fehlerfall einfach mal durch das Log zu scrollen und sich die Frage zu stellen, ob einem das, was man da liest, überhaupt im Fehlerfall Ansätze zur Analyse bringen würde.

Gutes Monitoring

Zu jedem guten IT-System gehört ein gutes Monitoring. Welche Metriken kann man für sein System definieren und visualisieren? In ein Monitoring gehören nicht nur Parameter, die einem seine Programmiersprache oder sein Framework sowieso schenkt – CPU-Last, RAM-Verbrauch, … – sondern vor allem auch eigene, applikations- oder komponentenspezifische Metriken, die den Zustand des Systems beschreiben (Anzahl angemeldeter User, Anzahl abgearbeiteter Business-Objekte über die Zeit, …). Jede Schnittstelle nach außen sollte im Monitoring vertreten sein. Wie viele Requests kommen rein? Wie viele gehen raus? Die eigene Team-Verantwortung endet meist an den Grenzen des IT-Systems. Was dahinter passiert, weiß man nicht so genau. Daher sollte man diese Schnittstellen besonders gut beobachten.

Deployment-Strategien

Beim Aufbau der Build-Chain seines IT-Systems sollte man sich fragen, welche Deployment-Strategie man eigentlich verfolgt.

Gibt die Fachlichkeit es her, eine Rollback-Möglichkeit einzubauen? Nicht immer ist das möglich. Manchmal geht es gar nicht und manchmal erschweren bestimmte Updates das Rollback – z.B. wenn man das Datenbankschema ändert und die alte Version mit dem geänderten Schema nicht arbeiten kann. Rollback-Skripte für DB-Schema-Änderungen sind möglich, sieht man aber doch eher bei sehr, sehr kritischen IT-Systemen. Es lohnt sich, beim Ausrollen einer Änderung auf Produktion kurz die Frage zu stellen, ob eine Rollback-Möglichkeit besteht und in Abhängigkeit von der Antwort auf diese Frage besonders sorgfältig vorzugehen.

Ein Rollback wird erleichtert, wenn man auf Blue-Green-Deployments setzt. Bei diesem Ansatz existiert das Produktivsystem zwei Mal. Eine Kopie läuft produktiv, auf der anderen wird entwickelt bzw. integriert. Möchte man deployen, schaltet man einfach um. Die vormals produktive Kopie wird zum Entwicklungssystem, das Entwicklungssystem zum Produktivsystem. Ein Rollback ist hier besonders einfach, da das alte Produktivsystem nach dem Deployment noch existiert.

Eine weitere Strategie, die Produktionsprobleme eventuell schneller behebbar machen kann, sind Feature Toggles, also Schalter, mit denen man eine neu hinzugefügte Funktionalität im laufenden Betrieb abschalten kann. Hierbei gilt es allerdings zu beachten, dass Feature-Toggles zumindest ein kleines Stück zusätzliche Komplexität in den Code packen und daher nicht allzu breit eingesetzt werden sollten.

Läuft ein IT-System stark parallelisiert auf mehreren Knoten, so ist ein schrittweises Deployment ein guter Weg, um ein neues Release auf Produktion auszurollen und dabei im Fehlerfall möglichst wenige User zu beeinträchtigen.

Gute Staging-Systeme

Produktionsfehler geschehen nicht, wenn das Problem bereits auf einem vorherigen System aufgetreten ist – egal ob man es Integration, Abnahme, Staging oder wie auch immer nennt. In vielen Software-Projekten wird mit Staging-Systemen gearbeitet. Nichtsdestotrotz steht es oft um die Qualität dieser Staging-Systeme nicht sonderlich gut. Zumindest das System direkt vor Produktion sollte in Bezug auf Ressourcen (CPU, RAM, Plattenplatz, …) möglichst identisch mit dem Produktivsystem sein. Läuft ein Service als verteiltes System auf mehreren Knoten parallel, muss das auch auf Staging bereits der Fall sein.

Ein häufiger Pferdefuß sind auch die Datenmengen. Performanzprobleme lassen sich nur schwer finden, wenn im Produktivsystem 50 Millionen Datensätze liegen, im Staging-System aber nur 50.000. Testdaten sind natürlich nicht immer einfach zu erstellen – besonders wenn Produktionsdaten aufgrund von z.B. DSGVO-Anforderungen nicht genutzt werden können. In eine Entscheidung, auf große Testdatenmengen zu verzichten, sollte dann aber immer das Risiko eines Produktionsfehlers einkalkuliert werden.

Ist es nicht oder nur unter sehr großem Aufwand möglich, ein Staging-System in Bezug auf Ressourcen und Daten ähnlich der Produktion aufzubauen und zu erhalten, darf man sich durchaus die Frage stellen, ob ein Staging-System überhaupt Sinn ergibt, oder ob die Energie, die dort reinfließt nicht in anderen Maßnahmen besser aufgehoben ist.

Oft ausrollen

Als letzten Punkt möchte ich die Empfehlung aufführen, möglichst oft auf Produktion zu deployen. Dies hat zwei Effekte: zum Einen steigt damit die Übung und zum Anderen sinken der Respekt und somit die Nervosität im Team. Mehr Routine führt zu weniger Fehlern. Zum Anderen sinkt durch häufigere Deployments der funktionale Umfang bzw. die Änderung im einzelnen Deployment. Kleinere Änderungen enthalten weniger Fehlerpotential als größere Änderungen.

Häufige Rollouts auf Produktion bedingen natürlich ein entsprechendes Vorgehensmodell im Team: automatisiertes Deployment (um den Aufwand für häufige Deployments zu reduzieren) und die Entwicklung begleitende, automatisierte QA-Maßnahmen sind Voraussetzung, um vorab genügend Sicherheit für ein Produktions-Deployment ohne langwierige Testphasen zu ermöglichen.

Fazit

Am Ende dieses Artikels muss ich feststellen, dass es zu dem Thema anscheinend doch das ein oder andere zu sagen gibt – es sei denn, ich mache viele Worte um nichts (was ich nicht hoffe). Konkrete Checklisten zum Abhaken im Fehlerfall sind es zwar nicht geworden, da jedes IT-System unterschiedlich ist. Ein strukturiertes Analysevorgehen, eine Post-Mortem-Analyse und präventive Maßnahmen beim Bau des IT-Systems helfen aber, um den Fehler schneller zu finden oder sogar vorab zu verhindern.

Martin Pelzer

Über den Autor

Martin Pelzer, Senior Software Entwickler und IT-Consultant, ist überzeugt von agilen Arbeitsweisen

Martins LinkedIn Profil