12 Fehlertoleranz ein verteiltes System beinhaltet viele Abstraktionsebenen, die stark voneinander abhängen. - z.b. hängt der Klient von seinem Server ab, der wiederum von seinen Diensten, etc. - die Kette der Abhängigkeiten setzt sich durch die Softwareebenen bis zur Hardware fort. Fehlertoleranz bedeutet, dass das Gesamtsystem einen Fehler einer Komponente in den Abhängigkeitsrelationen maskiert. das Fehlverhalten einer Komponente wird vom Gesamtsystem ausgeglichen. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 1 Begriffe Failure das System verhält sich nicht wie spezifiziert. Error Teil eines Systemzustands, der verantwortlich für eine zukünftige Failure ist, falls keine entsprechenden Maßnahmen getroffen werden. Fault die Ursache eines Errors. da ein Error Teil des Systemzustandes ist, lässt sich dieser beobachten und evaluieren. eine Failure (d.h. Fehlverhalten) ist nicht leicht observierbar. - sie muss mit speziellen Mechanismen aus einem Error abgeleitet werden. - wenn nicht jeder Systemzustand erfasst wird, kann Fehlverhalten entstehen, ohne dass es bemerkt wird. ein (verteiltes) System ist fehlertolerant (engl.: fault tolerant), wenn es in der Lage ist, sich trotz des Auftretens von Faults spezifikationskonsistent zu verhalten. Redundanz wird als Schlüsselverfahren auf drei Ebenen eingesetzt. - bei Hardwareredundanz werden Hardwarekomponenten zusätzlich im System hinzugefügt. - bei Softwareredundanz werden Softwarekomponenten oder Codesegmente mehrfach bereitgehalten und ausgeführt. - bei Zeitredundanz wird zusätzliche Ausführungszeit für die vorgenannten Techniken spendiert. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 2
Phasen eines fehlertoleranten Systems Fehlererkennung (engl.: error detection) - ein Fehler wird im Zustand bemerkt (error) und daraus auf einen Fehler (fault) in einem Teil des Systems geschlossen. - Man nimmt an, dass dann ein Fehlverhalten (failure) der betroffenen Komponente des Systems auftritt. Schadensermittlung (engl.: damage confinement) - welcher Schaden ist bis zum Zeitpunkt der Erkennung aufgetreten. - die Auswirkungen sollten auf einen bekannten und beschränkten Bereich eingegrenzt werden können. Fehlerrecovery (engl.: error recovery) - der aufgetretene fehlerhafte Zustand wird behoben. - das System wird in einen korrekten Zustand gebracht. Fehlerbehandlung und Weiterführen des Systems (engl.: fault treatment and continued system service) - das fehlertolerante System soll spezifikationskonform weiter arbeiten - die fehlerhafte Komponente wird umgangen oder - in einer anderen Konfiguration verwendet. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 3 in sicherheitskritischen Systemen wird Fehlertoleranz oft durch redundante Auslegung der Hardware realisiert. - z.b. drei identische Hardwarekomponenten (engl.: triple modular redundancy, TMR), die mit den gleichen Eingaben im gleichen Takt arbeiten. - aus den drei Ergebnissen entscheidet die Majorität. - dadurch ist das System gegenüber dem Ausfall und der Fehlfunktion einer Komponente tolerant. - bei nur zwei Replikaten könnte nur der Ausfall einer Komponente maskiert werden. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 4
Ebenen und Bausteine fehlertoleranter Software Bausteine Fail-Stop Prozessoren beenden ihre Tätigkeit bei einem entdeckten Fehler und arbeiten nicht fehlerhaft im System weiter. in stabilem Speicher sind Daten auch nach dem Auftreten eines Fehlers fehlerfrei verfügbar. durch zuverlässige Kommunikation werden Nachrichten sicher und in der richtigen Reihenfolge zugestellt. auf den Basiselementen kann zuverlässige und atomare Broadcastkommunikation aufgebaut werden. unter Verwendung der Bausteine lassen sich unterschiedlich tolerante Dienste entwickeln. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 5 Fehlertoleranz- Dienste Bausteine fehlertolerante Software Prozeß-Zuverlässigkeit (Process-Resilience) Daten-Zuverlässigkeit (Data-Resilience) atomare Aktionen konsistente Zustands-Recovery zuverlässiger und atomarer Broadcast Fail-Stop Prozessoren, stabiler Speicher, zuverlässige Kommunikation verteiltes System fortgesetzter Dienst bei Designfehlern fortgesetzter Dienst bei Knotenfehlern Konsistenz bei Knotenfehlern Bild 12.1: Ebenen in einem fehlertoleranten verteilten System Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 6
12.1 Fehlersemantik Fehlersemantik beschreibt das Verhalten von Systemkomponenten und des gesamten Systems im Fehlerfall. Je nach Art des Fehlers wird das Fehlverhalten in verschiedene Klassen eingeteilt [Cri91] - Dienstverweigerung (engl.: omission failure bzw. denial of service) - eine Komponente reagiert nicht mit einer Antwort auf einen Auftrag. z.b. durch verlorengehende Nachrichten im Kommunikationsdienst. - fehlerhafte Antwort - eine Komponente antwortet falsch auf einen Auftrag (engl.: response failure). - falsche Werte werden übermittelt (engl.: value failure) - intern finden falsche Zustandsübergänge statt (engl.: state transition failure) und es entstehen lokal falsche Werte. - Zeitfehler (engl.: timing failure) - eine Komponente antwortet richtig, jedoch zum falschen Zeitpunkt. - meist kommen die Antworten zu spät z.b. durch einen überlasteten Server oder schlechte Netzverbindung. - Antworten können auch zu früh ankommen. z.b. in Echtzeitsystemen oder Multimediasystemen. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 7 - Serverabsturz (engl.: crash failure) - ein Server verweigert kontinuierlich seinen Dienst. - er wird von Klienten als abgestürzt vermutet. - weitere Unterscheidung je nach Zustand der Serverdaten nach Wiederanlaufen: - Amnesie-Crash: der Server startet im Initialzustand. er verliert jegliche Datenzustände zum Zeitpunkt des Absturzes. - Pause-Crash: der Server startet in dem Zustand, den er vor dem Absturz hatte. - Halte-Crash: die fehlerhafte Komponente steht nach dem Fehler und wird nicht erneut gestartet. - Byzantinische Fehler - eine Komponente verhält sich beliebig. - es können beliebige Kombinationen der anderen Klassen vorkommen. - oft sind Hardwarefehler dieursache von byzantinischen Fehlern. z.b. ein defekter Timerbaustein zerstört die Ordnung von Nachrichten. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 8
die Fehlersemantik beschreibt das Verhalten des Systems im Fehlerfall. d.h. ein fehlertolerantes System muss dies maskieren. - z.b. muss ein Service mit Omission-Semantik zur Fehlertoleranz so erweitert werden, dass verlorengehende Aufträge automatisch vom Klienten wiederholt werden. je mehr Fehlersemantiken tolerant begegnet werden soll, um so aufwendiger wird die Programmierung. die starke Schichtung eines Systems aus Mechanismen und Diensten bedingt eine hohe Abhängigkeit der Komponenten. Fehler werden von unteren Schichten in die höheren propagiert. dabei können sich Fehlerklassen ändern und sehr komplexe Phänomene auftreten. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 9 Maskierung von Fehlern Hierarchische Maskierung - Fehler von Diensten oder Komponenten niedrigerer Ebene werden von den sie nutzenden Komponenten höherer Ebene maskiert. - ist eine Maskierung auf einer unteren Ebene nicht möglich, wird eine Ausnahme (engl.: exception) auf höherer Ebene ausgelöst, um dann dort maskiert zu werden. - einfaches Beispiel: - Abfrage auf Division durch Null, wenn die Divisionshardware dies nicht selbst melden kann. IF Nenner <> 0 THEN Teile... ELSE Fehlerbehandlung... - Wenn auf allen Ebenen die Maskierung unmöglich ist, muss letztlich der Benutzer über die Ausnahme informiert werden. Maskierung durch Gruppenbildung - der Fehler einer einzelnen Komponente wird durch die Replikation der Funktionalität in einer Gruppe verborgen. - eine Gruppe heisst k-fehlertolerant, wenn sie den gleichzeitigen Ausfall von k Mitgliedern maskieren kann. - es genügen k+1 Gruppenmitglieder, um das Fehlverhalten von k Komponenten zu maskieren. - für byzantinische Fehler werden 3k+1 Mitglieder benötigt, da eine Mehrheitsentscheidung notwendig ist. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 10
12.2 Passive Redundanz Passive Redundanz kann durch den Primary-Backup-Ansatz erreicht werden. es existieren k Replikate von Prozessen oder Daten, wobei ein Replikat als Primärserver fungiert. die restlichen Replikate arbeiten als Backup. Anfragen werden immer an den Primärserver gestellt. ist der Primärserver fehlerhaft oder antwortet nicht, wird er durch einen Backupserver ersetzt. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 11 Aktualisierung der Backupserver: - Hot-Standby - die Backupserver laufen synchron mit dem Primärserver mit. - alle Anfragen gehen an alle Server. - die Antwort wird nur vom Primärserver erbracht. - beim Ausfall des Primärservers ist sofort ein Backupserver verfügbar. - Warm-Standby - Aufträge werden beim Primärserver gespeichert und periodisch den Backupservern übermittelt. - die Backupserver werden dadurch nachgezogen. - nach einem Ausfall muss der letzte Backupblock noch bearbeitet werden. - ein Backupserver steht nach kurzer Zeit zur Verfügung. - Cold-Standby - alle Aufträge und Datenveränderungen werden beim Primärserver stabil gespeichert. - fällt der Primärserver aus, muss anhand dieser Daten ein Backupserver vollständig nachgezogen werden. - die Verzögerung für das Fortsetzen des Dienstes ist unter Umständen recht lang. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 12
damit Lebendigkeit und Verfügbarkeit des Primärservers überwacht werden kann, sendet dieser meist periodisch ALIVE-Nachrichten an seine Backupserver. werden eine bestimmte Zeit keine ALIVE-Nachrichten empfangen, vermuten die Backupserver, dass der Primärserver nicht mehr verfügbar ist. die Backupserver wählen unter sich einen neuen Primärserver. Passive Redundanz kann einen Knotenfehler, d.h. omission, des Primärservers maskieren. Passive Redundanz wird auch als lose Synchronisation bezeichnet. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 13 12.3 Aktive Redundanz alle beteiligten Komponenten bzw. Server sind als Zustandsmaschinen mit identischen Übergangsfunktionen implementiert. Anfragen und Kommandos von außen verändern die Zustände aller Server synchron. wenn die Zustandsmaschinen im gleichen initialen Zustand beginnen und Kommandos in der gleichen Reihenfolge bearbeiten, befinden sich alle Maschinen immer im gleichen Zustand und erzeugen identische Ausgaben. aktive Redundanz bezeichnet man auch als enge Synchronisation. fällt eine Komponente aus, kann dies zu jedem Zeitpunkt maskiert werden. Die Maskierung eines Fehlers erfordert Übereinkunft (engl.: agreement) und Ordnung (engl.: order). - Übereinkunft: - jede nicht-fehlerhafte Zustandsmaschine empfängt alle Kommandos und weiss welche anderen nicht-fehlerhaft sind. - Ordnung: - die empfangenen Kommandos werden bei allen Servern in der gleichen Reihenfolge ausgeführt. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 14
Übereinkunft kann durch ein byzantinisches Übereinkunftsprotokoll für byzantinische Fehler oder durch einen zuverlässigen Broadcast bei Fail-Stop-Verhalten realisiert werden. Ordnung kann man durch eindeutige Identifikatoren aller Nachrichten und eine totale Ordnung über diese Identifikatoren erreichen. theoretisch lässt sich in verteilten Systemen bei asynchronen Prozessen und unbeschränkter Nachrichtenlaufzeit Übereinkunft nicht erzielen [FLP85]. daher ist immer eine Restwahrscheinlichkeit gegeben, dass das fehlertolerante System Fehlverhalten zeigt. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 15 Byzantinisches Generalsproblem auf den Hügeln um Byzanz stehen die Truppen einiger römischer Generäle. um den Angriff zu koordinieren, melden sich die Generäle gegenseitig ihre Truppenstärken. keiner der Generäle kann sicher sein, dass nicht ein anderer General bestochen wurde und falsche Angaben macht, bzw. dass Nachrichten während der Übermittlung verfälscht werden. Beispiel 1 1 2 2 X 1 1 2 2 4 Y 4 Bild 12.2 Byzantinisches Generalsproblem 3 Z 4 4 Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 16
Übereinkunftsprotokoll von Lamport, Shostak und Pease 1982: - die Generäle teilen sich ihre Truppenstärken mit und erhalten folgende Information: 1: (1,2,X,4)2: (1,2,Y,4)3: (1,2,3,4)4: (1,2,Z,4) - die Generäle tauschen die gesammelten Informationen untereinander aus und haben danach folgende Entscheidungsgrundlage: 1: (1,2,Y,4)2: (1,2,X,4)3: (1,2,X,4)4: (1,2,X,4) (a,b,c,d) (e,f,g,h) (1,2,Y,4) (1,2,Y,4) (1,2,Z,4) (1,2,Z,4) (1,2,Z,4) (i,j,k,l) - jeder General kann selbst eine Majoritätsentscheidung durchführen. z.b. ist für General 1 klar, dass die Werte an den Positionen 1, 2 und 4 korrekt sind und der dritte General ein Fehlverhalten aufweist. mit dem Algorithmus können 3k+1 Komponenten k fehlerhaft arbeitende Komponenten maskieren. für die Mehrheitsentscheidung sind 2k+1 funktionstüchtige Komponenten notwendig (mehr als zwei Drittel). Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 17 Beispiel: 2k+1 Komponenten reichen nicht aus (hier: k=1). - in beiden Szenarien weiss A nicht, welcher der beiden anderen Knoten fehlerhaft ist, da er jeweils die gleichen Nachrichteninhalte empfängt. B 1 1 B 1 0 fehlerhaft A 0 C fehlerhaft A 0 C Bild 12.3 Byzantinische Übereinkunft ist mit 2k+1 Komponenten unmöglich Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 18
12.4 Zuverlässigkeit bei Softwaredesignfehlern Problem: - verwendet man für die Redundanz identische Software, wird ein Programmierfehler in allen Replikaten zum Tragen kommen. N-Versionen-Programmierung ein Problem wird von N verschiedenen Entwicklungsteams oder in N Varianten unabhängig voneinander bearbeitet. es entstehen N verschiedene Designs, welche die gleiche Funktionalität und identische Schnittstellen bieten. mit sehr hoher Wahrscheinlichkeit haben die einzelnen Versionen unterschiedliche Fehler, so dass sie gegenseitig die Fehler einzelner maskieren können. alle Programme laufen gleichzeitig aktiv redundant mit den gleichen Eingaben. die mehrfache Ausgabe wird durch einen Mehrheitsentscheid in eine einzige Ausgabe überführt. es muss beachtet werden, dass unter Umständen nicht auf exakte Gleichheit geprüft werden kann (engl.: consistent comparison problem). - eine Berechnung mit Gleitkommazahlen kann mit unterschiedlicher Rechenreihenfolge unterschiedliche Rundungsfehler erzeugen. weiteres Problem: die Laufzeit wird immer von der langsamsten Komponente bestimmt. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 19 Recoveryblock in einer Komponente werden kritische Kodepassagen in mehreren Versionen implementiert. die Komponente führt zuerst die Primärversion aus und prüft das Ergebnis durch einen Akzeptanztest gegen die Spezifikation. ist ein Fehler aufgetreten, wird der ursprüngliche Zustand wiederhergestellt und die nächste alternative Version benutzt. die Alternativen lassen sich schachteln. Beispiel: ensure <acceptance test> by <primary module> else by <alternate module 1>... else by <alternate module n> else error ein Akzeptanztest ist kein vollständiger, erschöpfender Test aller Systemanforderungen, sondern eher eine Stichprobe. er ist dazu so flexibel zu halten, dass mehrere leicht unterschiedliche Ausgaben der zu testenden Module zulässig sein können. Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 20
man kann dynamisch durch verschiedene Akzeptanztests auch unterschiedliches Verhalten des Systems ermöglichen. - wenn der erste Akzeptanztest nicht erfolgreich ist, führt man einen abgeschwächten Test mit geringeren Anforderungen durch. - wird dies wiederholt vorgenommen, kann ein adaptives System mit automatisch angepasster reduzierter Funktionalität realisiert werden (engl.: graceful degradation). Michael Weber, Verteilte Systeme, Wintersemester 2000/2001, Kapitel 12, Seite 21