Anwendungs- und Infrastrukturresilienz

Abgeschlossen

Resilienz ist die Fähigkeit, den ursprünglichen Zustand nach vorübergehenden Ausfällen wiederherzustellen. Durch die Wiederherstellungsstrategie der App wird die normale Funktionalität mit nur minimalen Auswirkungen auf die Benutzer wiederhergestellt. In Cloudumgebungen können Fehler auftreten, weshalb Ihre App so reagieren sollte, dass Downtimes und Datenverluste minimiert werden. Idealerweise behandelt Ihre App Fehler so, dass Benutzer*innen diese Problem gar nicht erst bemerken.

Entwerfen Sie Ihre Apps aufgrund der volatilen Natur von Microserviceumgebungen so, dass sie Teilausfälle erwarten und diese behandeln. Ein Teilausfall könnte beispielsweise Codeausnahmen, Netzwerkausfälle, nicht reagierende Serverprozesse und Hardwarefehler umfassen. Sogar geplante Aktivitäten wie das Verschieben von Containern auf einen anderen Knoten in einem Kubernetes-Cluster können einen vorübergehenden Fehler verursachen.

Resilienzansätze

Beim Entwerfen widerstandsfähiger Anwendungen müssen Sie häufig zwischen dem Fail-Fast-Ansatz und einer graduellen Leistungsminderung wählen. Beim Fail-Fast-Ansatz wird ein Fehler oder eine Ausnahme sofort durch die Anwendung ausgelöst, wenn ein Fehler auftritt, anstatt zu versuchen, eine Wiederherstellung einzuleiten oder das Problem zu umgehen. Dadurch können Probleme schnell identifiziert und behoben werden. Bei einer graduellen Leistungsminderung versucht die Anwendung, den Betrieb mit begrenzten Kapazitäten fortzuführen, auch wenn einige Komponenten fehlschlagen.

In cloudnativen Anwendungen ist es wichtig, dass Dienste Fehler ordnungsgemäß behandeln anstatt schnell fehlzuschlagen. Da Microservices dezentralisiert und unabhängig bereitgestellt werden können, werden Teilausfällen erwartet. Der Fail-Fast-Ansatz würde bei einem Fehler in einem Dienst dazu führen, dass abhängige Dienste schnell abgeschaltet werden, wodurch die Gesamtsystemresilienz reduziert wird. Stattdessen sollten Microservices so programmiert werden, dass sie interne und externe Dienstfehler erwarten und tolerieren. Diese graduelle Leistungsminderung ermöglicht es dem gesamten System, den Betrieb fortzusetzen, auch wenn einige Dienste unterbrochen werden. Für Benutzer*innen wichtige Funktionen können weiterhin ausgeführt werden, um einen vollständigen Ausfall zu vermeiden. Der Ansatz der graduellen Leistungsminderung gibt unterbrochenen Diensten außerdem Zeit, um eine Wiederherstellung durchzuführen oder sich eigenständig zu reparieren, bevor der Rest des Systems beeinträchtigt wird. Das bedeutet, dass die graduelle Leistungsminderung bei Mikroservices-basierten Anwendung besser auf die Best Practices für Resilienz wie die Fehlerisolation und eine schnelle Wiederherstellung ausgerichtet sind. Sie verhindert, dass sich lokale Incidents auf das gesamte System ausweiten.

Es gibt zwei grundlegende Ansätze für die Unterstützung einer graduellen Leistungsminderung mit Resilienz: Anwendung und Infrastruktur. Jeder Ansatz hat Vor- und Nachteile. Beide Ansätze können je nach Situation geeignet sein. In diesem Modul erfahren Sie, wie Sie die codebasierte und infrastrukturbasierte Resilienz implementieren.

Codebasierte Resilienz

.NET verfügt über eine Erweiterung für Resilienz und die Behandlung vorübergehender Fehler, mit der eine codebasierte Resilienz implementiert werden kann: Microsoft.Extensions.Http.Resilience.

Es handelt sich dabei um eine flüssige, leicht verständliche Syntax zum Erstellen von Code zur threadsicheren Behandlung von Fehlern. Es gibt mehrere Resilienzrichtlinien, die das Verhalten bei der Fehlerbehandlung definieren. In diesem Modul wenden Sie die Wiederholungs- und Circuit-Breaker-Strategien auf HTTP-Clientvorgänge an.

Wiederholungsstrategie

Eine Wiederholungsstrategie ist genau das, was der Name impliziert. Die Anforderung wird nach einer kurzen Wartezeit wiederholt, wenn eine Fehlerantwort empfangen wird. Die Wartezeit erhöht sich bei jedem Wiederholungsversuch. Dabei kann es sich um eine lineare oder eine exponentielle Erhöhung handeln.

Nachdem die maximale Anzahl an Wiederholungen erreicht wurde, bricht die Strategie den Vorgang ab und löst eine Ausnahme aus. Aus Sicht der Benutzer*innen benötigt die App meist mehr Zeit, um einige Vorgänge abzuschließen. Außerdem kann es länger dauern, bis die App Benutzer*innen darüber informiert werden, dass der Vorgang nicht abgeschlossen werden konnte.

Circuit-Breaker-Strategie

Eine Circuit-Breaker-Strategie unterbricht nach einer wiederholten Anzahl an Fehlern einen Zieldienst, indem sie ihn anhält und versucht, mit ihm zu kommunizieren. Bei dem Dienst könnte ein schwerwiegendes Problem vorliegen, wodurch er vorübergehend nicht reagiert. Nach einer festgelegten Anzahl von aufeinanderfolgenden Fehlern werden die Verbindungsversuche ausgesetzt, wodurch der Circuit Breaker geöffnet wird. Während dieses Wartevorgangs schlagen zusätzliche Vorgänge im Zusammenhang mit dem Zieldienst sofort fehl, ohne dass versucht wird, eine Verbinden zum Dienst herzustellen. Nach Ablauf der Wartezeit wird noch mal versucht, den Vorgang auszuführen. Wenn der Dienst reagiert, wird der Circuit Breaker geschlossen, und das System wechselt wieder in den normalen Zustand.

Infrastrukturbasierte Resilienz

Sie können ein Dienstnetz verwenden, um die infrastrukturbasierte Resilienz zu implementieren. Abgesehen von der Resilienz ohne Codeänderung kann ein Dienstnetz auch für die Datenverkehrsverwaltung, Richtlinien, Sicherheit, starke Identität und Einblicke verwendet werden. Ihre App ist von diesen betrieblichen Funktionen entkoppelt, die auf die Infrastrukturebene verschoben werden.

Vergleich mit codebasierten Ansätzen

Ein infrastrukturbasierter Resilienzansatz kann eine metrikbasierte Ansicht verwenden, durch die eine dynamische Anpassung an die Clusterbedingungen in Echtzeit möglich ist. Bei diesem Ansatz wird eine weitere Dimension zur Verwaltung des Clusters, aber kein Code hinzugefügt.

Ein codebasierter Ansatz ermöglicht Ihnen Folgendes:

  • Abschätzen, welche Wiederholungs- und Timeoutparameter geeignet sind
  • Konzentrieren auf eine bestimmte HTTP-Anforderung

Es gibt keinen angemessenen Ansatz, um im Code Ihrer App auf einen Infrastrukturfehler zu reagieren. Denken Sie daran, dass Hunderte oder Tausende von Anforderungen gleichzeitig verarbeitet werden. Sogar eine Wiederholung mit exponentiellem Backoff (Anzahl der Anforderungen) kann einen Dienst überlasten.

Bei infrastrukturbasierten Ansätzen werden interne App-Komponenten dagegen nicht berücksichtigt. Komplexe Datenbanktransaktionen sind für Dienstnetze beispielsweise nicht sichtbar. Solche Transaktionen können ausschließlich mit einem codebasierten Ansatz vor Fehlern geschützt werden.

In den folgenden Lerneinheiten implementieren Sie Resilienz für eine Microservice-basierte App mithilfe der .NET-HTTP-Resilienz im Code und einem Linkerd-Dienstnetz.