Operations heute und morgen, Teil 4: Hochverfügbarkeit

Seite 3: Isolierung, Redundanz

Inhaltsverzeichnis

Eine Anwendung in kleinere Module zu zerlegen, gehört heute zum guten Ton in der Softwareentwicklung. Aus der Perspektive der Fehlertoleranz ist die Aufteilung ebenfalls eine gute Idee. Im Fehlerfall ist nur ein Teil der Anwendung kompromittiert und nicht die ganze Anwendung – vorausgesetzt, die Bausteine sind als möglichst unabhängige Einheiten entwickelt worden und gegeneinander isoliert. Diese unabhängigen Einheiten werden, je nach Quelle, Bulkheads (als Metapher aus dem Schiffsbau übernommen), Failure Units oder Units of Mitigation genannt. Die Einheiten isolieren sich up- und downstream gegen Fehler anderer Einheiten, um kaskadierende, das heißt sich über mehrere Einheiten fortpflanzende Fehler zu vermeiden.

Das Finden geeigneter Failure Units ist ein reines Design-Thema. Es gibt keine fertigen Bibliotheken, Frameworks oder Best Practices, die sich einfach anwenden ließen. Hier sind Augenmaß, Erfahrung und kontinuierliches Lernen gefragt. Hat man eine Struktur gefunden, stehen für die Implementierung eine Menge Muster und Prinzipien zur Verfügung, etwa lose Kopplung, Latenzüberwachung, Request-Limitierung oder auch die vollständige Validierung aller Aufrufparameter und Rückgabewerte (vgl. [1], [2]).

Redundanz ist ein weiteres zentrales Muster im Kontext der Fehlertoleranz. Typischerweise werden Failure Units redundant ausgelegt. Redundanz ist geeignet, mit allen Arten von Fehlern umzugehen, nicht nur mit Absturzfehlern. Zunächst muss man sich Gedanken über das Szenario machen, dass mit Redundanz adressiert werden soll:

  • Soll ein Failover implementiert werden, das heißt beim Ausfall einer Einheit (idealerweise komplett transparent) auf eine andere umgeschaltet werden?
  • Oder soll die Latenz gering gehalten werden? Das bedeutet, es werden mehrere Einheiten redundant genutzt, um die Wahrscheinlichkeit einer zu langsamen Antwort zu reduzieren.
  • Oder sollen Antwortfehler erkannt (in Zeiten von NoSQL keine Seltenheit), das heißt die Antworten mehrerer redundanter Einheiten ausgewertet werden, um die Wahrscheinlichkeit fehlerhafter Antworten zu reduzieren?
  • Oder soll Skalierung/Lastverteilung implementiert, also eine Einheit zu zahlreichen Anfragen auf mehrere Einheiten verteilt werden?
  • ...

Abhängig vom gewählten Szenario sind dann weitere Aspekte zu berücksichtigen:

  • Welche Routing-Strategie passt zum gewählten Szenario, wenn Load Balancer eingesetzt werden? Reicht einfaches Round Robin oder wird eine komplexere Strategie benötigt? Und unterstützt diese der Load Balancer?
  • Stellt das System einen automatischen Master-Wechsel sicher, wenn ein Master-Slave-Ansatz für Failover zum Einsatz kommt und der Master ausfällt?
  • Um die Latenz gering zu halten, kann man einen "Fan out & quickest one wins"-Ansatz verwenden. Das heißt, eine Anfrage wird parallel an mehrere redundante Einheiten gesendet und die schnellste Antwort kommt zum Einsatz. Wie stellt man bei so einem Ansatz sicher, dass die Einheiten nicht von alten, nicht mehr benötigten Anfragen so belastet werden, dass sie die neuen Anfragen nicht mehr zeitnah bearbeiten können