Software Aging

Ich habe im Laufe meiner Entwicklerzeit schon einiges gesehen. Leider musste ich extrem viele Stunden mit dem Analysieren von Bugs verbringen. Dabei waren für mich immer die angenehmsten Bugs, wenn eine Exception geflogen ist nach dem Motto „Das habe ich in diesem State nicht erwartet“. Der Fehler war schnell zu verstehen und schnell behoben. Aber dann gibt es diese Bugs wo man dran sitzt und keine Ahnung hat … Wie kam die Software in diesen State? Wie kann ich es überhaupt reproduzieren? Kann ich es überhaupt reproduzieren?

Welche qualitätssichernden Maßnahmen hat man oft angewandt? In den letzten 10 Jahren als Entwickler konnte ich immer wieder sehen, dass sehr viel Energie in Langzeittests investiert wurde. Das sind Tests, wo man feststellen will, ob das System „stabil“ läuft. Meist laufen die Tests über eine handvolle Tage. Das macht man meistens mit einer gewissen Grundlast, welche das System im Hintergrund beschäftigt. Meine Meinung zu dem Thema: vergeudete Liebesmühe.

Warum? Meist ist die Grundlast, die simuliert wird recht monoton – d.h. sie hat mit den realen Lastszenarien wenig zu tun. Wenn ich den Test für 3 Tage laufen gelassen haben – wer sagt mir, dass nicht nach 4 Tagen die Probleme anfangen? Der Einsatz von Profilern (e.g. von JetBrains) hilft natürlich dabei, Trendanalysen machen zu können – steigt der Speicher? etc. Auch kann ich mit Gatling schauen, ob ich meine nichtfunktionalen-Anforderungen erreicht hab. Trotzdem habe ich schon Systeme crashen gesehen, weil die Logfiles auf die gleiche Platte geschrieben haben wie die Datenbank und kein rolling aktiviert war – die Datenbank konnte nicht mehr schreiben. Und das passierte eben nicht nach 3 Tagen.

Sollte ich jetzt meinen Code bis ins letzte Detail fit machen für Langlebigkeit? Es kann Sinn machen – aber in den Domänen wo ich unterwegs bin – ich sage mal: Nein! Bevor wir weiter machen – was sagt die akademische Welt dazu? Hier findet man ein interessantes Schlagwort: Software-Aging.

In software engineering, software aging refers to all software’s tendency to fail, or cause a system failure after running continuously for a certain time.

Wer kennt es nicht? TCP Verbindungen, die in FIN_WAIT stecken, Memory Leaks, Prozesse die in einem State hängen und auf etwas warten, was nie mehr kommen wird, usw.

Wie weit sollte man Energie investieren, um diese Fehler präventiv zu vermeiden? Ich denke: Nicht sonderlich viel. Besser ist es meiner Meinung nach, mit den Fehlern zu leben – sie zu akzeptieren und stattdessen in Rejuvenation Strategien zu investieren. In .NET haben wir Isolationsmechanismen wie AppDomains. Wir haben Docker. Wir haben Virtualle Maschinen. All diese Techniken erlauben es, die Software automatisch neu zu starten. Es gibt jetzt nur 2 Challenges zu überwinden:

  • Das System braucht ein sauberes Fail-Over: Aber brauchen wir das nicht sowieso, wenn wir Reability gewährleisten wollen? Oder ein unterbrechungsfreies Deployment? Rejuvenation ist ja nichts anderes als ein Deployment mit der gleichen Version …
  • Detektion: Wann gerät das System in Schieflage? Wann starte ich neu? Das ist natürlich die schwierigste Frage. Profiling kann hier nicht schaden – Windows Performance Counter oder ähnliches (APM – Application Performance Monitoring wie Dynatrace).

Aber das ist sicherlich der schwierigste Part Ich bin gerade in eine Projekt wo tagsüber mit großer Last zu rechnen ist – in der Nacht eher mit geringer Last. Was spricht dagegen, in der Nacht regenerierende Maßnahmen zu setzen? Fault-Tolerance sieht ähnliche Konzepte vor – warum also nicht präventiv anwenden?

Fazit: Meiner Meinung nach wäre die Energie hier besser investiert. Ein Fail-Over kann ich sofort testen und die Funktionalität sofort beurteilen. Ebenfalls kann ich für 1 Tag einen Volllast Test machen um die Grundstabilität zu beurteilen. Ob eine Software 65 Tage stabil läuft? I dont know …