REL10-BP04 Verwenden von Bulkhead-Architekturen, um den Umfang von Beeinträchtigungen zu begrenzen - Säule „Zuverlässigkeit“

REL10-BP04 Verwenden von Bulkhead-Architekturen, um den Umfang von Beeinträchtigungen zu begrenzen

Implementieren Sie Bulkhead-Architekturen (zellenbasierte Architekturen), um die Auswirkungen von Fehlern innerhalb eines Workloads auf eine begrenzte Anzahl von Komponenten zu beschränken.

Gewünschtes Ergebnis: Eine zellenbasierte Architektur verwendet mehrere isolierte Instances eines Workloads, wobei jede Instance als Zelle bezeichnet wird. Jede Zelle ist unabhängig. Sie teilt ihren Status nicht mit anderen Zellen und bearbeitet eine Teilmenge der gesamten Workload-Anfragen. Dadurch werden die möglichen Auswirkungen eines Fehlers, z. B. eines fehlerhaften Software-Updates, auf eine einzelne Zelle und die von ihr verarbeiteten Anfragen reduziert. Wenn in einem Workload 10 Zellen für die Beantwortung von 100 Anfragen verwendet werden, sind bei einem Fehler 90 % der gesamten Anfragen nicht davon betroffen.

Typische Anti-Muster:

  • Es wird ein unbegrenztes Wachstum der Zellen zugelassen.

  • Code-Updates oder Bereitstellungen werden auf alle Zellen gleichzeitig angewandt.

  • Status oder Komponenten werden von den Zellen geteilt (mit Ausnahme der Router-Schicht).

  • Es werden komplexe Geschäfts- oder Routing-Logiken in die Routing-Schicht eingefügt.

  • Es gibt keine Minimierung der zellenübergreifenden Interaktionen.

Vorteile der Nutzung dieser bewährten Methode: Bei zellenbasierten Architekturen treten viele häufige Fehlerarten innerhalb einer Zelle selbst auf, was eine zusätzliche Fehlerisolierung ermöglicht. Diese Fehlergrenzen bieten Schutz vor Fehlern, die sich sonst nur schwer eindämmen lassen, wie z. B. eine erfolglose Codebereitstellung oder Anfragen, die beschädigt sind oder einen bestimmten Fehlermodus auslösen (Poison Pill Requests).

Implementierungsleitfaden

Auf einem Schiff sorgen Schotten dafür, dass eine Beschädigung des Rumpfes auf einen Teil des Schiffes beschränkt bleibt. In komplexen Systemen wird dieses Muster oft kopiert, um eine Fehlerisolierung zu ermöglichen. Fehlerisolierte Grenzen beschränken die Auswirkungen eines Fehlers innerhalb eines Workloads auf eine begrenzte Anzahl von Komponenten. Komponenten außerhalb der Grenze sind vom Ausfall nicht betroffen. Wenn Sie mehrere fehlerisolierte Grenzen verwenden, können Sie die Auswirkungen auf Ihren Workload einschränken. Bei AWS können Kunden mehrere Availability Zones und Regionen verwenden, um eine Fehlerisolierung zu gewährleisten. Das Konzept der Fehlerisolierung lässt sich jedoch auch auf die Architektur Ihres Workloads ausweiten.

Der gesamte Workload wird durch einen Partitionsschlüssel in Zellen unterteilt. Dieser Schlüssel muss mit dem Grain des Service übereinstimmen, d. h. mit der logischen Art und Weise, in der der Workload eines Service mit minimalen zellenübergreifenden Interaktionen unterteilt werden kann. Beispiele für Partitionsschlüssel sind die ID des Kunden, die ID der Ressource oder jeder andere Parameter, der in den meisten API-Aufrufen leicht zugänglich ist. Eine Schicht für das Routing von Zellen verteilt Anfragen auf der Grundlage des Partitionsschlüssels an einzelne Zellen und präsentiert den Kunden einen einzigen Endpunkt.

Diagramm einer zellenbasierten Architektur

Abbildung 11: Zellenbasierte Architektur

Implementierungsschritte

Bei der Entwicklung einer zellenbasierten Architektur sind mehrere Designüberlegungen zu berücksichtigen:

  1. Partitionsschlüssel: Bei der Wahl des Schlüssels für die Partitionierung sollten Sie besonders sorgfältig vorgehen.

    • Er sollte mit der Struktur des Service übereinstimmen oder mit der natürlichen Art und Weise, wie der Workload eines Service mit minimalen zellenübergreifenden Interaktionen unterteilt werden kann. Beispiele sind Kunden-ID oder Ressourcen-ID.

    • Der Partitionsschlüssel muss in allen Anfragen verfügbar sein – entweder direkt oder in einer Weise, die sich durch andere Parameter leicht deterministisch ableiten lässt.

  2. Persistente Zellenzuordnung: Upstream-Services sollten während des Lebenszyklus ihrer Ressourcen nur mit einer einzigen Zelle interagieren.

    • Je nach Workload kann eine Strategie zur Migration von Zellen erforderlich sein, um Daten von einer Zelle in eine andere zu migrieren. Ein mögliches Szenario, in dem eine Migration von Zellen erforderlich sein kann, ist, wenn ein bestimmter Benutzer oder eine bestimmte Ressource in Ihrem Workload zu groß wird und eine eigene Zelle benötigt.

    • Zellen sollten keinen Status und keine Komponenten gemeinsam nutzen.

    • Folglich sollten zellenübergreifende Interaktionen vermieden oder auf ein Minimum beschränkt werden, da diese Interaktionen Abhängigkeiten zwischen den Zellen schaffen und somit die Möglichkeiten zur Fehlerisolierung verringern.

  3. Routing-Schicht: Die Routing-Schicht ist eine gemeinsame Komponente von Zellen und kann daher nicht dieselbe Strategie der Segmentierung wie bei Zellen nutzen.

    • Es wird empfohlen, dass die Routing-Schicht Anfragen auf einzelne Zellen verteilt, indem sie einen effizienten Algorithmus für die Zuordnung von Partitionen einsetzt – z. B. als die Kombination von kryptographischen Hash-Funktionen und einer modularen Arithmetik.

    • Um Auswirkungen auf mehrere Zellen zu vermeiden, muss die Routing-Schicht so einfach und horizontal skalierbar wie möglich bleiben, was den Verzicht auf eine komplexe Geschäftslogik innerhalb dieser Schicht erforderlich macht. Dies hat den zusätzlichen Nutzen, dass das erwartete Verhalten jederzeit leicht nachvollziehbar ist, was eine gründliche Testbarkeit ermöglicht. Wie Colm MacCárthaigh in Reliability, constant work, and a good cup of coffee (Zuverlässigkeit, konstante Arbeit und eine gute Tasse Kaffee) erläutert, führen einfache Designs und konstante Arbeitsmuster zu zuverlässigen Systemen und verringern die Antifragilität.

  4. Zellengröße: Zellen sollten eine maximale Größe haben und nicht darüber hinaus wachsen dürfen.

    • Die maximale Größe sollte durch gründliche Tests ermittelt werden – bis Sollbruchstellen erreicht und sichere operative Margen etabliert sind. Weitere Details zur Implementierung von Testverfahren finden Sie unter REL07-BP04 Durchführen von Lasttests für die Workload

    • Der gesamte Workload sollte durch Hinzufügen zusätzlicher Zellen wachsen, sodass der Workload mit der steigenden Nachfrage skalieren kann.

  5. Multi-AZ oder Multi-Region-Strategien: Es sollten mehrere Schichten zur Ausfallsicherheit genutzt werden, um sich gegen verschiedene Fehlerbereiche zu schützen.

    • Für die Ausfallsicherheit sollten Sie einen Ansatz wählen, bei dem verschiedene Verteidigungsebenen aufgebaut werden. Eine Ebene schützt vor kleineren, häufiger auftretenden Unterbrechungen, indem eine hochverfügbare Architektur mit mehreren AZs erstellt wird. Eine weitere Verteidigungsebene schützt vor seltenen Ereignissen wie Naturkatastrophen mit großer Reichweite und Unterbrechungen auf Regionsebene. Für diese zweite Ebene muss die Architektur Ihrer Anwendung mehrere AWS-Regionen umfassen. Wenn Sie eine Multi-Region-Strategie für Ihren Workload implementieren, ist er vor weitreichenden Naturkatastrophen, die einen großen geografischen Bereich in einem Land betreffen, oder technischen Fehlern in einer ganzen Region geschützt. Beachten Sie dabei, dass das Implementieren einer Multi-Region-Architektur äußerst komplex sein kann und bei den meisten Workloads nicht erforderlich ist. Weitere Details finden Sie unter REL10-BP02 Auswählen der geeigneten Standorte für Ihre Multi-Standort-Bereitstellung.

  6. Code-Bereitstellung: Eine gestaffelte Strategie für die Bereitstellung von Code sollte der gleichzeitigen Bereitstellung von Codeänderungen in allen Zellen vorgezogen werden.

Risikostufe, wenn diese bewährte Methode nicht eingeführt wird: hoch

Ressourcen

Zugehörige bewährte Methoden:

Zugehörige Dokumente:

Zugehörige Videos:

Zugehörige Beispiele: