Studienarbeit - Institut für Verteilte Systeme
Transcription
Studienarbeit - Institut für Verteilte Systeme
Entwurf und Implementierung einer generischen Protokollinstanz für die Varianten des Paxos-Algorithmus Studienarbeit im Fach Informatik vorgelegt von Udo Bartlang geb. am 13.05.80 in Temeschburg/Rumänien Angefertigt am Lehrstuhl für Informatik 4 (Verteilte Systeme und Betriebssysteme) Friedrich-Alexander-Universität Erlangen-Nürnberg Betreuer: Prof. Dr. Wolfgang Schröder-Preikschat Dipl.-Inf. Hans P. Reiser Dipl.-Inf. Rüdiger Kapitza Beginn der Arbeit: Abgabe der Arbeit: 1. August 2004 1. Februar 2005 Ich versichere, dass ich die Arbeit ohne fremde Hilfe und ohne Benutzung anderer als der angegebenen Quellen angefertigt habe und dass die Arbeit in gleicher oder ähnlicher Form noch keiner anderen Prüfungsbehörde vorgelegen hat und von dieser als Teil einer Prüfungsleistung angenommen wurde. Alle Ausführungen, die wörtlich oder sinngemäß übernommen wurden, sind als solche gekennzeichnet. Erlangen, 1. Februar 2005 Kurzzusammenfassung Leslie Lamports Paxos-Algorithmus liefert einen Mechanismus zur Lösung des Einigungsproblems in einem asynchronen, verteilten System. Aus seiner ursprünglichen Version entstanden Derivate wie Multi-Paxos, Fast-Paxos, DiskPaxos , oder Miguel Castros Variante für byzantinische Fehler, der BFT-PKAlgorithmus. Das Ziel dieser Arbeit ist es, im Kontext der Gruppenkommunikationsschicht von AspectIX, eine generische Protokollinstanz für eine crash-stop und eine crash-recovery Variante von Multi-Paxos, sowie für den BFT-PK-Algorithmus zu entwerfen und zu realisieren. Die Protokollinstanz soll innerhalb der Gruppenkommunikationsschicht als Modul eingesetzt werden, um eine totale Ordnung über den ausgetauschten Nachrichten innerhalb einer Gruppe zu etablieren. Die generische Protokollinstanz erlaubt es dabei je nach Anforderung, eine dynamische Rekonfiguration der gewünschten Version eines Einigungsalgorithmus zur Systemlaufzeit vorzunehmen. Dadurch wird es möglich einen rekonfigurierbaren, total-geordneten Gruppenkommunikationsdienst basierend auf einem verteilten Einigungsalgorithmus zu implementieren. Abstract Leslie Lamport’s Paxos algorithm describes a mechanism for the solution of the consensus problem in an asynchronous, distributed system. Out of the original version derived algorithms like Multi-Paxos, Fast-Paxos, Disk-Paxos, or Miguel Castro’s variant, to achieve consensus in the presence of Byzantine failures, the so called BFT-PK algorithm. The goal of this work is to design and realize, in the context of the Group Communication Layer of AspectIX, a generic protocol instance for a crash-stop and a crash-recovery variant of Multi-Paxos, as well as for the BFT-PK algorithm. The protocol instance ought to be used as a module in the Group Communication Layer to achieve a total order over the exchanged messages inside of a group. The generic instance permits a way to reconfigure dynamically the concrete used version of a consensus algorithm at run-time. This makes it possible, to implement a reconfigurable, totally-ordered group communication service based on distributed consensus algorithms. Inhaltsverzeichnis 1 Einleitung 1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Theoretischer Hintergrund . . . . . . . . . . . . . . . . . . . . . . 1.3 Gruppenkommunikationsschicht . . . . . . . . . . . . . . . . . . . 2 Theoretische Betrachtung der 2.1 Basic-Paxos . . . . . . . . . 2.2 Multi-Paxos . . . . . . . . . 2.3 BFT-PK . . . . . . . . . . . Algorithmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Entwurf und Implementierung 3.1 Anforderungen . . . . . . . . . . . . . . . . . . . . . 3.2 Grundstruktur . . . . . . . . . . . . . . . . . . . . . . 3.3 Generische Protokollinstanz als Einigungskomponente 3.4 Rekonfiguration zur Laufzeit . . . . . . . . . . . . . . 3.5 Multi-Paxos . . . . . . . . . . . . . . . . . . . . . . . 3.6 BFT-PK . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 4 6 8 8 14 16 . . . . . . 26 26 28 31 33 36 49 4 Messungen 4.1 Rahmenbedingungen . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Ergebnisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 59 61 5 Zusammenfassung und mögliche Ergänzungen 5.1 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Mögliche Ergänzungen . . . . . . . . . . . . . . . . . . . . . . . . 65 65 66 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kapitel 1 Einleitung 1.1 Motivation Da singuläre Systeme durch ihre schlechte Eigenschaft als single point of failu” re“, in der Regel einen Flaschenhals in Bezug auf Leistung und Zuverlässigkeit darstellen, gewinnen verteilte Systeme immer mehr an Bedeutung. Ein priorer Wunsch bei dem Einsatz eines Systems ist es, einen offerierten Dienst1 möglichst hoch verfügbar anzubieten. Aus dieser Intention heraus entsteht die Idee, einen Dienst nicht exklusiv auf einem einzigen Server zu betreiben, sondern diesen repliziert auf eine Gruppe von Rechnern zu verteilen. Um zu gewährleisten, dass die Replikate in einem untereinander konsistenten Zustand betrieben werden, sind Mechanismen notwendig, welche in der Lage sind die Zustände der einzelnen Replikate zu synchronisieren. Das Wunschziel dabei ist, einen auf mehrere Knoten2 replizierten Dienst nach außen hin als exklusiv, auf einem einzigen Knoten laufend, erscheinen zu lassen. Verteilte Einigungs-Algorithmen bilden die Grundlage eines solchen Dienstes, welcher im optimalen Fall immer korrekt funktioniert und seine Leistung permanent anbieten kann. 1.1.1 Ziel der Arbeit Leslie Lamports Paxos-Algorithmus beschreibt einen Mechanismus zur Lösung des Einigungsproblems und damit eine mögliche Lösung der Synchronisation in einem verteilten System. 1 In diesem Kontext bezeichnet ein Dienst eine beliebige als deterministischer Zustandsautomat modellierbare Anwendung. 2 Der Terminus Knoten abstrahiert von der konkret dahinterstehenden Instanz eines Rechners, Prozessors oder Prozesses. Ein Knoten repräsentiert somit eine einzelne aktive Instanz in einem verteilten System, welche mit anderen Instanzen alleine durch den Austausch von Nachrichten kommuniziert. 2 1.1. Motivation 3 Das Ziel dieser Arbeit ist es, im Rahmen der Gruppenkommunikationsschicht von AspectIX, eine generische Protokollinstanz für eine crash-stop und ein crashrecovery Variante von Multi-Paxos, sowie für den byzantinisch fehlertoleranten BFT-PK zu entwerfen und zu implementieren. Die Gruppenkommunikation stellt dabei den verteilten Dienst dar, dessen Arbeitsweise durch die realisierte Protokollinstanz zu synchronisieren ist. Dabei soll diese als Modul in die Gruppenkommunikationsschicht integriert werden und zur totalen Ordnung der ausgetauschten Nachrichten innerhalb einer Gruppe Verwendung finden. Um in der Lage zu sein das Gruppenkommunikationssystem zur Laufzeit auf sich ändernde Rahmenbedingungen einstellen zu können, soll in dieser Arbeit eine generische Protokollinstanz entwickelt werden, die es erlaubt die konkrete Version des Einigungsalgorithmus dynamisch zu rekonfigurieren. Unter sich ändernden Rahmenbedingungen versteht man beispielsweise ein sich änderndes Fehlverhalten der an einer Gruppe beteiligten Knoten. Die realisierte Protokollinstanz kann wahlweise konfiguriert werden um ein gutmütiges, oder sogar ein byzantinisches Fehlverhaltensmodell zu tolerieren. Im Kontext eines gutmütigen Fehlermodells kann nach Bedarf, auch ein Wiederanlaufen von Knoten, gemäß einem crash-recovery Verhaltens ermöglicht werden. Dem Gruppenkommunikationsdienst wird somit die Möglichkeit geboten, sich dynamisch zur Laufzeit zu entscheiden welches Fehlermodell dieser akut unterstützen will. Da sich die Anzahl der Teilnehmer in dem betrachteten Gruppenkommunikationssystem im Laufe der Zeit ändern kann, erlaubt die implementierte Protokollinstanz eine dynamische Adaption der eingesetzten Algorithmen an diesen Sachverhalt. 1.1.2 Aufbau der Arbeit Im Folgenden werden theoretische Hintergründe der Arbeit kurz präsentiert. Dabei wird im Wesentlichen auf die Problemstellung einer verteilten Einigung eingegangen. In Kapitel 2 werden die in der Arbeit eingesetzten Einigungsalgorithmen theoretisch vorgestellt. Dabei werden ihre Funktionalitäten und ihre Anforderungen an ein Systemmodell erläutert. Kapitel 3 beschreibt den Entwurf und die Realisierung der generischen Protokollinstanz. In dem Kapitel werden zudem die wichtigsten Entwurfsentscheidungen und Implementierungsdetails gezeigt. Um die Implementierung hinsichtlich ihrer Leistungsfähig zu analysieren, werden in Kapitel 4 durchgeführte Messungen dargestellt und analysiert. Das letzte Kapitel fasst schließlich die wesentlichen Erfahrungen und Schlussfolgerungen, die beim Erstellen dieser Arbeit gewonnen werden konnten, zusammen und gibt einen Ausblick auf mögliche Ergänzungen. 4 1.2 1.2.1 Kapitel 1. Einleitung Theoretischer Hintergrund Verteilte Systeme Ein verteiltes System bezeichnet eine Konfiguration mehrerer autonomer Knoten, die durch ein Netzwerk miteinander verbunden sind und kooperieren um eine gemeinsame Aufgabe zu lösen, beziehungsweise einen Dienst anzubieten. Die Kommunikation der Knoten untereinander beschränkt sich dabei auf den reinen Austausch von Nachrichten. 1.2.2 Kommunikationsmodelle Im Kontext verteilter Algorithmen differenziert man die Art des Nachrichtenaustausches in synchrone und asynchrone Kommunikation. Der Unterschied der beiden Kommunikationsarten liegt in der komplementären Annahme über die Laufzeit der ausgetauschten Nachrichten begründet. Während die synchrone Kommunikation es erlaubt, von einer maximalen Laufzeit einer Nachricht auszugehen, kann die Laufzeit bei der asynchronen Variante theoretisch beliebig groß werden. Somit kann bei der synchronen Kommunikation sicher auf einen Verlust einer Nachricht, damit eventuell implizit auf einen Ausfall eines Knotens, geschlossen werden, falls diese nicht innerhalb eines maximalen Zeitfensters eintreffen sollte. Dieser sichere Schluss ist bei der asynchronen Kommunikation nicht möglich. Bei der asynchronen Variante ist durch den Einsatz von Timeout-Mechanismen ein langsamer von einem ausgefallenen Knoten nicht definitiv unterscheidbar. 1.2.3 Fehlermodelle Ein Vorteil bei dem Einsatz eines verteilten gegenüber dem eines singulären Systems, liegt in der Tolerierung gewisser Grade des Ausfalls, beziehungsweise Versagens3 , seiner Komponenten. Ein einzelnes System wird durch einen Ausfall in der Regel unbrauchbar, während ein verteiltes System in der Lage ist, Ausfälle gewisser Teilkomponenten zu kompensieren. Ein verteiltes System ist also ein Gebilde, dass sich aus der Summe seiner Komponenten zusammensetzt. Je mehr Komponenten allerdings an einem solchen System beteiligt sind, desto wahrscheinlicher wird es, dass sich eine be3 Während einem Ausfall eine physikalische Veränderung der betroffenen Komponente zugrunde liegt, findet bei einem Versagen keine physikalische Modifikation statt [Sag03]. Ein Versagen betrifft damit sowohl Hardware, als auch Software. Im Weiteren wird nur der Begriff des Ausfalls verwendet. 1.2. Theoretischer Hintergrund 5 teiligte Komponente fehlerhaft verhält. Das Fehlverhalten der Knoten lässt sich folgendermaßen differenzieren: • Man spricht von einem gutmütigen Fehlverhalten(benign faults), wenn ein Knoten zwar ausfallen darf, er sich bis zu dem Zeitpunkt seines Ausfalls jedoch spezifikationsgerecht verhalten muss. • Demgegenüber kann sich ein Knoten gemäß einem byzantinischen Fehlermodells handelnd(malicious faults), beliebig“ verhalten. Dieser könnte auch ” Aktionen vollführen, welche ein korrekter Knoten nicht tun würde. 1.2.4 Verteilter Konsensus Im Kontext der verteilten Systeme bezeichnet das Einigungsproblem(consensus problem) die Problematik der konsistenten Einigung innerhalb einer Gruppe verteilter Knoten. Jeder beteiligte Knoten propagiert einen Vorschlag eines möglichen Einigungswerts(proposal). Sobald sich alle fehlerfreien Knoten auf den gleichen Wert einigen, ist eine Lösung des Problems erreicht. Sollten alle Knoten den gleichen Wert vorschlagen, muss eine Einigung auf genau diesen Wert erfolgen. Sollte kein einziger Knoten einen Wert vorschlagen, soll auch keine Einigung auf einen Wert erfolgen. Eine dem Einigungsproblem äquivalente Form ist das sogenannte Verständigungsproblem (agreement problem). Im Gegensatz zu dem Einigungsproblem wird ein möglicher Einigungswert jedoch nicht von allen Knoten, sondern nur von einem bestimmten Knoten, dem sogenannten Anführer(leader), vorgeschlagen. Löst ein Algorithmus das Einigungsproblem, so lässt sich mit diesem ebenfalls das Verständigungsproblem lösen und umgekehrt. Beide Problemstellungen sind somit zueinander synonym [RK03]. Will man einen Algorithmus, beziehungsweise ein Protokoll, zur Lösung des Einigungsproblems formulieren, muss der Algorithmus bestimmten Anforderungen hinsichtlich der Konsistenz genügen: • Eine Einigung darf nur auf einen Entscheidungswert erfolgen, der auch von einem Teilnehmer am Einigungsprozess vorgeschlagen worden ist. • Eine Einigung muss auf einen einzigen Wert erfolgen, das heißt, korrekte Knoten dürfen sich nicht unterschiedlich entscheiden. • Jeder Knoten entscheidet sich genau ein einziges Mal. • Ein Knoten wird nur über eine erfolgreiche Einigung informiert, falls es auch eine solche gegeben hat. • Jeder korrekte Knoten entscheidet sich irgendwann definitiv. 6 Kapitel 1. Einleitung Die ersten vier Bedingungen entstehen durch den Anspruch auf Sicherheit (safety), während die letzte Bedingung, die Forderung nach einer Terminierung, aus Gründen des Wunsches nach Lebendigkeit (liveness) entsteht. Problematik Ein gewisses Zugeständnis an die Lösbarkeit des Einigungsproblems in einem asynchronen Kommunikationssystem muss man gemäß [FLP85] erbringen. Der sogenannten FLP impossibility folgend ist es nicht möglich einen deterministischen, total korrekten Algorithmus für das Einigungsproblem in dem asynchronen Fall zu finden, wenn auch nur ein inkorrekter Knoten am Einigungsprozess beteiligt ist. Der Beweis gilt allerdings nur für total korrekte Algorithmen, das heißt es können partiell korrekte Algorithmen zur Lösung des Einigungsproblems im asynchronen Fall existieren, wie beispielsweise der betrachtete Paxos-Algorithmus und seine Derivate. Paxos erfüllt immer die formulierten Sicherheit-Konsistenzbedingungen des Einigungsproblems, seine zuverlässige Terminierung ist jedoch nicht immer gewährleistet. Tatsächlich unterliegt die Lebendigkeit des Algorithmus bestimmten partiell-synchronen“ Annahmen, was eine Lösung des Einigungspro” blems im asynchronen Fall ermöglicht. 1.3 Gruppenkommunikationsschicht Die Gruppenkommunikationsschicht von AspectIX [Löh04] bildet die praktische Anwendung der in dieser Arbeit realisierten Lösung des verteilten Konsensus. Das Hauptanwendungsgebiet der Gruppenkommunikation bildet die Unterstützung der Implementierung replizierter Dienste. Die Gruppenkommunikationsschicht ermöglicht es allen Teilnehmern eines unterstützten Dienstes die gleichen Nachrichten in derselben Reihenfolge zuzustellen, also eine totale Ordnung über die ausgetauschten Nachrichten zu etablieren. Eine Besonderheit liegt in der modularen Architektur und dem Funktionsprinzip gemäß des Ansatzes einer agreement based group communication“. ” Die Schicht ermöglicht also die Funktionalität eines konsistenten Nachrich” tendienstes“ durch den Einsatz eines austauschbaren Einigungsalgorithmus in ihrem Kern, welcher durch eine einfach gehaltene Schnittstelle zur Verfügung stehen soll. Der Algorithmus soll eine Einigung auf die nächste von einem Teilnehmer empfangene Nachricht und damit eine totale Ordnung aller Nachrichten erzielen. Da die Gruppe dynamisch verwaltet werden soll, wird auch das Management der Gruppe über die Funktionalität der Einigungskomponente erzielt. Die in dieser Arbeit realisierte generische Protokollinstanz füllt somit den Kern für eine korrekt arbeitende Gruppenkommunikation. Dadurch wird es möglich 1.3. Gruppenkommunikationsschicht 7 einen rekonfigurierbaren, total-geordneten Gruppenkommunikationsdienst, basierend auf einem verteilten Einigungsalgorithmus, zu implementieren. AspectIX selbst ist eine CORBA-basierte Middleware, die aktuell an der Universität Ulm und der Friedrich-Alexander-Universität Erlangen-Nürnberg entwickelt wird [ASP05]. Kapitel 2 Theoretische Betrachtung der Algorithmen In diesem Kapitel werden die in der Arbeit verwendeten Algorithmen theoretisch betrachtet und kurz vorgestellt. Allen Algorithmen ist gemein, dass sie dafür vorgesehen sind, ausgehend von der Lösung des Verständigungsproblems, das Einigungsproblem in einem asynchronen Kommunikationssystem zu lösen. Ein Unterschied der Algorithmen bildet die jeweilige Annahme über das unterstützte Fehlermodell der am Konsensusprozess beteiligten Knoten. Während Basic-Paxos und der darauf basierende Multi-Paxos lediglich in der Lage sind ein maximal gutmütiges Fehlverhalten der Teilnehmer zu tolerieren, erlaubt es der BFT-PK-Algorithmus auch mit sich byzantinisch fehlerhaft verhaltenden Knoten umzugehen. 2.1 Basic-Paxos Die ursprüngliche Form des sogenannten Paxos-Algorithmus stammt von Leslie Lamport [Lam89]. Dadurch, dass Paxos keinen Anspruch auf totale Korrektheit hinsichtlich seiner Terminierung stellt, ist der Algorithmus trotz [FLP85] in der Lage das Einigungsproblem in einem asynchronen Kommunikationssystem zu lösen. Der Paxos-Algorithmus ist dabei effizient und fehlertolerant. Durch sein flexibel gestaltbares Konzept bildet er die Grundlage zahlreicher auf ihn basierender Derivate. Durch seine Anwendung ermöglicht er die Implementierung fehlertoleranter replizierter Dienste. Im Weiteren wird Paxos in seiner einfachen Variante als Basic-Paxos bezeichnet. Basic-Paxos ist dafür konzipiert, eine einmalige Einigung auf einen Entscheidungswert zu ermöglichen. Er erlaubt also die Lösung des Einigungsproblems, einer einzigen Einigungsinstanz1 . Im Hinblick auf einen praktischen Einsatz ist 1 Eine Einigungsinstanz ist als eine einzige Runde zur Lösung des Einigungsproblems zu verstehen. 8 2.1. Basic-Paxos 9 der alleinige Gebrauch von Basic-Paxos somit wenig sinnvoll, da ein replizierter Dienst in der Regel fortwährend koordiniert werden muss. 2.1.1 Systemmodell Im Folgenden werden die Voraussetzungen genannt, die Basic-Paxos für ein korrektes Funktionieren an seine Umwelt“ stellt. ” Kommunikation Der Algorithmus arbeitet auf einem asynchronen Kommunikationsmodell, in dem Knoten durch den direkten Austausch von Nachrichten miteinander kommunizieren. Es wird vorausgesetzt das jeder Knoten in der Lage ist zu jedem anderen Teilnehmer eine Nachricht zu senden, beziehungsweise von jedem am Konsensusprozess beteiligten Knoten eine Nachricht zu empfangen. Theoretisch betrachtet sollte somit zwischen zwei beliebigen Knoten ki und kj eine bidirektionale Kommunikationsverbindung bestehen. Das zugrunde liegende Kommunikationssystem darf dabei Nachrichten in ihrer Laufzeit beliebig lange verzögern, duplizieren oder gar verwerfen, also nicht zustellen(omission failure). Es sollte allerdings gelten, dass im Kommunikationssystem keine Nachrichten entstehen“. Ein Knoten soll eine Nachricht also erst ” empfangen, nachdem ein anderer Knoten diese gesendet hat. Darüberhinaus gilt als letzte Annahme, dass falls ein Knoten ki eine Nachricht an Knoten kj unendlich oft sendet, ein korrekter kj diese Nachricht auch unendlich mal empfängt(weak loss [Lyn96]). Da der Algorithmus jedoch nicht in der Lage ist byzantinische Fehler zu tolerieren, dürfen Nachrichten auf keinen Fall auf eine beliebige Art verfälscht werden. Knoten Basic-Paxos geht von einer festen Menge, mit einer unveränderlichen Anzahl von n am Einigungsprozess teilnehmenden Knoten N = {k1 , k2 , ..., kn } aus. Ein Knoten wird dabei hinsichtlich seiner Verarbeitungsgeschwindigkeit keinerlei Restriktionen unterworfen. Um einen sinnvollen Progress zu gewährleisten, sollten die Knoten allerdings in der Lage sein eintreffende Nachrichten zügig“ zu verarbei” ten. Restriktiver verhält es sich mit der Annahme über das unterstützte Fehlverhalten von Knoten. Paxos ist nicht in der Lage ein byzantinisches Fehlverhalten zu tolerieren, ein Knoten darf sich somit maximal gutmütig fehlerhaft verhalten. Basic-Paxos kann somit Totalversagen(crash-stop) von Knoten verkraften. Ein Knoten k ist somit zu einem bestimmten Zeitpunkt t entweder ausgefallen, oder er arbeitet korrekt. 10 Kapitel 2. Theoretische Betrachtung der Algorithmen Die maximale Knotenanzahl an ausgefallenen Teilnehmern ist dabei nicht beschränkt. Alleine um einen Progress zu erzielen muss ein Quorum2 an Knoten in der Lage sein miteinander zu kommunizieren. Als zusätzliche Fähigkeit bietet Basic-Paxos die Möglichkeit, dass Knoten wiederanlaufen dürfen(crash-recovery). Falls dies unterstützt werden soll, muss ein Knoten Zugriff auf ein persistentes Speichermedium besitzen auf dieses er notwendige“ Systeminformationen vor seinem Abbruch ablegen kann. Ein Kno” ten sollte somit sowohl mit einem flüchtigen, als auch mit einem nicht-flüchtigen Speichermedium ausgestattet sein. Als Letztes ist es erforderlich, dass jeder Knoten über eine systemweit eindeutige Bezeichnung(NodeID) identifizierbar ist. Dies wäre etwa durch eine totale Ordnung aller im System vorhandenen NodeIDs gegeben. Die Eindeutigkeit der Bezeichnung ist für den Einigungsprozess des Basic-Paxos grundlegend, da jeder Vorschlagswert eines Knotens durch eine eindeutige Sequenznummer ausgezeichnet wird, welche ihrerseits aus der NodeID berechnet wird. 2.1.2 Funktionsweise Basic-Paxos unterteilt die Menge der am Konsensus beteiligten n Knoten theoretisch in normale“ Teilnehmer und einen ausgezeichneten Anführerknoten. Nur ” ein Anführer soll in der Lage sein, einen Einigungswert vorzuschlagen. Praktisch ist diese Unterteilung jedoch nicht als exklusiv zu betrachten, da in der Regel ein Anführer gleichzeitig auch einen Teilnehmer darstellt. Theoretisch ist jeder Knoten in der Lage die Aufgabe eines Anführers wahrzunehmen. Praktisch gesehen ist es jedoch sinnvoll zur Laufzeit einen einzigen Knoten als Anführer auszuzeichnen, da mehrere gleichzeitige Anführer das System in dem Progress der Entscheidungsfindung behindern würden. Letzteres schafft das Problem der eindeutigen Bestimmung eines Anführers. In einem asynchronen System, in dem jeder Knoten zu jedem Zeitpunkt ausfallen kann, ist es unmöglich eine deterministische, sichere Lösung dieses Problems zu bieten. In der ursprünglichen Beschreibung [Lam89] ist keine bestimmte Vorgehensweise zur Bestimmung eines Anführers formuliert. Für den Progress und damit die Lebendigkeit von Basic-Paxos wird lediglich gefordert, dass alle n Knoten den gleichen Anführer annehmen, sowie dass bei einem Ausfall eines Anführers möglichst bald ein neuer Anführer bestimmt wird. Basic-Paxos genügt somit die Annahme, dass es in dem System irgendwann immer einen exklusiven Anführer geben wird, wobei Sicherheit permanent gewährleistet ist. Dadurch, dass keine strengere Bedingung erforderlich ist, löst Basic-Paxos trotz [FLP85] 2 Basic-Paxos ist in der Lage auf einem beliebigen Quorensystem zu operieren. In diesem Kontext wird jedoch stets von dem beliebten Fall der Mehrheitsquoren ausgegangen. Unter einem Quorum Q wird somit l m eine einfache Mehrheit verstanden, gebildet durch folgende Anzahl an Knoten: |Q| ≥ |N2|+1 . 2.1. Basic-Paxos 11 das Einigungsproblem. Ein Beweis der Korrektheit des Algorithmus findet sich beispielsweise in [PLL00]. Eine einfache Anführerwahl ermöglicht sich unter der Bedingung total geordneter NodeIDs und der Annahme jeder Knoten schicke periodisch ein Lebenszeichen an alle anderen Teilnehmer. Es würde derjenige Knoten als Anführer erkoren, welcher unter allen als nicht ausgefallen betrachteten Knoten, die kleinste NodeID besitzt. Da diese Lösung nicht besonders fair ist, bietet sich hier Optimierungspotential. In der Realisierung der Arbeit wird zur Lösung des Problems auf einen Fehlerdetektor, ähnlich [CT96] zurückgegriffen. Die einmalige Einigung auf einen gemeinsamen Vorschlagswert verläuft in Basic-Paxos grob nach folgendem Schema, wobei eine besondere Unterscheidung der Termini Akzeptieren eines Wertes“, versus Auswahl eines Wertes“ notwendig ” ” ist: Zunächst wird unter allen Teilnehmern ein Anführer bestimmt, der im Anschluss einen Wert zur Einigung propagiert. Jedes Replikat kann diesen Vorschlag akzeptieren. Ein Vorschlag wäre erfolgreich, falls ein Quorum an Knoten existiert, welches den gleichen Vorschlag akzeptiert hat. Dieser Vorschlag wäre dann endgültig ausgewählt. Das Akzeptieren eines Wertes stellt somit die Vorstufe zu dessen finaler Auswahl dar. 2.1.3 Ablauf Abbildung 2.1 stellt eine Illustration eines möglichen Ablaufszenarios dar. Sie zeigt das Scheitern des ursprünglichen Anführerknotens k1 und den anschließenden erfolgreichen Einigungsprozess, initiiert durch den nachfolgenden Anführer k2 . Wie man aus Abbildung 2.1 ersehen kann, lässt sich der Ablauf des Algorithmus logisch in drei Phasen unterteilen: 1. In der ersten Phase stellt ein Anführer sicher, dass er einen korrekten Wert vorschlagen wird und er der alleinige Anführer im System ist. Dazu informiert er sich, ob in dem System bereits alte“ Vorschlagswerte vorhanden ” sind. 2. Mittels der gewonnenen Erkenntnisse aus der ersten Phase, propagiert der Anführer in der zweiten Phase einen konsistenten“ Wert. ” 3. Die dritte Phase dient letztendlich dazu, eine erfolgreiche Einigung im System zu kommunizieren. Im Weiteren werden die einzelnen Phasen näher erläutert. 12 Kapitel 2. Theoretische Betrachtung der Algorithmen k1 k2 k3 k4 [READ,1] [ACK_READ,1,-1,null] [WRITE,1,v] [READ,2] (Phase 1) [ACK_READ,2,1,v] [WRITE,2,v] (Phase 2) [ACK_WRITE,2] [DECISION,v] (Phase 3) Abbildung 2.1: Ablaufszenario von Basic-Paxos Phase 1 • Der Einigungsalgorithmus startet damit, dass ein Anführerknoten eine READ-Nachricht [READ, seqNr] an alle am Konsensus teilnehmenden Knoten sendet. Die READ-Nachricht beinhaltet dabei eine vom Anführer angedachte Sequenznummer seqN r. Basic-Paxos verwendet Sequenznummern um korrelierende Nachrichten eindeutig zu identifizieren. Dabei muss bei der Wahl von seqN r beachtet werden, dass diese systemweit eindeutig ist. Ansonsten könnten byzantinische Fehlersituationen entstehen. Um dieses Problem zu meistern, könnte man beispielsweise den Wertebereich an möglichen Sequenznummern disjunkt auf die Teilnehmer verteilen, zum Beispiel durch Anwendung folgender Formel: seqN r = N odeID + k·|N |, mit k ≥ 0 (2.1) 2.1. Basic-Paxos 13 Eine größere Sequenznummer lässt dabei auf einen späteren“ Vorschlags” wert schließen und umgekehrt. – Empfängt ein korrekter Knoten eine READ-Nachricht, antwortet er mit einem NACK-READ [NACK READ, seqNr], falls bereits ein READ oder WRITE mit einer größeren Sequenznummer als seqNr erhalten wurde. – Andernfalls antwortet der Knoten mit einem ACK-READ [ACK READ, seqNr, seqNr’ ,proposal’], wobei seqN r0 die größte bis dato aus einer empfangenen WRITE-Nachricht entstammende Sequenznummer bezeichnet und proposal0 den dazu korrespondierenden akzeptierten Vorschlagswert. Soll ein Wiederanlaufen von Knoten ermöglicht werden, muss der Knoten das Versprechen, keine Vorschläge mit einer Sequenznummer kleiner als seqN r zu akzeptieren persistent sichern. Er muss also konkret seqN r auf einem nicht-flüchtigen Speichermedium ablegen. – Hat ein Knoten noch keine WRITE-Nachricht akzeptiert, bezeichnen seqN r0 und proposal0 default“–Werte. Erstreckt sich der Sequenznum” mernbereich über N0 , könnte man beispielsweise seqN r0 mit −1 und proposal0 mit dem speziellen Wert null belegen. • Ein Anführer wartet auf ACK-READ-Nachrichten eines Quorums unterschiedlicher Knoten und bildet daraus seinen Vorschlagswert für die zweite Phase. Empfängt ein Anführer mindestens ein NACK-READ, beendet er seine weiteren Versuche einen Wert zu propagieren, da er sich sicher sein kann, dass es mindestens einen anderen aktiven Anführer im System gibt. Somit werden Einigungsversuche die nicht zu der größten im System bekannten Sequenznummer gehören, konsequent abgebrochen. Damit ein Anführer nicht unendlich lange auf ein Quorum an ACK-READNachrichten wartet, zum Beispiel könnte die Mehrzahl der Knoten in der Zwischenzeit temporär ausgefallen sein, muss er Basic-Paxos mit einer größeren Sequenznummer, gebildet gemäß Formel 2.1, erneut starten. Phase 2 • Ein Anführer sendet eine WRITE-Nachricht [WRITE, seqNr, proposal] an die Teilnehmer in der Hoffnung, dass diese seinen Vorschlagswert proposal akzeptieren. Der Wert proposal ist dabei entweder der eigene Vorschlag, den der Anführer ursprünglich propagieren wollte, oder es handelt sich um den Wert proposal0 , der zu der höchsten Sequenznummer seqN r0 , aller empfangenen ACK-READ-Nachrichten korrespondiert. 14 Kapitel 2. Theoretische Betrachtung der Algorithmen • Ein Knoten antwortet, analog zu der ersten Phase, bei Erhalt einer WRITENachricht entweder mit: – Einer NACK-WRITE-Nachricht [NACK WRITE, seqNr], falls er bereits ein READ oder ein WRITE mit einer größeren Sequenznummer empfangen hat. – Ansonsten akzeptiert er das WRITE und kommuniziert dies durch eine positive Quittierung mittels einer ACK-WRITE-Nachricht an den Anführer [ACK WRITE, seqNr]. Soll ein Wiederanlaufen von Knoten ermöglicht werden, muss der Knoten das Versprechen, keine Vorschläge mit einer Sequenznummer kleiner als seqN r zu akzeptieren, persistent sichern. Er müsste somit seqN r und proposal auf einem nicht-flüchtigen Speichermedium festhalten. • Der Anführer wartet wiederum bis er entweder mindestens eine negative Bestätigung, also ein NACK-WRITE, erhält und bricht seine Ausführung daraufhin ab. Oder er erhält durch ein Quorum positive Rückmeldungen und fährt mit der dritten Phase fort. Phase 3 • Empfängt ein Anführer ACK-WRITE-Nachrichten durch ein Quorum unterschiedlicher Knoten, wurde sein Vorschlag im System ausgewählt und die Einigung ist somit erfolgt. Um das Gelingen den restlichen Knoten mitzuteilen, versendet er an alle eine DECISION-Nachricht [DECISION, proposal]. • Jeder Knoten, der ein DECISION empfängt, entscheidet sich endgültig für Wert proposal. • Optional könnte ein Knoten das erfolgreiche Empfangen eines DECISIONs dem Anführer positiv quittieren. In dem Diagramm der Abbildung 2.2 ist noch einmal der gesamte Ablauf des Algorithmus aus der Sicht eines Anführers zusammengefasst. 2.2 Multi-Paxos Der in Abschnitt 2.1 beschriebene Basic-Paxos ist für eine einzige Entscheidung des Einigungsproblems in einem asynchronen System konzipiert. Will man einen verteilt replizierten Dienst implementieren, ist man in der Regel an einer sukzessiven Lösung, also einer Unterstützung beliebig vieler Entscheidungsinstanzen“, ” beziehungsweise Entscheidungsrunden“, interessiert. Multi-Paxos wurde genau ” aus dieser Problemstellung heraus kreiert. Die ursprüngliche Idee geht, wie schon im Falle des Basic-Paxos, wieder auf Leslie Lamport zurück [Lam89]. 2.2. Multi-Paxos 15 Abbildung 2.2: UML-Aktivitätsdiagramm eines Anführers 2.2.1 Systemmodell Die Annahmen, denen Multi-Paxos zugrunde liegt, entsprechen größtenteils dem Systemmodell von Basic-Paxos aus Abschnitt 2.1.1. Der entscheidende Unterschied besteht in der Annahme über die feste Menge an teilnehmenden Knoten. Multi-Paxos kann angepasst werden, um eine dynamische Änderung der Anzahl der am Konsensus beteiligten Knoten zu ermöglichen. 2.2.2 Funktionsweise Basic-Paxos liefert eine einmalige Einigung auf eines Entscheidungswert. Das Prinzip von Multi-Paxos ist es nun, für eine Lösung einer einzelnen Entscheidungsinstanz, Basic-Paxos zu verwenden. Einzelne Entscheidungsinstanzen werden dabei in Runden unterteilt, die eindeutig über eine Rundennummer 16 Kapitel 2. Theoretische Betrachtung der Algorithmen roundN r3 gekennzeichnet und identifizierbar sind. Am einfachsten erscheint es, für die Entscheidungsfindung der einzelnen Runden, einfach voneinander unabhängige Basic-Paxos–Instanzen einzusetzen. Da sich ein globales Systemverhalten, wie der Ausfall von Knoten, jedoch auf alle laufenden Runden von Multi-Paxos auswirkt, bietet sich hier Optimierungspotential. Theoretisch betrachtet, wäre Multi-Paxos in der Lage beliebig viele Einigungsrunden parallel zueinander ablaufen zu lassen, wobei jede einzelne Runde auf einer festen Menge an Teilnehmern operiert. Eine Lösungsidee zu der dynamischen Adaption des Algorithmus an eine sich ändernde Teilnehmermenge ist kurz in [Lam01] angedeutet: • Zunächst muss man Multi-Paxos auf eine feste Anzahl von k zueinander parallel ablaufenden Runden begrenzen. Runde n+k darf also erst gestartet werden, wenn Runde n entschieden ist. • Als nächstes kann man eine mögliche Änderung der am Konsensusprozess beteiligten Knotenmenge, selber wieder durch einen von einem Anführer vorgeschlagenen Einigungswert formulieren. • Konsistenz wird schließlich dadurch erreicht, dass, falls eine Einigung über eine Änderung der Knotenmenge in Runde n erfolgt ist, diese Änderungsaktion erst für Runden ≥ n + k im System übernommen werden darf. 2.2.3 Ablauf Ein Anführer hat bei Multi-Paxos die Möglichkeit beliebig viele Entscheidungswerte für verschiedene Runden zu propagieren. Dazu instanziiert er für jeden Entscheidungswert und damit für jede Runde eine Instanz von Basic-Paxos. Das Konzept von Multi-Paxos bildet folglich eine Abstraktion über die einzelnen verwendeten Basic-Paxos–Instanzen. Der Ablauf von Multi-Paxos in einer Runde gleicht somit, in seiner einfachsten Form, dem in Abschnitt 2.1.3 beschriebenen Ablauf von Basic-Paxos. Ein Unterschied ist, dass jede versendete Nachricht zusätzlich eine eindeutige Rundennummer roundN r in sich trägt. Dies geschieht zur Differenzierung der einzelnen Entscheidungsinstanzen. Die roundN r wird durch einen Anführer inkrementierend vergeben. 2.3 BFT-PK BFT-PK löst das Einigungsproblem in einem asynchronen verteilten System, für eine beliebige Anzahl von Entscheidungsinstanzen und unterstützt dabei, im Gegensatz zu Multi-Paxos, zusätzlich ein byzantinisches Fehlermodell. 3 roundN r∈ N0 2.3. BFT-PK 17 Mit auch nur einem einzigen sich byzantinisch fehlverhaltendem Teilnehmer könnte Multi-Paxos keine Gewährleistung über einen korrekten Einigungsprozess geben. Dieses Problem wurde für ein asynchrones System durch Miguel Castros byzantinisch fehlertolerantes Einigungsprotokoll Byzantine Fault To” lerance Algorithm“ [Cas01], kurz BFT, gelöst. In der Arbeit wird der sogenannte BFT-PK-Algorithmus, eine mit einer Public-Key-Signierung arbeitenden Variante des BFT betrachtet. Analog zu Multi-Paxos kann BFT-PK dafür verwendet werden jede Art eines replizierten Dienstes zu implementieren. 2.3.1 Systemmodell Im Folgenden werden die Rahmenbedingungen für ein korrektes Funktionieren des BFT-PK formuliert. Dabei werden jegliche Annahmen, die für Basic-Paxos gelten, siehe Abschnitt 2.1.1, unterstützt. Kommunikation BFT-PK operiert auf einem asynchronen verteilten System, in welchem Knoten, durch ein unzuverlässiges Netzwerk miteinander verbunden, auf der Grundlage des Austauschens von Nachrichten miteinander kommunizieren. Das Netzwerk darf dabei versendete Nachrichten verlieren, beliebig lange verzögern, duplizieren oder außer Reihenfolge zustellen. Da der Algorithmus byzantinische Fehler tolerieren kann, dürfen Nachrichten auch verfälscht werden. Knoten BFT-PK geht von der Grundannahme einer festen Menge von n teilnehmenden Knoten N = {k1 , k2 , ..., kn } aus. Dabei dürfen sich die einzelnen Knoten gemäß dem byzantinischen Fehlermodell verhalten. Jeder Knoten ist systemweit eindeutig über eine NodeID identifizierbar. Diese soll zur Vereinfachung aus der Menge {0, 1, ..., |N | − 1} stammen. Um korrupte Nachrichten identifizieren zu können, macht der Algorithmus Gebrauch von kryptographischen Hilfsmitteln. Nachrichten beinhalten PublicKey basierte Signaturen, sowie Hashwerte, kurz Hashes4 . Jeder Knoten muss in der Lage sein Nachrichten mit einem Public-Key-basiertem Verfahren zu signieren und derartig signierte Nachrichten zu verifizieren. 4 Es wird vorausgesetzt dass Hashwerte durch eine kollisionsresistente Hash-Funktion d gebildet werden. Es soll also unmöglich“ sein, zwei unterschiedliche Nachrichten mi und mj zu ” finden, so dass d(mi ) = d(mj ) gilt. 18 Kapitel 2. Theoretische Betrachtung der Algorithmen Als notwendige Einschränkung dürfen sich Knoten zwar beliebig“ verhalten, ” sie sollen jedoch nicht in der Lage sein Signaturen fälschen zu können5 . Im Weiteren wird eine durch Knoten ki signierte Nachricht msg mit [msg] σi und der Hash über ihr, mit d(msg) bezeichnet. Ein Knoten muss Zugriff auf ein flüchtiges Speichermedium besitzen, um darauf einen Speicher(Log) anzulegen. In diesem Log speichert dieser, wenn nötig, empfangene, beziehungsweise gesendete Nachrichten, sowie erforderliche“ Syste” minformationen. 2.3.2 Funktionsweise BFT-PK arbeitet ebenso wie Basic-Paxos mit Quoren zur eindeutigen Bestimmung von Mehrheiten im System. Dabei gilt die allgemeine Erkenntnis, dass um f byzantinisch fehlerhafte Knoten tolerieren zu können, insgesamt mehr als 3f Knoten nötig sind6 [Cas01]. BFT-PK k garantiert dabei Sicherheit und Lebendigkeit, solange sich nicht mehr j als |N 3|−1 Teilnehmer byzantinisch fehlerhaft verhalten. Der Algorithmus benötigt keinerlei synchrone Beschränkungen des Kommunikationsmodells um Sicherheit zu gewährleisten, er muss allerdings gewisse Annahmen über Synchronität treffen, um Lebendigkeit zu ermöglichen. Würde er diese Annahmen nicht treffen, könnte er dazu verwendet werden, das Einigungsproblem in einem asynchronen verteiltem System zu implementieren, was, wie erwähnt, nach [FLP85] nicht möglich ist. Die Ausfallsicherheit des Algorithmus ist, in Bezug auf eine konsistente Lösung des Einigungsproblems in Anbetracht byzantinischen Fehlverhaltens, optimal. BFT-PK gibt sich bereits mit 3f + 1 am Konsensus partizipierenden Knoten zufrieden, was gemäß Formel 2.2 das Minimum darstellt. Analog zu Basic-Paxos unterteilen sich die am Konsensus beteiligten Knoten in normale“ Teilnehmer und Anführer. Die Bestimmung eines Anführerknotens ” erfolgt hier allerdings anders. Auch ist dazu bei BFT-PK ein Mechanismus fest formuliert. Die Teilnehmer des BFT-PK bewegen sich in einer Abfolge von Konfigurationen, genannt views7 . In einer view ist genau ein Knoten der Anführer. Bei den aus Abschnitt 2.3.1 angenommenen n Teilnehmern, wäre das deterministisch derjenige, dessen NodeID der aus Formel 2.3 generierten id entspricht. id = view mod |N | (2.3) 5 Falls sich ein Knoten ki korrekt verhält und eine Nachricht msg nicht signiert hat, so darf kein anderer Knoten kj existieren, der dies anstelle von ki getan hat. 6 |N | ≥ 3f + 1 7 view ∈ N0 (2.2) 2.3. BFT-PK 19 Die views werden während der Laufzeit von BFT-PK fortlaufend nummeriert. Damit wird sichergestellt, dass im Falle byzantinischer Anführer, maximal f Anführer abfolgender views fehlerhaft sein können. Analog zu Multi-Paxos löst BFT-PK das Einigungsproblem für eine beliebige Anzahl an Einigungsinstanzen. Auch hier soll eine einzelne Instanz durch eine eindeutige Rundennummer roundN r identifiziert werden. Ein Anführer einer view propagiert einen Entscheidungswert pro Runde, er weist also jedem Vorschlag sukzessive eine roundN r zu. Anschließend wird er versuchen in der aktuellen view die einzelnen Einigungsinstanzen erfolgreich ablaufen zu lassen. Ein sich byzantinisch fehlerhaft verhaltender Anführer könnte nun unterschiedlichen Einigungswerten die gleiche roundN r zuweisen, oder er könnte damit aufhören überhaupt roundN rs zuzuweisen. Er könnte auch Lücken bei der Zuweisung von roundN rs lassen. Durch diese Probleme würde der Einigungsprogress zum Stillstand kommen. Um dem Vorzubeugen und einen fehlerhaften Anführer entmachten zu können, überwachen die restlichen normalen“ Knoten der view ” das Verhalten des Anführers. Falls nötig, lösen sie einen Wechsel hin zu einer neuen view und damit zu einem neuen Anführer aus. Prinzipiell lässt sich die in BFT-PK verwendete view mit der in Basic-Paxos verwendeten seqN r vergleichen. Beide werden aufgrund einer nicht zustandegekommenen Einigung konsistent, zu ihrem jeweils geltenden Kontext, inkrementiert mit dem Ziel eine Einigung in einem nachfolgendem Versuch“ zu erzielen. ” In der Arbeit werden die beiden Mechanismen“ durch unterschiedliche Termini ” voneinander differenziert, da beiden eine unterschiedliche Philosophie zu Grunde liegt, zum Beispiel als Kriterium bei der Anführerbestimmung. Wie bereits erwähnt, nutzt der Algorithmus Quoren. Wobei in einem byzantinischen Kontext, bei einer totalen Knotenanzahl von 3f + 1 Teilnehmern, eine beliebige Menge von wenigstens 2f + 1 Knoten ein Mehrheitsquorum bilden soll. Eine einfache Mehrheit, wie im Falle von Basic-Paxos, ist hier nicht ausreichend. Durch diese Annahme ergibt sich: • Zwei beliebige Quoren überschneiden sich in mindestens einem korrekten Teilnehmer. • Zu jeder Zeit existiert ein Quorum, bestehend aus ausschließlich korrekten Knoten. Mit diesen beiden Eigenschaften erlauben es derartige Quoren ein zuverlässiges Medium für konsistente Entscheidungen darzustellen, da im Falle einer Entscheidung eines Quorums, kein anderes Quorum eine unterschiedliche Entscheidung fällen kann. Davon macht BFT-PK bei jeder Entscheidung über einen weiteren Progress im Einigungsprozess Gebrauch. Er bildet sogenannte Nachrichten-Zertifikate: 20 Kapitel 2. Theoretische Betrachtung der Algorithmen Ein sogenanntes starkes Zertifikat“ enthält dabei eine Anzahl von 2f + 1 ” Nachrichten unterschiedlicher Knoten, also die Information einer entscheidungsfähigen Mehrheit. Jeder Schritt im Ablauf von BFT-PK wird durch ein solches Zertifikat besiegelt. 2.3.3 Ablauf k1 [PRE-PREPARE,1,0,v] [PREPARE,1,0,d(v)] k2 k3 k4 (Phase 1) (Phase 2) [COMMIT,1,0,d(v)] (Phase 3) Abbildung 2.3: Ablaufszenario von BFT-PK Abbildung 2.3 zeigt ein mögliches Szenario eines Ablaufs von BFT-PK zur Einigung innerhalb einer Runde. Innerhalb der ersten dargestellten view ist k1 der Anführerknoten und Knoten k2 ein Teilnehmer, der sich möglicherweise byzantinisch fehlerhaft verhält. Im Vergleich zu dem genannten Szenario 2.1 aus Abschnitt 2.1.3 offenbaren sich auf den ersten Blick zwei Unterschiede: • Aus zeitlicher Sicht, benötigt BFT-PK im Normalfall weniger Nachrichtenlaufzeiten um eine Einigung zu erzielen. • Auf der anderen Seite ist die Anzahl der ausgetauschten Nachrichten bei BFT-PK auch im Normalfall deutlich größer als bei Basic-Paxos. Das Protokoll für eine erfolgreiche Lösung einer Einigungsinstanz im Normalfall lässt sich in drei Phasen aufgliedern: 2.3. BFT-PK 21 1. PRE-PREPARE-Phase 2. PREPARE-Phase 3. COMMIT-Phase Die erste Phase gewährleistet im Zusammenspiel mit der Zweiten eine, selbst bei fehlerhaftem Anführer, totale Ordnung der Einigungswerte in der gleichen view. Die dritte Phase gewährleistet diese Ordnung über alle views hinweg. Im Folgenden werden die in den drei Phasen durchgeführten Aktivitäten präsentiert. Im Anschluss daran wird ein Mechanismus gezeigt durch den BFT-PK ein beliebiges Anwachsen der verwendeten Nachrichtenspeicher verhindert. Als Abschluss wird der Prozess zum Wechseln eines Anführers vorgestellt. PRE-PREPARE-Phase • Will der Anführer der aktuellen view, ohne Beschränkung der Allgemeinheit Knoten ki , einen Einigungswert proposal propagieren, ordnet er diesen zunächst einer eindeutigen Einigungsrunde roundN r zu. Im Anschluss daran schickt er allen anderen Teilnehmern eine signierte PRE-PREPARENachricht [PRE-PREPARE, view, roundNr, proposal,i] σi und fügt diese seinem Log hinzu. • Empfängt ein Knoten kj ein PRE-PREPARE: – Verwirft er dieses, falls er sich nicht in der gleichen view wie die in der Nachricht enthaltenen befindet, er die Signatur der Nachricht nicht verifizieren kann, oder sich die roundN r der Nachricht nicht in einem durch min-roundNr und max-roundNr begrenzten Wertebereich befindet. Letzte Bedingung verhindert es, dass ein fehlerhafter Anführer Rundennummern beliebig verschwenden könnte. Später wird die Festlegung dieses Bereiches näher erläutert. – Knoten kj akzeptiert ein PRE-PREPARE, wenn zusätzlich zu den obigen Bedingungen nicht bereits ein anderes PRE-PREPARE mit gleicher view und gleicher roundN r aber unterschiedlichem proposal akzeptiert wurde8 . Eine akzeptierbare Nachricht wird im Weiteren als korrekt“ bezeichnet. ” PREPARE-Phase • Hat ein Knoten kj ein PRE-PREPARE akzeptiert und ist dabei nicht der Anführer der aktuellen view, sendet er an alle restlichen Knoten eine 8 Die genannten Bedingungen um eine Nachricht zu akzeptieren gelten in gleicher Weise für alle Phasen. In der PREPARE- und der COMMIT-Phase wird ein empfangenes proposal jedoch über den Vergleich des darüber gebildeten Hashwertes unterschieden. 22 Kapitel 2. Theoretische Betrachtung der Algorithmen PREPARE-Nachricht [PREPARE, view, roundNr, d(proposal), j] σj ,wobei d(proposal) den Hashwert über Einigungswert proposal bezeichnet9 . Knoten kj fügt anschließend beide Nachrichten seinem Log hinzu. • Daraufhin wartet ein Knoten auf den Empfang von 2f passender, korrekter PREPARE-Nachrichten anderer Teilnehmer, um sich daraus ein PREPA” RED-Zertifikat“ generieren zu können. Ist im System für einen bestimmten Einigungswert proposal ein PREPARED-Zertifikat vorhanden, beweist dies durch die Eigenschaft eines starken Zertifikates, dass sich die Teilnehmer über die Ordnung des proposals in der gleichen view entschieden haben. BFT-PK garantiert somit, dass es keine zwei PREPARED-Zertifikate im System geben kann, welche über eine gleiche view und eine gleiche roundN r, aber über ein unterschiedliches proposal gebildet wurden. COMMIT-Phase • Hat sich ein Knoten kj erfolgreich ein PREPARED-Zertifikat generiert, sendet er an alle anderen Teilnehmer eine COMMIT-Nachricht [COMMIT, view, roundNr, d(proposal), j] σj und fügt daraufhin die Nachricht wieder seinem eigenen Log hinzu. • Sammelt ein Knoten kj passende, korrekte COMMIT-Nachrichten von 2f +1 unterschiedlichen Knoten, hält er ein starkes Zertifikat, das als COM” MITTED-Zertifikat“ bezeichnet wird. • Ein proposal einer bestimmten roundN r ist in einer view erfolgreich, wenn ein Knoten kj ein dazu passendes PREPARED-Zertifikat, sowie ein korrespondierendes COMMITTED-Zertifikat besitzt. Das proposal wäre dann im System ausgewählt. Garbage Collection BFT-PK verwendet einen Garbage Collection“-Mechanismus um ein beliebiges ” Anwachsen seiner Logs zu verhindern. Allerdings ist es nicht trivial, beliebige Nachrichten aus dem Speicher zu entfernen, da gesammelte Zertifikate für einen späteren Beweis der Gültigkeit eventuell noch benötigt werden könnten. Dies erfordert einen Mechanismus um Sicherungspunkte(Checkpoints) konsistent im System anzulegen. Grundsätzlich basiert das von BFT-PK verwendete Checkpointing wiederum auf dem Austausch von Nachrichten. Da es nicht performant wäre Checkpoints nach jeder erfolgreichen Runde anzulegen, versucht man dies periodisch, nach 9 Dadurch, dass nicht in allen Phasen der vollständige Einigungswert verschickt wird, ergibt sich ein Gewinn an Performanz. 2.3. BFT-PK 23 einer bestimmten Anzahl an erfolgreichen Einigungsinstanzen, zu tun. Ein systemweit konsistent angelegter Checkpoint wird als stabil bezeichnet. Will ein Knoten ki einen Checkpoint anlegen, sendet er eine CHECKPOINTNachricht [CHECKPOINT, maxRoundNr, d(state), i] σi an alle Teilnehmer, wobei maxRoundN r die letzte erfolgreiche Runde bezeichnet, die in dem Checkpoint berücksichtigt werden soll und d(state) den Hash über den eigenen Zustand. Wird BFT-PK für die Implementierung eines replizierten Dienstes verwendet, könnte man sich unter state den Zustand eines Replikats vorstellen, welcher sich aus der sequentiellen Verarbeitung der proposals bis einschließlich Einigungsrunde maxRoundN r eingestellt hat. Sammelt ein Knoten insgesamt 2f + 1 CHECKPOINT-Nachrichten unterschiedlicher Knoten, welche die gleiche maxRoundN r und den gleichen d(state) beinhalten, kann er sich ein CHECKPOINT-Zertifikat“ generieren. Durch solch ” ein Zertifikat wird ein Checkpoint stabil. Ist ein Checkpoint stabil, kann ein Knoten alle Nachrichten, die für eine Runde roundN r ≤ maxRoundN r gesendet wurden, verwerfen. Ebenso kann er alle früher“ angelegten Checkpoints verwerfen. ” Als nützlicher Nebeneffekt wird das Checkpointing außerdem eingesetzt um die angesprochenen Ober- und Untergrenzen eines nachrichtenakzeptierenden Fensters, beschränkt durch maxRoundN r und minRoundN r, zu setzen. Dabei wird die untere Grenze minRoundN r auf den Wert maxRoundN r des letzten stabilen Checkpoints gesetzt. Der obere Grenzwert maxRoundN r wird mit minRoundN r zuzüglich einer additiven Konstante k belegt. Das Verwenden dieses verschiebbaren Fensters verhindert, wie bereits angesprochen, dass ein fehlerhafter Anführer jegliche Rundennummern sinnlos aufbrauchen könnte. View Change BFT-PK garantiert während seiner Laufzeit, unter Einhaltung der in Abschnitt 2.3.1 gestellten Voraussetzungen, permanente Sicherheit. Um auch einen fortwährenden Progress im Einigungsprozess, beziehungsweise Lebendigkeit zu gewähren, ist es notwendig, einen fehlerhaften Anführer abzulösen. Dies erreicht der Algorithmus durch den Einsatz eines View Change“-Mechanismus. ” Den Kern des Mechanismus bildet ein konsequentes Observieren der Aktivitäten eines Anführer durch die restlichen, normalen“ Teilnehmer einer view. ” Vermutet ein Knoten einen sich fehlerhaft verhaltenden Anführer initiiert er ein View Change, einen Wechsel der aktuellen, hin zu einer neuen view und damit auch zu einem neuen Anführer. Eine Möglichkeit ein fehlerhaftes Verhalten zu erkennen, bietet die Überwachung von gestarteten Einigungsrunden durch einen Timer-Mechanismus“, vergleiche den Ablauf in Abbildung 2.4. ” Wird der Lauf einer gestartete Runde nicht bis zu einer bestimmten Zeitschranke t erfolgreich beendet, wird ein Fehlverhalten des Anführers gefolgert und die sogenannte View Change“-Phase eingeleitet. Ab diesem Zeitpunkt ak” 24 Kapitel 2. Theoretische Betrachtung der Algorithmen Abbildung 2.4: UML-Aktivitätsdiagramm des Timer-Mechanismus im View ” Change“-Protokoll zeptiert ein Knoten, bis auf CHECKPOINT, VIEW-CHANGE und NEW-VIEW, keine Nachrichten mehr. Knoten ki forciert anschließend den Wechsel hin zu einer anderen view newV iew. Er sendet deshalb an alle Teilnehmer eine VIEW-CHANGE-Nachricht [VIEW-CHANGE, newView, lastCheckpointRound, lastCheckpointCertificate, preparedCertificates, i] σi . Hierbei bezeichnen lastCheckpointRound die Rundennummer des letzten bekannten stabilen Checkpoints und lastCheckpoint− Certif icate dessen Korrektheitsbeweis. Die Menge preparedCertif icates beinhaltet alle durch ki ab Runde lastCheckpointRound empfangenen PREPREPAREs, für die der Knoten erfolgreich ein PREPARED-Zertifikat generieren konnte. Der Sinn dahinter ist, dass der Anführer von newV iew die in preparedCertif icates enthaltenen Einigungswerte propagieren soll. Dadurch wird eine konsistente, view-übergreifende Ordnung der Einigungswerte ermöglicht. Empfängt der Anführer, ohne Beschränkung der Allgemeinheit kj , von newV iew 2f gültige VIEW-CHANGE-Nachrichten unterschiedlicher Knoten ist der Wechsel hin zu newV iew erfolgreich verlaufen. Per NEW-VIEWNachricht, [NEW-VIEW, newView, viewChangeCertificate, newViewRounds] σj , postuliert dieser den erfolgreichen Wechsel an alle Teilnehmer. Die Menge viewChangeCertif icate bezeichnet dabei ein starkes Zertifikat, welches aus 2f empfangenen und einer selbst generierten VIEW-CHANGE-Nachricht besteht. Die Menge newV iewRounds umfasst PRE-PREPARE-Nachrichten, die nach folgendem Muster gebildet werden: 1. Der Anführer bestimmt den Wert min des letzten stabilen Checkpoints aus viewChangeCertif icate, sowie den Wert max, welcher der größten Rundennummer einer PRE-PREPARE-Nachricht in viewChangeCertif icate entspricht. 2.3. BFT-PK 25 2. Für jede Rundennummer n, mit min < n ≤ max, generiert der Anführer ein PRE-PREPARE für newV iew wie folgt: (a) Enthält viewChangeCertif icate ein VIEW-CHANGE, welches ein zu n passendes PREPARED-Zertifikat beinhaltet, startet der Anführer kj Runde n in newV iew erneut. Der Knoten bildet dafür eine für newV iew gültige PRE-PREPARE-Nachricht [PRE-PREPARE, newView, n, proposal] σj , wobei proposal der Einigungswert eines passenden PREPARED-Zertifikats der Runde n ist und der Nachricht aus viewChangeCertif icate, mit der größten view entstammt. (b) Enthält viewChangeCertif icate keine zu n passende Nachricht, startet der Anführer die Runde erneut mit einem speziellen Einigungswert N OOP 10 und generiert Nachricht [PRE-PREPARE, newView, n, NOOP]. Dieses ist notwendig, um keine Lücken in der Abfolge an Rundennummern entstehen zu lassen. Wurde ein NEW-VIEW versendet, fügt der Anführer alle Nachrichten aus newV iewRounds zu seinem Log hinzu. Ist zusätzlich min größer als die Rundennummer des letzten stabilen Checkpoints des Anführers, fügt der Anführer den Beweis für die Stabilität des Checkpoints mit Rundennummer min seinem Log bei und führt eine Garbage Collec” tion“ durch. Anschließend geht der Anführer in newV iew über und ist wieder in der Lage jegliche Nachrichtenarten zu akzeptieren. Ein normaler“ Knoten akzeptiert ein NEW-VIEW für newV iew, falls die ” Nachricht korrekt signiert wurde und die Mengen viewChangeCertif icate und newV iewRounds valide sind. Er fügt, gemäß dem Prinzip des Anführers, die neuen Nachrichten seinem Log bei und startet ein PREPARE für jede in newV iewRounds enthaltene Nachricht. Diese PREPARE-Nachrichten fügt der Knoten ebenfalls seinem Speicher zu und geht über nach newV iew. 10 Die Verarbeitung eines N OOP s durch einen Knoten führt zu keiner weiteren internen Aktion. Würde man dieses Prinzip auf einen Zustandsautomaten münzen, vollzieht der Automat als Konsequenz eines Ereignisses N OOP keinen Zustandsübergang. Kapitel 3 Entwurf und Implementierung Dieses Kapitel beschreibt den praktischen Teil der Arbeit, das Design und die Realisierung einer generischen Protokollinstanz für eine crash-stop und ein crashrecovery Variante von Multi-Paxos, sowie den BFT-PK-Algorithmus im Kontext der in Abschnitt 1.3 vorgestellten Gruppenkommunikationsschicht von AspectIX. In Abschnitt 3.1 werden die Anforderungen an eine solche Instanz formuliert. Eine Grundstruktur der Realisierung wird in Abschnitt 3.2 präsentiert. Ein Framework der generischen Protokollinstanz wird in Abschnitt 3.3 illustriert. Spezielle Anpassungen, die für eine dynamische Rekonfiguration der Protokollinstanz notwendig werden, sind in Abschnitt 3.4 angeführt. Abschnitte 3.5 und 3.6 beschreiben schließlich, wie die präsentierte Grundstruktur auf die beiden Algorithmen angewendet wurde und wie deren konkrete Implementierungen aussehen. Die Implementierung wurde dabei komplett in der Sprache Java vorgenommen. Dies geschah zum einen, da die Arbeitsumgebung“ der Protokollinstanz, ” die Gruppenkommunikationsschicht ihrerseits bereits komplett durch diese Sprache realisiert wurde. Zum Anderen, aus Gründen der Plattformunabhängigkeit, die durch eine Kodierung in Java erreicht werden kann. Die Implementierung der Protokollinstanz verteilt sich auf die Pakete org.aspectix.group und org.aspectix.group.consensus. Sämtliche Bedingungen, die in Kapitel 2 theoretisch an ein korrektes Funktionieren der Algorithmen formuliert wurden, sind in der Realisierung beachtet und umgesetzt. 3.1 Anforderungen Als praktischer Teil der Arbeit sollte eine generische Implementierung der in Kapitel 2 vorgestellten Varianten des Paxos-Algorithmus, Multi-Paxos und BFTPK entworfen und implementiert werden. Diese generische Protokollinstanz sollte zudem einfach erweiterbar für weitere Varianten von Paxos konfigurierbar sein und ihre Generalität sollte dabei mit möglichst wenig Verlust an Effizienz erreicht 26 3.1. Anforderungen 27 werden. Zusätzlich soll die Implementierung in der Lage sein, zur Laufzeit den konkret eingesetzten Einigungsalgorithmus dynamisch bestimmen zu können. Eine Schnittstelle soll von der eingesetzten Variante abstrahieren und damit eine dynamische Rekonfiguration, also ein dynamisches Wechseln zwischen den implementierten Varianten ermöglichen. Die Protokollinstanz soll sich im Bezug auf Logik und Funktionalität in die in Abschnitt 1.3 vorgestellte Gruppenkommunikationsschicht von AspectIX einbetten und diese in ihrer Funktionalität konsistent erweitern und unterstützen. Wie bereits erläutert besteht der Sinn der Gruppenkommunikationsschicht darin, einen Mechanismus zum total geordneten Austausch von Nachrichten zwischen den Teilnehmern der Gruppe1 zu bieten. Primäre Aufgabe der generischen Protokollinstanz ist es dabei, als Einigungsmodul“ in der Gruppenkommunika” tionsschicht, eine totale Ordnung über den ausgetauschten Nachrichten zu etablieren. Der Zugang zu der Einigungskomponente soll dabei durch eine einfach gehaltene Schnittstelle, siehe Abbildung 3.1, ermöglicht werden. Abbildung 3.1: UML-Klassendiagramm der Schnittstelle zur Einigungskomponente Als Schnittstelle zu der Gruppenkommunikationskomponente soll die Protokollinstanz mit propose() eine Methode zum konsistenten propagieren eines Entscheidungswertes proposal zur Verfügung stellen, sowie eine Methode getValue(), welche die Möglichkeit offeriert, die nächste“2 Entscheidung ab” zufragen. Dabei muss getValue() synchron“ blockierend implementiert sein. ” Das heißt, falls die nächste“ Entscheidung der Einigungskomponente noch nicht ” verfügbar ist, wird in getValue() auf diese blockierend gewartet. Eine weitere Anwendung betrifft das Management der Gruppenteilnehmer, genannt Knoten. Ein Knoten soll der Gruppe beitreten, beziehungsweise ein beigetretener Teilnehmer soll von der Gruppe austreten können. Auch dieses Management soll konsistent über die Einigungskomponente abgewickelt werden. Die Teilnehmermenge soll also dynamisch zur Laufzeit verwaltbar sein. Die Protokoll1 Eine Gruppe(Group) bezeichnet die Menge der Teilnehmer an der Gruppenkommunikation. Nicht zu einer Gruppe gehören allerdings mögliche externe Sender, beziehungsweise Empfänger [Löh04]. 2 Im Sinne total geordneter Nachrichten. 28 Kapitel 3. Entwurf und Implementierung instanz muss folglich durchwegs konsistent in der Lage sein auf einer dynamischen Gruppe an Knoten zu operieren. 3.2 Grundstruktur Zunächst soll eine logische Einordnung der Arbeit im Kontext der Gruppenkommunikationsarchitektur erfolgen. Eine grobe Architektur des Gesamtsystems der Abbildung 3.2: Die Hauptkomponenten der Gruppenkommunikationsschicht Gruppenkommunikationsschicht ist in Abbildung 3.2 skizziert. Bei deren Design wurde auf Modularität großen Wert gelegt. Die oberste Schicht bildet die Gruppenkommunikationskomponente. Ihr obliegt die Logik über die Funktionalität und das Management der Gruppe. Sie bildet gleichzeitig die Schnittstelle für aufsetzende praktische Anwendungen. Zur Lösung ihrer Konsistenzfragen“ stützt ” sie sich auf die Einigungskomponente, welche durch die in der Arbeit präsentierte generische Protokollinstanz gebildet wird. Beide Komponenten nutzen zum Austausch von Nachrichten die unterste Schicht, das Kommunikationssystem, welches von einem realen, physikalischen Netzwerk abstrahiert. Im Folgenden werden die Komponenten des Gruppenkommunikationssystems, welche direkt durch die generische Protokollinstanz verwendet werden, kurz präsentiert. Für eine genaue Beschreibung ihrer Funktionalität sei auf [Löh04] verwiesen. 3.2.1 Gruppenkommunikationssystem Die Klasse Group implementiert die oben genannte Gruppenkommunikationskomponente. Sie bildet die Schnittstelle für aufsetzende Anwendungen der Gruppenkommunikationsschicht und stellt Methoden zum Senden und Empfangen von Gruppennachrichten“ zur Verfügung. Gruppennachrichten haben die Eigenschaft ” allen Teilnehmern einer Gruppe, in gleicher Reihenfolge, zugestellt zu werden. Da die Gruppenkommunikationsschicht ein offenes“ Gruppenkonzept ver” folgt, bietet Group zudem Methoden um der Gruppe bei-, beziehungsweise auszutreten. 3.2. Grundstruktur 29 Als letztes offeriert Group eine Schnittstelle, um ein dynamisches Rekonfigurieren der gesamten Gruppenkommunikationsschicht zu ermöglichen. 3.2.2 Kommunikationssystem Das Kommunikationssystem ist durch die Klasse ComSys implementiert. ComSys ist in der Lage, einen Kommunikationsdienst basierend auf unidirektionalen TCP-Verbindungen anzubieten und unterstützt dabei eine netzwerkunabhängige Adressierung von Knoten. Dadurch und durch die Fähigkeit von ComSys abgebrochene Verbindungen wiederherzustellen, wird ein Wiederanlaufen von Knoten, gemäß crash-recovery, möglich. Ein Knoten kann somit transparent, für einen Anwender von ComSys, mit einer anderen IP-Adresse oder einem anderen TCP-Port wieder anlaufen. Basierend auf ComSys steht die Klasse ComID und das Interface Listener zur Verfügung. Auf der einen Seite ermöglicht ComID einer Anwendung das Senden von Nachrichten eines bestimmten Typs. Auf der anderen Seite ermöglicht es ComSys Objekten, die Listener implementieren, sich als Empfänger bestimmter Nachrichten zu registrieren. Jedes Objekt der generischen Protokollinstanz wird mit einer Referenz auf eine Instanz des Kommunikationssystems initialisiert. Die einzelnen Komponenten einer Implementierung der Protokollinstanz teilen sich somit ein Kommunikati” onsobjekt“. 3.2.3 Nachrichten Nachrichten werden durch die Klasse Message repräsentiert und sind mit einer bestimmten Typkennung versehen. Für die Übertragung einer Nachricht, wird diese mittels Java Serialization“ in eine passende Form konvertiert. ” 3.2.4 Einigungswerte Einigungswerte, die per propose() an die Einigungskomponente übergeben werden, sind durch die Klasse Proposal dargestellt, siehe Abbildung 3.3. Dabei wurde die ursprüngliche Version aus [Löh04] erweitert, um den zusätzlichen Anforderungen der Protokollinstanz gerecht zu werden. Das Attribut operation kann nun zusätzlich mit dem Wert PROPOSE_RECONFIG belegt werden, um einen Wechsel des aktuellen Einigungsalgorithmus zu forcieren. Entsprechend bewirkt ein REFUSE_RECONFIG das Gegenteil. Wie später noch erläutert wird, kann es bei Multi-Paxos und BFT-PK vorkommen, dass Lücken an Einigungsrunden geschlossen werden müssen. Dazu kann ein Proposal mit einem NOOP als Wert von operation verwendet werden. Die Funktionalität eines NOOP entspricht dabei genau der in Abschnitt 2.3.3 beschriebenen Bedeutung. 30 Kapitel 3. Entwurf und Implementierung Abbildung 3.3: UML-Diagramm der Klassen Proposal und ProposalReply Einigungswerte, die per getValue() an Group zurückgegeben werden, sind durch die Klasse ProposalReply modelliert. Dabei bildet ProposalReply einen Wrapper“ um das eigentlich zurückzugebende proposal der Klasse Proposal. ” Dies ist nötig, da zuzüglich des Einigungswertes der aktuell zurückgelieferten Runde, zum Beispiel im Falle eines PROPOSE_JOIN, notwendige Informationen über den Status der Einigungskomponente an Group mitzuteilen sind. Für PROPOSE_JOIN wären das die Rundennummer joinround, ab der ein Knoten dem Einigungsprozess beitritt, oder die aktuelle view joinview, falls als Einigungsalgorithmus der BFT-PK zum Einsatz kommt. 3.2.5 Knoten Abbildung 3.4: UML-Diagramm der Klasse NodeID Um ein Arbeiten von BFT-PK und Multi-Paxos zu ermöglichen, ist es, Ka- 3.3. Generische Protokollinstanz als Einigungskomponente 31 pitel 2 folgend, Grundvoraussetzung, dass die Knoten systemweit eindeutig identifizierbar sind. Diese Funktionalität wird einerseits durch die Klasse NodeID, andererseits durch eine Logik des Gruppenmanagements innerhalb der Klasse Group ermöglicht. Die Klasse NodeID repräsentiert dabei die Abstraktion eines physischen“ Knotens. Dabei wurde die ursprüngliche Klasse aus [Löh04], um Me” thoden erweitert, um in dynamischen Datenstrukturen der Java API“ eingesetzt ” zu werden, siehe Abbildung 3.4. 3.3 Generische Protokollinstanz als Einigungskomponente Abbildung 3.5: Grundstruktur eines Frameworks der generischen Protokollinstanz Die Hauptaufgabe der generischen Protokollinstanz ist es, einen Mechanismus für eine totale Ordnung aller ausgetauschten Gruppennachrichten zu ermöglichen. Um die Realisierung einer derartigen Funktionalität für unterschiedliche Einigungsprotokolle zu erleichtern, wurde, inspiriert durch [BDF+01], eine Grundstruktur eines Frameworks“ zur Implementierung der Einigungsalgorithmen ent” worfen, siehe Abbildung 3.5. Die in Abbildung 3.2 dargestellte Einigungskomponente wird dabei, in dem Framework, in drei logische Teile zerlegt und erstreckt sich in der Abbildung auf die Schichten zwei bis vier. • Das Grundprinzip bildet die Abstraktion des rundenbasierten“ Konsensus” ansatzes, wie er in Kapitel 2 vorgestellt wurde. Multi-Paxos und BFT-PK ist gemein, dass sie um einen fortwährenden Einigungsprogress, für eine Vielzahl an Entscheidungswerten, zu erzielen, sich auf einzelne Konsensusinstanzen zur Lösung je einer Entscheidungsrunde stützen. Die zweite Schicht kapselt dabei die Logik, je eine Konsensusinstanz für eine Runde zu ermöglichen. • Um diese einzelnen Instanzen zu verwalten ist die dritte Schicht zuständig. Diese offeriert eine Art Fabrik“, um einzelne Konsensusinstanzen konsistent ” zu kreieren. 32 Kapitel 3. Entwurf und Implementierung • Die vierte Schicht garantiert, nach oben hin, eine totale Ordnung der Gruppennachrichten(TO-Nachrichten). Sie kapselt somit die Logik um Nachrichten allen Gruppenteilnehmern in derselben Reihenfolge zukommen zu lassen. Dabei muss sie garantieren, dass ein per propose() übergebenes Proposal irgendwann sicher als Entscheidungswert einer Runde erfolgreich ist, zumindest solange der Initiator des propose() nicht ausfällt. Daraus resultiert, dass, falls ein Proposal in einer Runde nicht erfolgreich propagiert werden kann, es in einer der nachfolgenden Runden, also durch eine andere Konsensusinstanz, erfolgreich sein muss. Um performant zu arbeiten, sollte versucht werden, möglichst viele Runden parallel zueinander ablaufen zu lassen. Realisierung des AgreementInterface Abbildung 3.6: Grundstruktur der Implementierung des AgreementInterface Im Folgenden wird auf die Realisierung der vierten Schicht und damit der offerierten Leistung des AgreementInterface allgemein eingegangen. Dabei werden die Funktionalitäten der Implementierung kurz dargestellt. Konkret wurde das AgreementInterface für die implementierten Paxos-Varianten durch die Klassen GenericPaxosAgreement, MultiPaxosAgreement und BFT_PK_Agreement realisiert. Dabei wird die vierte Schicht des Frameworks für 3.4. Rekonfiguration zur Laufzeit 33 die beiden Varianten des Multi-Paxos durch MultiPaxosAgreement und für BFTPK durch BFT_PK_Agreement implementiert. Gemeinsames Verhalten und gemeinsame Datenstrukturen der beiden Klassen sind so weit wie möglich in deren abstrakter Oberklasse GenericPaxosAgreement zusammengefasst. Die beiden Klassen implementieren dabei nicht nur die ursprünglich geforderten Methoden propose() und getValue(). Sie enthalten mit zwei init()und einer destroy() Methode auch die Möglichkeit, die jeweilige Variante sau” ber“ zu initialisieren und zu beenden. Dies ist für einen dynamischen Austausch der Einigungskomponente zur Laufzeit zwingend notwendig, wie in Abschnitt 3.4 näher erläutert wird. Damit ein Austausch einer Paxos-Variante durch eine andere sauber geschehen kann, verfügen die Klassen über einen Mechanismus, den Einigungsprozess ab einer bestimmten Runde zu stoppen. Ebenfalls ist für einen Austausch des aktuellen Objektes einer laufenden Klasse die Methode getUndeliveredProposals() nötig. Diese ermöglicht es, dass Einigungswerte, die noch nicht im System erfolgreich propagiert werden konnten, in das nachfolgende Einigungsobjekt übernommen werden können. Somit wird ein Verlust an Einigungswerten im Zuge des Austauschvorgangs verhindert. Auf dem Weg von einem Vorschlag Proposal zu einer Einordnung in eine Runde, im Sinne einer totalen Ordnung, durchläuft dieser folgende interne Datenstrukturen: • Initial per propose() übergebene Proposals werden in receivedProposals aufgenommen. • Wird ein Proposal zur Bearbeitung freigegeben“, wird es nach undeli” veredProposals verschoben. • Sollte eine Entscheidung eines Proposals schließlich für die nächste erwartete Runde, im Sinne einer totalen Ordnung, erfolgreich sein, wird dieses in deliveredProposals platziert. • Schließlich werden in awaitingToBeDeliveredProposals alle Proposals gepuffert, die zwar erfolgreich für eine Runde entschieden wurden, jedoch noch nicht gemäß der totalen Ordnung zugestellt werden können. 3.4 Rekonfiguration zur Laufzeit Die realisierte Protokollinstanz zur totalen Ordnung von Gruppennachrichten unterstützt eine Rekonfiguration ihrer Funktionalität zur Laufzeit. Folgende Arten an dynamischen Änderungsaktionen werden aktuell unterstützt: • Knoten können dem Einigungsprozess zur Laufzeit beitreten und sich von diesem wieder entfernen. 34 Kapitel 3. Entwurf und Implementierung • Ein dynamischer Austausch des konkret eingesetzten Einigungsalgorithmus ist möglich. Vorgehensweise Abbildung 3.7: UML-Diagramm der Klasse GroupPolicy Ein dynamischer Austausch des Einigungsalgorithmus bedeutet dabei nicht nur das reine Wechseln des Algorithmus. Der Einigungsalgorithmus zu dem hin gewechselt wird, setzt seine Arbeit ab der Einigungsrunde fort, in der der alte Einigungsalgorithmus aufgehört hat. Die dynamische Rekonfiguration setzt in der Klasse Group an. Sie ist dafür verantwortlich eine Instanz eines Einigungsalgorithmus zu starten. Welchen konkreten Einigungsalgorithmus Group instanziiert, wird mithilfe der Klasse GroupPolicy, siehe Abbildung 3.7, festgelegt. Folgende Attribute werden für eine Konfiguration zur Verfügung gestellt: • In consensusClass wird der Klassenname des zu startenden Einigungsalgorithmus hinterlegt. • Das Attribut maxParallelRounds legt fest, wie viele Runden innerhalb eines Einigungsalgorithmus parallel zueinander ausgeführt werden dürfen. Weshalb eine derartige Beschränkung nötig ist, wird im Anschluss diskutiert. • Durch recoveryMode wird es erlaubt, mittels einer Belegung mit RECOVERY_NONE ein crash-stop, oder durch eine Belegung mit RECOVERY_STABLE_STORAGE ein crash-recovery Modell eines Einigungsalgorithmus zu verwenden. Aktuell wird diese Auswahl nur für die Implementierung von Multi-Paxos unterstützt. Eine Rekonfiguration stellt einen erheblichen Eingriff in ein laufendes System dar. Um die Rekonfiguration konsistent für die ganze Gruppe ablaufen zu lassen, wird jede Form eines Rekonfigurationswunsches als Proposal verpackt“ und der ” 3.4. Rekonfiguration zur Laufzeit 35 Einigungskomponente per propose() übergeben. Die Einigungskomponente entscheidet anschließend wann, also in welcher exakten Runde, die Rekonfiguration erfolgen kann. Wie bereits erwähnt, ist es für die Performanz eines Konsensusalgorithmus wünschenswert, dass dieser möglichst viele Einigungen parallel fällen kann. Für die generische Protokollinstanz heißt das, sie sollte in der Lage sein, möglichst viele Runden zeitgleich“ zueinander ablaufen zu lassen. Will man nun allerdings ” eine Rekonfiguration auf der Grundlage des Einigungsprotokolls ablaufen lassen, ist eine beliebige Parallelität der Runden nicht möglich. Würde man dies erlauben, könnte es passieren, dass eine Aktion zur Rekonfiguration, beispielsweise eine Änderung der Menge an Gruppenteilnehmern, für Runde n vorgeschlagen werden würde, während parallel dazu Runde n + 1 gestartet wird. Ein Konsistenzproblem würde dann vorliegen, wenn Runde n + 1 vor Runde n entschieden wird, da Runde n + 1 auf einem Systemmodell entschieden worden wäre, welches aufgrund der Entscheidung in Runde n nicht gültig ist. Um in dem Beispiel zu bleiben, würde Runde n + 1 von einer falschen Anzahl an Teilnehmerknoten ausgehen, was für eine Entscheidungsfällung, auf der Basis einer Mehrheit, fatal wäre. Die Lösung des Problems erreicht man, durch eine Beschränkung der Anzahl an parallelen Runden auf einen fixen Wert maxParallelRounds. Falls nun eine Aktion zur Rekonfiguration, wie oben beschrieben, in Runde n beschlossen wird und maxParallelRounds Runden parallel ausgeführt werden dürfen, darf die Rekonfiguration erst für Runden größer gleich n + maxP arallelRounds ausgeführt werden. Für die Implementierung bedeutet das, dass Runde n + maxP arallelRounds erst dann gestartet werden darf, falls alle vorherigen Runden kleiner gleich n entschieden wurden. Eine Aktion zur Rekonfiguration für Runde n soll somit, aus Gründen der Konsistenz, von der Einigungskomponente an Group per getValue() mitgeteilt werden, wenn alle Runden bis n + maxP arallelRounds erfolgreich entschieden wurden. Um nicht in Gefahr zu kommen, dass aufgrund eines Mangels an Entscheidungswerten eine Rekonfigurationsaktion nicht nach Außen“ kommuniziert ” werden kann, fügt die Einigungskomponente autonom eine bestimmte Anzahl an NOOPs, als Vorschlagswerte zur Auffüllung“ der fehlenden Runden, hinzu. ” Bei der Vorgehensweise zur Behandlung einer Rekonfiguration bezüglich der Teilnehmermenge, ist zwischen der Implementierung von MultiPaxosAgreement und BFT_PK_Agreement zu differenzieren. Während die Implementierung von MultiPaxosAgreement eine interne Unterstützung zur Adaption einer sich ändernden Teilnehmermenge zur Laufzeit bietet, ist es bei BFT_PK_Agreement erforderlich, dass Group konsistent ein jeweils auf einer festen Knotenmenge operierendes Objekt der Klasse dynamisch instanziiert. 36 Kapitel 3. Entwurf und Implementierung 3.5 Multi-Paxos Wie schon in Abschnitt 3.3 angedeutet, wird in [BDF+01] eine Möglichkeit dargestellt, den in Abschnitt 2.2 vorgestellten Multi-Paxos Algorithmus in logische Module zu zerlegen. Durch diese Dekonstruktion“ des Algorithmus wird es mög” lich ein Framework für die Implementierung weiterer Varianten zu erhalten. Dabei werden im Bezug auf die Logik von Multi-Paxos zwei wesentliche Abstraktionen vorgenommen: • Es wird ein rundenbasierter Konsensus, wie in Abschnitt 3.3 angedeutet, eingeführt. Dieser setzt seinerseits, auf der Abstraktion eines rundenba” sierten Registers“ auf. • Eine schwache“ Anführerbestimmung wird konstruiert. ” Abbildung 3.8: UML-Klassendiagramm des Frameworks von Multi-Paxos Das entworfene Framework ist in Abbildung 3.8 dargestellt. Die Funktionalitäten der einzelnen Komponenten werden im Bezug zu der Schichtenarchitektur aus Abbildung 3.5 im Folgenden kurz skizziert: • AgreementInterface bildet die einzige Schnittstelle zu Group. • GenericPaxosAgreement implementiert gemeinsam mit MultiPaxosAgreement die Logik eine totale Ordnung der Einigungswerte zu etablieren, erfüllt somit die primäre Anforderung von Seiten der Group. Dadurch wird die vierte Schicht realisiert. 3.5. Multi-Paxos 37 • RoundBasedConsensusInterface kapselt die Logik eine Einigung einer einzelnen Runde zu ermöglichen und macht dabei Gebrauch von RegisterInterface. Zusammen realisieren sie die zweite Schicht. • RegisterInterface ermöglicht es einen Entscheidungswert pro Runde zu fixieren und zu speichern. • RegisterDisposerInterface dient der Verwaltung der konkreten Instanzen einer das RegisterInterface implementierenden Klasse und realisiert damit die dritte Schicht. • FailureDetectorInterface liefert den mit hoher Wahrscheinlichkeit aktuellen eindeutigen Anführer des Systems. Durch die Wahl die Implementierung von Multi-Paxos an dieses Framework anzulehnen ergeben sich folgende Vorteile: • Logisch zusammengehörende Einheiten des Algorithmus können separiert in einzelnen Klassen zusammengefasst werden. • Durch logisch separierte Klassen vereinfacht sich der theoretische Nachweis über die Korrektheit der Implementierung und ihre Wartung. • Durch Substitution einzelner logischer Module kann man einfach“ neue ” Varianten des Algorithmus kreieren. Um den letzten Punkt zu belegen, ist in der Arbeit neben dem nach dem crash-stop Modell arbeitenden Multi-Paxos, eine crash-recovery Variante implementiert. Diese unterstützt, unter der Zuhilfenahme eines persistenten Speichermediums, ein konsistentes Wiederanlaufen eines ausgefallenen Knotens. In [BDF+01] werden insgesamt vier weitere Varianten des Multi-Paxos präsentiert, die das Framework in ihrer Implementierung unterstützt. Im Weiteren wird die Realisierung des Multi-Paxos Frameworks für eine crash-stop und eine crash-recovery Variante beschrieben. 3.5.1 Realisierung des RegisterInterface Das RegisterInterface ist als Abstraktion eines gewöhnlichen“ Registers, im ” Kontext der Funktionalität von Basic-Paxos, vergleiche Abschnitt 2.1, zu verstehen. Das Interface wurde durch die in Abbildung 3.9 dargestellten beiden Klassen WaitFreeRoundBasedRegister und WaitFreeRoundBasedRegisterCrashRecovery implementiert. WaitFreeRoundBasedRegister dient dabei der Realisierung der crash-stop und WaitFreeRoundBasedRegisterCrashRecovery für die wiederanlauffähige Multi-Paxos Variante. Beide Varianten sind von der Logik und dem Aufbau nahezu gleich. Im Folgenden wird WaitFreeRoundBasedRegister 38 Kapitel 3. Entwurf und Implementierung Abbildung 3.9: UML-Klassendiagramm der Implementierung des RegisterInterface beschrieben, auf die erweiterte Funktionalität von WaitFreeRoundBasedRegisterCrashRecovery wird im Anschluss kurz eingegangen. Ein Objekt der Klasse WaitFreeRoundBasedRegister wird im Weiteren kurz als Register“ bezeichnet. Ein solches Register dient als Speicherort eines Wer” tes value der Klasse Proposal und offeriert als Schnittstelle zwei Operationen, um einen lesenden und einen schreibenden Zugriff zu erlauben: • RegisterValue read(int seqNr) • RegisterValue write(int seqNr, Proposal proposal) Die Methode read() abstrahiert dabei die Logik von der ersten und write() von der zweiten Phase des Basic-Paxos. Analog zu Basic-Paxos werden die Leseund Schreibe-Methoden des RegisterInterface mit einer Sequenznummer seqNr aufgerufen. Dabei können die Methoden erfolgreich verlaufen oder fehlschlagen. Zu beachten ist hier, dass die Methode write() nicht atomar ist, das heißt, auch im Falle eines Fehlschlagens von write() könnte ein read() value lesen. Dies ist notwendig um der Funktionalität von Basic-Paxos, im Falle eines Anführerwechsels, zu entsprechen. Ein Register sollte dabei mit einem speziellen initialen Wert null von value versehen sein. Sowohl read(), als auch write(), sollen bei Aufruf einen Rückgabewert liefern. Dieser Wert wird durch die Klasse RegisterValue repräsentiert. Sie enthält 3.5. Multi-Paxos 39 ein boolesches Attribut commit, dass angibt ob eine Operation erfolgreich(true) war und ein Attribut value, das dem Proposal-Wert der zuletzt in das Register geschrieben wurde entspricht. Was unter einer erfolgreichen Operation in diesem Kontext zu verstehen ist, wird im Folgenden näher erläutert. Um den Sicherheitsanforderungen von Basic-Paxos gerecht zu werden, genügen read() und write() folgenden Anforderungen: • Falls ein read(seqNr) fehlschlägt, wurde auf das Register ein read(seqNr’) oder ein write(seqNr’,proposal*), mit seqN r0 ≥ seqN r angewendet. Der Wert proposal∗ bezeichnet dabei einen beliebigen Wert eines Proposals. • Falls ein write(seqNr, proposal*) fehlschlägt, wurde auf das Register ein read(seqNr’) oder ein write(seqNr’, proposal*), mit seqN r0 > seqN r angewendet. • Ist ein read(seqNr) oder ein write(seqNr, proposal*) erfolgreich, kann kein read(seqNr’), beziehungsweise kein write(seqNr’, proposal*), mit seqN r0 ≤ seqN r erfolgreich sein. – Falls ein erfolgreiches read(seqNr) ein RegisterValue.value 6= null liefert, wurde auf das Register vorher ein write(seqNr’, proposal) mit proposal 6= null und seqN r0 < seqN r angewendet. – Falls ein write(seqNr, proposal) erfolgreich ist und kein weiteres write(seqNr’, proposal’) mit einem seqN r0 ≥ seqN r und einem proposal0 6= proposal erfolgt, liefert ein nachfolgendes read(seqNr’’) mit seqN r00 > seqN r ein RegisterValue.value mit dem Wert proposal. Ein Register operiert auf einer festen Knotenmenge nodes, da dies die Voraussetzung für eine eindeutige Bildung eines Quorums im Sinne von Basic-Paxos ist. Einzelne Register werden durch das Attribut roundNr unterschieden, die Methode getRoundNr() erlaubt dessen Zugriff. Die Register müssen zur Erbringung ihrer Funktionalität Nachrichten, repräsentiert durch die Klasse RegisterMessage, miteinander austauschen. Dazu wird zum Senden von Messages ComID verwendet. Nachrichten können einem Register über die Methode handleMsg() übergeben werden. Die Nachrichtenbehandlung innerhalb eines Registers ist in dem Aktivitätsdiagramm der Abbildung 3.10 illustriert. Das Attribut read bezeichnet dabei die größte aus einem read() stammende seqNr und write die größte entstammende Sequenznummer infolge eines write(). Die Arbeitsweise der beiden Methoden ist im Zusammenhang mit dem Nachrichtenaustausch zusammenfassend in Abbildung 3.11 skizziert. Anzumerken ist, 40 Kapitel 3. Entwurf und Implementierung Abbildung 3.10: UML-Aktivitätsdiagramm der Nachrichtenbehandlung von WaitFreeRoundBasedRegister dass das Warten auf ein Quorum an Nachrichten innerhalb der Methoden nicht aktiv erfolgt, sondern über einen Synchronisationsmechanismus gesteuert wird. Neben der vorgestellten Funktionalität verfügt die Klasse WaitFreeRoundBasedRegisterCrashRecovery über die Methoden store() und recover(), um ein Wiederanlaufen eines Registers zu unterstützen. Um dies zu ermöglichen werden die Attribute read, write und value persistent gespeichert und können somit bei einer Reinstanziierung eines WaitFreeRoundBasedRegisterCrashRecoveryObjekts wiederhergestellt werden. 3.5.2 Realisierung des RoundBasedConsensusInterface Wie bereits angedeutet, kapselt RoundBasedConsensusInterface mit der Hilfe von RegisterInterface die Logik der zweiten Schicht der Architektur aus Abbildung 3.5. Analog zu der Realisierung von RegisterInterface sind für die beiden Varianten von Multi-Paxos, einerseits Klasse WaitFreeRoundBasedConsensus und andererseits WaitFreeRoundBasedConsensusCrashRecovery implementiert. Entsprechend arbeitet WaitFreeRoundBasedConsensus auf Objekten der Klasse WaitFreeRoundBasedRegister und WaitFreeRoundBasedConsensusCrashRecovery auf denen von WaitFreeRoundBasedConsensusCrashRecovery. Bis auf das Basieren auf unterschiedlichen Registern, verhalten sich die beiden Klassen identisch, so dass exemplarisch nur die Klasse WaitFreeRoundBasedConsensus beschrieben wird. Ein Objekt dieser Klasse wird im Folgenden kurz mit Konsensusinstanz bezeichnet. 3.5. Multi-Paxos 41 Abbildung 3.11: UML-Aktivitätsdiagramm des Read-/Write-Mechanismus von WaitFreeRoundBasedRegister Eine Konsensusinstanz soll genau eine Entscheidungsrunde lösen, entsprechend wird diese für eine bestimmte roundNr instanziiert. Um Runde roundNr entscheiden zu können, braucht sie ein passendes Register register. Dieses wird ihr als Referenz durch ein Objekt registerDisposer der Klasse WaitFreeRoundBasedRegisterDisposer geliefert. Dessen genaue Funktionsweise wird in Abschnitt 3.5.3 beschrieben. Um einen Einigungsprozess für eine bestimmte Runde anzustoßen, wird die Methode RegisterValue propose(int seqNr, Proposal initProposal) offeriert. Die Sequenznummer seqNr entspricht dabei der in Abschnitt 2.1 genannten Sequenznummer von Basic-Paxos und initProposal dem zu propagierenden Ei- Abbildung 3.12: UML-Klassendiagramm der Implementierung des RoundBasedConsensusInterface 42 Kapitel 3. Entwurf und Implementierung nigungswert. In Abbildung 3.13 wird die Arbeitsweise von propose() illustriert. Vergleicht man die Arbeitsweise von propose() mit dem Ablauf des Basic-Paxos Abbildung 3.13: UML-Aktivitätsdiagramm der Methode propose() von WaitFreeRoundBasedConsensus aus Abschnitt 2.1.3, wird sich ein Anführer zuerst per register.read() informieren ob es bereits Vorschlagswerte im System für Runde roundNr gibt, um anschließend zu versuchen, einen konsistenten Entscheidungswert über den Aufruf eines register.write() zu propagieren. Solange es im System eine Mehrheit an funktionierenden Knoten gibt, erreicht man dadurch einen wartefreien Mechanismus zur Einigung einer Runde. 3.5.3 Realisierung des RegisterDisposerInterface Die beiden primären Aufgaben einer Realisierung von RegisterDisposerInterface sind es zum einen, eine konsistente Verwaltung der Knotenmenge pro Runde zu ermöglichen. Und zum anderen, eine Fabrik zur Instanziierung von Registern anzubieten. Die Schnittstelle wurde für die beiden Varianten des Multi-Paxos durch die Klassen WaitFreeRoundBasedRegisterDisposer und WaitFreeRoundBasedRegisterCrashRecoveryDisposer implementiert. Bis auf die Tatsache, dass die crash-recovery Version WaitFreeRoundBasedRegisterCrashRecovery-Objekte und die andere Version Objekte der Klasse WaitFreeRoundBasedRegister verwaltet, besteht bei ihnen kein großer Unterschied. Im Weiteren wird daher zusammenfassend einfach von einem RegisterDisposer gesprochen. 3.5. Multi-Paxos 43 Abbildung 3.14: UML-Klassendiagramm der Implementierung des RegisterDisposerInterface Da die implementierte generische Protokollinstanz auf einer variablen Knotenmenge operieren muss, jedoch ein Register einer bestimmten Runde auf einer festen Menge, beinhaltet ein RegisterDisposer eine Logik um je nach Rundennummer entscheiden zu können, welche Knotenmenge auf ein zu instanziierendes Register anzuwenden ist. Ein RegisterDisposer ist somit in der Lage, durch die Methode getNodes(), für eine bestimmte Rundennummer die aktuell gültige Knotenmenge im System zu liefern. Über getNrNodes() ist eine Ausgabe der an einer bestimmten Runde beteiligten Anzahl an Knoten möglich. Um dem RegisterDisposer von Änderungen der Knotenmenge ab einer bestimmten Runde modificationRoundNr zu unterrichten, stehen die Methoden addMember() und removeMember(), jeweils um einen Knoten konsistent hinzuzufügen, oder zu entfernen, zur Verfügung. Ein RegisterDisposer ist für die Verwaltung von jeglichen Registern zuständig. Er kapselt nicht nur die Logik um Register zu instanziieren, sondern bildet auch den zentralen Empfangspunkt für deren Nachrichten. Dazu registriert er sich bei ComSys als Listener für Nachrichten vom Typ RegisterMessage. Dies ist daher notwendig, da falls ein Register für eine Runde, für die eine Nachricht zugestellt werden soll, noch nicht existiert, es zwingend dynamisch instanziiert werden muss. Über die Methode getRegister() kann eine Referenz auf ein Register einer bestimmten Runde zurückgegeben werden. Auch ein Aufruf von getRegister() veranlasst ein Instanziieren eines Registers, falls dieses noch nicht, für die angeforderte Runde, existiert. Über die Methode existsRegister() ist es möglich, sich von der Existenz eines Registers einer bestimmten Runde zu überzeugen. 44 Kapitel 3. Entwurf und Implementierung Die einzelnen Register und Teilnehmermengen werden in den dynamischen Datenstrukturen nodesPool und registerPool verwaltet. Dabei ist es ausreichend in nodesPool eine Historie über die letzten NR_OF_MAX_PARALLEL_ROUNDS Aktionen zur Änderung der Teilnehmermenge aufzubewahren. 3.5.4 Realisierung des FailureDetectorInterface Abbildung 3.15: UML-Klassendiagramm der Implementierung des FailureDetectorInterface Die Hauptaufgabe einer Realisierung des FailureDetectorInterface ist es eine Anführerbestimmung zu ermöglichen, wie sie in Abschnitt 2.1.2 gefordert wurde. Die genaue Spezifikation des FailureDetectorInterface, sowie die das Interface implementierende Klasse FailureDetectorOmega, sind in Abbildung 3.15 dargestellt. Eine Instanz von FailureDetectorOmega wird im Weiteren kurz mit Fehlerdetektor bezeichnet. Im Folgenden werden die implementierten Methoden des Interface kurz präsentiert, anschließend wird die Funktionsweise von FailureDetectorOmega illustriert. • Über die Methode getLeader() kann der aktuell, durch den Fehlerdetektor vermutete Anführer abgefragt werden. 3.5. Multi-Paxos 45 • Die Methode isNewLeader() liefert true, falls seit ihrem letztmaligen Aufruf, ein neuer Anführer bestimmt wurde. • Methode setNewLeaderCallback() erlaubt es eine Instanz einer Implementierung der Klasse NewLeaderCallbackInterface zu registrieren, welche dynamisch über die Bestimmung eines neuen Anführers informiert wird. • Auch ein Fehlerdetektor arbeitet auf einer bestimmten Menge an Knoten, welche als Kandidaten für einen Anführer in Frage kommen. Die Methoden addMember(), beziehungsweise removeMember(), dienen dazu einen Knoten zu der Observation“ durch den Fehlerdetektor hinzuzufügen, beziehungs” weise ihn von dieser zu entfernen. • Die Methode stop() erlaubt ein sauberes“ Beenden der Aktivitäten eines ” Fehlerdetektors. Ein Mechanismus zum Austausch von Nachrichten des Typs FailureDetectorOmegaMessage bildet die Grundlage eines Fehlerdetektors. Er nützt dabei ComID um Nachrichten über das Kommunikationssystem zu versenden und registriert sich als Listener, um derartige Nachrichten zu empfangen. Ein Fehlerdetektor versendet über einen Timer-Mechanismus“ mit der ” Periode period fortwährend I_AM_ALIVE_MSG-Nachrichten an alle überwachten Knoten als Zeichen seiner Aktivität. Der Timer-Mechanismus basiert dabei auf einem periodisch aktivierten Thread UpdateDetectorTask. Überwachte Knoten, die prinzipiell als Anführer in Frage kommen würden, werden intern, mittels einer Datenstruktur trustList, verwaltet. Falls ein Fehlerdetektor von einem überwachten Knoten keine I_AM_ALIVE_MSG innerhalb eines bestimmten Zeitfensters TrustListValue.timeoutInterval empfängt, wird der Knoten aus der trustList entfernt und würde damit nicht mehr als Anführer in Frage kommen. Wird eine I_AM_ALIVE_MSG eines Knotens rechtzeitig empfangen, welcher allerdings aktuell nicht in der trustList enthalten ist, wird dieser der trustList wieder hinzugefügt und mit einem größeren TrustListValue.timeoutInterval versehen. Dies geschieht aus Gründen der Fairness, da es sich eventuell um einen Knoten handelt, der nicht ausgefallen war, sondern nur über eine langsame“ ” Netzwerkanbindung verfügt. Da es nicht sinnvoll ist einen Knoten als Anführer zu bestimmen der instabil ist, also häufig ausfällt und wiederanläuft, wird die Anführerwahl zusätzlich auf eine Datenstruktur epochNrList gestützt. Erholt sich ein Knoten gemäß dem unterstützten crash-recovery Modell von einem Ausfall, teilt er dies allen Teilnehmern durch das Senden einer RECOVERED_MSG-Nachricht mit. Erhält ein Fehlerdetektor eine RECOVERED_MSG eines Knotens, inkrementiert er dessen Epochennummer“ EpochNrListValue.epochNr und fügt den Knoten ” 46 Kapitel 3. Entwurf und Implementierung anschließend seiner trustList hinzu, falls dieser nicht ohnehin schon enthalten ist. Ein instabiler Prozess sollte somit im System immer einen höheren Wert seiner EpochNrListValue.epochNr besitzen, als ein stabiler Knoten. Damit im System solch ein globales Wissen“, über instabile Knoten, etabliert werden kann, syn” chronisieren sich die Fehlerdetektoren untereinander. Dazu schickt jeder Fehlerdetektor in seiner, ohnehin notwendig auszutauschenden, I_AM_ALIVE_MSG zusätzlich seine aktuelle epochNrList mit. Es wird nun genau derjenige überwachte Knoten von einem Fehlerdetektor als Anführer bestimmt, welcher in dessen trustList enthalten ist und zusätzlich die kleinste EpochNrListValue.epochNr besitzt. Treffen diese Eigenschaften auf mehrere Knoten gleichzeitig zu, wird der Knoten mit der kleinsten NodeID als Anführer bestimmt. Da die NodeID total geordnet sind, ist eine solche Wahl immer möglich. Durch die beschriebene Funktionalität kann systemweit zwar nicht garantiert werden, dass zu einem bestimmten Zeitpunkt jeder Fehlerdetektor genau denselben Anführer bestimmt. Es wird allerdings möglich, zu garantieren, dass dies irgendwann“ sicher passieren wird. Damit wird die durch Basic-Paxos geforderte ” Funktionalität erfüllt. 3.5.5 Realisierung von MultiPaxosAgreement Abbildung 3.16: UML-Klassendiagramm der Implementierung von MultiPaxosAgreement MultiPaxosAgreement implementiert das AgreementInterface und offeriert je nach GroupPolicy eine crash-recovery oder eine einfache crash-stop Variante des Multi-Paxos. Die Klasse bildet die oberste Abstraktionsschicht der bisher 3.5. Multi-Paxos 47 vorgestellten Logik der Realisierung des Multi-Paxos und ermöglicht eine totale Ordnung der an sie übergebenen Einigungswerte. Dabei basiert MultiPaxosAgreement auf einer Abfolge an WaitFreeRoundBasedConsensus-Instanzen. Die nächste zu startende Einigungsrunde wird intern durch roundNr und die nächste, im Sinne einer totalen Ordnung, zuzustellenden Runde durch nextToBeDelivered verwaltet. Um ein crash-recovery Modell zu unterstützen verfügt die Klasse über die Methoden store() und recover(), um die notwendigen Systeminformationen persistent zu sichern und wiederherstellen zu können. Die Klasse MultiPaxosAgreement soll als autonome“ Einheit arbeiten kön” nen, deshalb implementiert sie die Runnable-Schnittstelle. Um Nachrichten der Art MultiPaxosAgreementMessage verschicken zu können, verwendet sie ComID. Um derartige Nachrichten zu empfangen, registriert sie sich als Listener für diesen Nachrichtentyp. Die Klasse realisiert NewLeaderCallbackInterface um sich bei einem Fehlerdetektor zu registrieren. Im Folgenden wird die interne Funktionalität der Klasse näher erläutert: 1. Wird einem Objekt der Klasse ein Proposal per propose() übergeben, wird über den failureDetector der aktuelle Anführer abgefragt. Ist der ausführende Knoten nicht der aktuelle Anführer, leitet er das Proposal an diesen per UNDELIVERED_MSG-Nachricht weiter. Wird dem aktuellen Anführer ein Proposal übermittelt, versucht er für dieses eine neue Einigungsrunde zu starten, falls keine der beiden folgenden Bedingungen erfüllt ist: (a) Das Proposal wird bereits versucht für eine laufende Runde propagiert zu werden, beziehungsweise es wurde bereits erfolgreich propagiert. In solch einem Fall würde das Proposal verworfen werden. (b) Die aktuelle maximale Anzahl an parallel ablaufenden Runden maxParallelRounds, beziehungsweise eine spezielle Runde stopRound3 ist erreicht, wie in Abschnitt 3.4 erläutert. Wäre eine Runde stopRound erreicht, würde der laufende Thread der Klasse suspendiert werden. 2. Kann eine nächste Runde betreten“ werden, instanziiert der Anführer einen ” Thread vom Typ ProposeThread, der eine Einigung für die nächste Runde roundNr initiiert. 3. Ein ProposeThread instanziiert dabei, je nachdem ob die aktuelle MultiPaxosAgreement-Instanz das crash-recovery, oder das crash-stop Modell unterstützt, ein Objekt consensus der Klasse WaitFreeRoundBasedConsensusCrashRecovery oder WaitFreeRoundBasedConsensus. Solange der Knoten der Anführer ist, wird ProposeThread periodisch, mit 3 Durch den Einsatz der stopRound ist es Möglich den Algorithmus in einer bestimmten Runde anzuhalten. 48 Kapitel 3. Entwurf und Implementierung einer immer höheren Sequenznummer, versuchen consensus.propose() solange auszuführen, bis dieses erfolgreich zurückkehrt. Falls eine erfolgreiche Einigung erzielt werden konnte, teilt der Anführer dies den restlichen Knoten durch das Senden einer DECISION_MSG-Nachricht mit. (a) Konnte Proposal nicht für roundNr propagiert werden, da im System bereits ein anderer Einigungswert für die Runde akzeptiert wurde, wird Proposal einfach in einer späteren Runde erneut versucht zu propagieren. (b) Wie bereits angesprochen, könnte in dem Fall eines Ausfalls der Mehrheit an Knoten consensus.propose() blockieren. Um dies zu verhindern, überwacht ProposeThread den Einigungsvorgang und startet ihn erneut, falls dieser zu lange“ andauern würde. ” 4. Empfängt ein Knoten eine DECISION_MSG, beendet dieser zunächst einen eventuell für die entschiedene Runde laufenden ProposeThread. Anschließend versucht er den empfangenen Entscheidungswert Proposal im Sinne der totalen Ordnung zuzustellen. Er vergleicht dafür die entschiedene Runde, mit der als nächstes erwarteten Runde nextToBeDelivered: (a) Entspricht die Rundennummer der empfangenen Entscheidung nextToBeDelivered, wird das Proposal zugestellt und kann per getValue() abgerufen werden. (b) Falls Proposal für eine Runde später als nextToBeDelivered gültig ist, wird dieses zunächst intern gepuffert, da es noch nicht im Sinne einer totalen Ordnung zugestellt werden kann. Anschließend wird der Knoten versuchen, sich bei dem Knoten von dem er die DECISION_MSGNachricht erhalten hat, um ein Update“ zu bemühen, damit er seine ” Lücke in den abfolgenden Runden schließen kann. Zu diesem Zweck sendet er eine Nachricht vom Typ UPDATE_REQUEST_MSG an den Knoten. Aus Gründen der Performanz wird ein Knoten kein Update für Runden vor seinem Beitritt zum Einigungsprozess beantragen. 5. Empfängt ein Knoten einen Update-Wunsch eines anderen Teilnehmers, versucht er dessen Wissenslücken zu schließen und sendet ihm, über eine UPDATE_MSG-Nachricht, alle Ergebnisse der angeforderten Runden zu, für die dieser den Entscheidungswert kennt. 3.6. BFT-PK 49 Abbildung 3.17: UML-Klassendiagramm der Implementierung von BFT-PK 3.6 BFT-PK In dieser Sektion wird die Realisierung des in Abschnitt 2.3 vorgestellten BFTPK-Algorithmus beschrieben. Für die Implementierung wurde, im Bezug auf die in Abbildung 3.5 präsentierte Schichtenarchitektur, die in Abbildung 3.17 illustrierte Klassenarchitektur entworfen. Im Folgenden werden die einzelnen Klassen und Schnittstellen der Architektur kurz vorgestellt, im Anschluss daran, werden ihre einzelnen Funktionalitäten näher erläutert: • Das AgreementInterface bildet die bekannte Schnittstelle zu Group. • Im Zusammenspiel mit GenericPaxosAgreement realisiert die Klasse BFT_PK_Agreement die vierte Schicht und damit die Funktionalität, eine totale Ordnung über den empfangenen Einigungswerten zu etablieren. • Die zweite Schicht, und damit die Fähigkeit eine einzelne Runde zu entscheiden, wird durch die Klasse BFT_PK_RoundBasedConsensus realisiert. • Die Klasse BFT_PK_RoundBasedConsensusDisposer implementiert die eine zentrale Verwaltung der einzelnen BFT_PK_RoundBasedConsensus-Objekte und damit die Aufgabe der dritten Schicht. Darüber hinaus kapselt die Klasse den View Change Mechanismus des BFT-PK. 50 Kapitel 3. Entwurf und Implementierung • Mit der Klasse BFT_PK_Message wird eine einheitliche Form der, durch den BFT-PK ausgetauschten, Nachrichten eingeführt. • Eine Möglichkeit zur Signierung und Verifizierung von Nachrichten, wird durch die Schnittstelle BFT_PK_SignatureInterface beschrieben. • Eine Realisierung der Schnittstelle BFT_PK_DigestInterface erlaubt es, einen Hashwert über einen übergebenen byte-Array zu bilden. 3.6.1 Realisierung von BFT PK Message Abbildung 3.18: BFT PK Message UML-Klassendiagramm der Implementierung von Damit BFT-PK byzantinische Fehler tolerieren kann, ist es, wie in Abschnitt 2.3.1 erläutert, notwendig, eine Nachricht sicher ihrem Sender zuordnen zu können. Um dies zu unterstützen, macht der Algorithmus von einem MAC4 ” Verfahren“ Gebrauch. 4 Message Authentification Code 51 3.6. BFT-PK Das hat zur Konsequenz, dass ausgetauschte BFT_PK_Message-Nachrichten zusätzlich zu ihrer reinen Nutzinformation content ein Attribut contentSignature, welches den MAC der Nachricht repräsentiert, tragen. Unter einem MAC versteht man ein Zertifikat das über den Hashwert des ursprünglichen Nachrichteninhalts gebildet wird. Da dieses Grundprinzip für die Bildung aller, innerhalb von BFT-PK ausgetauschten, Nachrichten gemein ist, wurde die Grundstruktur einer solchen Nachricht in der Klasse BFT_PK_Message gekapselt. Für die unterschiedlichen Typen an ausgetauschten Nachrichten muss dabei nur der reine Nachrichteninhalt, repräsentiert durch die Klasse BFT_PK_MessageContent, variiert werden. Ein Gesamteindruck dessen, wird in Abbildung 3.18 gegeben. 3.6.2 Realisierung des BFT PK DigestInterface Abbildung 3.19: UML-Klassendiagramm BFT PK DigestInterface der Implementierung des Wie aus Abbildung 3.19 ersichtlich, wird BFT_PK_DigestInterface durch die Klasse BFT_PK_Digest implementiert. BFT_PK_Digest offeriert mit der Methode getDigest() eine Möglichkeit einen Hashwert über einen an sie übergebenen byte-Array zu bilden. Dabei wurde als Übergabeparameter ein Typ vom Wert byte[] gewählt, da sich alle in BFT-PK verwendeten Objekte, über die ein Hashwert gebildet werden soll, sich in einen solchen konvertieren lassen. Der generierte Hashwert wird dabei ebenfalls in Form eines byte-Arrays zurückgegeben. Ein Gleichheitsvergleich, über die erzeugten Hashwerte, wird durch die statische Methode isEqual() ermöglicht. Klassenintern wird, zur Realisierung von getDigest(), der weit verbreitete SHA-1 Algorithmus [NIST95] eingesetzt, da dieser aktuell alle in Abschnitt 2.3.1 geforderten Ansprüche an eine Hashfunktion unterstützt. Für den Einsatz von 52 Kapitel 3. Entwurf und Implementierung SHA-1 wird auf die Klasse MessageDigest aus dem Paket java.security der Java API zurückgegriffen. Durch die einfach gehaltene Schnittstelle des BFT_PK_DigestInterface wird ein Integrieren weiterer Hashfunktionen unterstützt. 3.6.3 Realisierung des BFT PK SignatureInterface Abbildung 3.20: UML-Klassendiagramm BFT PK SignatureInterface der Implementierung des Das BFT_PK_SignatureInterface wird durch die Klasse BFT_PK_Signature implementiert. Wie Abbildung 3.20 zeigt, stellt BFT_PK_Signature mit der Methode sign() eine Möglichkeit einer Signierung eines übergebenen byte-Arrays zur Verfügung. Die Methode liefert wieder einen byte-Array als Signatur zurück, welche mittels verify() verifiziert werden kann. Dabei ist BFT_PK_Signature konzipiert einen MAC-Mechanismus mittels des DSA-Algorithmus [NIST00] anzubieten. Zur Implementierung dieser Funktionalität wird die Klasse Signature aus java.security verwendet. DSA selber basiert auf dem Prinzip der asymmetrischen Verschlüsselung, mittels eines privaten und eines öffentlichen Schlüssels. Die Klasse BFT_PK_Signature erlaubt es dabei einem Knoten sich ein entsprechendes Schlüsselpaar zu kreieren. Für ein Funktionieren des BFT-PK wird vorausgesetzt, dass jede Signatur einer empfangenen Nachricht, transparent über verify(), auf ihre Gültigkeit hin verifiziert werden kann. Dazu ist es notwendig, dass jeder Knoten Kenntnis über die öffentlichen Schlüssel aller Teilnehmer besitzt. 53 3.6. BFT-PK Abbildung 3.21: UML-Klassendiagramm BFT PK RoundBasedConsensus 3.6.4 der Implementierung von Realisierung von BFT PK RoundBasedConsensus Ein Objekt der Klasse BFT_PK_RoundBasedConsensus implementiert die Logik eine Einigungsrunde roundNr innerhalb einer bestimmten view zu lösen. Abbildung 3.21 zeigt die von der Klasse dazu benötigten Komponenten. Dabei operiert ein solches Objekt auf einer festen Menge an Knoten nodes. Die Funktionsweise der Klasse entspricht dabei genau dem in Abschnitt 2.3.3 beschriebenen Ablauf der einzelnen Phasen des BFT-PK, ab dem Zeitpunkt, ab dem ein Knoten eine Nachricht vom Typ BFT_PK_PRE_PREPARE_MSG, also ein PRE-PREPARE, empfängt. Eine Nachricht wird per handleMsg() an ein Objekt der Klasse zugestellt. Um Nachrichten an andere Teilnehmer senden zu können, macht die Klasse von ComID Gebrauch. Dem in Abschnitt 2.3.3 beschriebenen Ablauf folgend, tauschen Instanzen von BFT_PK_RoundBasedConsensus Nachrichten der Klasse BFT_PK_PrepareMessage und BFT_PK_CommitMessage untereinander aus. Um solche Nachrichten signieren zu können, verfügt die Klasse über eine Referenz auf ein BFT_PK_Signature-Objekt. Damit Hashwerte über empfangene Proposals gebildet werden können, wird über eine Referenz auf ein BFT_PK_Digest-Objekt verfügt. Entsprechend dem Fortschritt des Einigungsprozesses, wird das interne boolesche Attribut prepared wahr, falls erfolgreich ein PREPARED-Zertifikat generiert werden konnte. Ein PREPARED-Zertifikat kann per Methode getPrepared() in Form einer Instanz der Klasse BFT_PK_PreparedCertificate abgefragt werden. Wird auch ein COMMITTED-Zertifikat generiert, ist gemäß der COMMIT- 54 Kapitel 3. Entwurf und Implementierung Phase, aus Abschnitt 2.3.3, Runde roundNr erfolgreich entschieden worden. Intern wird dies durch den Wert true des Attributs committed repräsentiert. Ein Erfolg wird schließlich zum einen BFT_PK_Agreement durch ein agreement.processDecision() in Form eines übermittelten BFT_PK_SuccessCertificate mitgeteilt. Zum anderen wird durch ein disposer.stopTimer() die Überwachung der Runde roundNr beendet. Wie man in Abbildung 3.21 erkennen kann, wird als Beweis der erfolgreichen Einigung in einem BFT_PK_SuccessCertificate das PRE-PREPARE, das PREPARED-Zertifikat und das COMMITTED-Zertifikat mitgeliefert. 3.6.5 Realisierung von BFT PK RoundBasedConsensusDisposer Abbildung 3.22: UML-Klassendiagramm BFT PK RoundBasedConsensusDisposer der Implementierung von Die Klasse BFT_PK_RoundBasedConsensusDisposer implementiert die dritte Schicht der Architektur aus Abbildung 3.5. Sie stellt damit die zentrale Komponente zur Verwaltung von BFT_PK_RoundBasedConsensus-Objekten dar. Dabei erfüllt sie die Funktionalität einer Fabrik, um diese Objekte zu kreieren. Gleichzeitig stellt die Klasse den zentralen Empfangspunkt für Nachrichten an die ein- 3.6. BFT-PK 55 zelnen BFT_PK_RoundBasedConsensus-Objekte dar. Ein Objekt der Klasse registriert sich folglich als Listener beim ComSys. Sobald ein Nachrichtentyp der Art BFT_PK_PRE_PREPARE_MSG, BFT_PK_PREPARE_MSG oder BFT_PK_COMMIT_MSG empfangen wird, muss, falls noch nicht existent, für die adressierte roundNr ein entsprechendes BFT_PK_RoundBasedConsensus-Objekt instanziiert werden. Die Nachricht wird dem zuständigen Objekt anschließend übermittelt. Verwaltet werden die einzelnen BFT_PK_RoundBasedConsensus-Objekte in der dynamischen Datenstruktur consensusPool. Da BFT_PK_RoundBasedConsensusDisposer die vollkommene Sicht über den Einigungsprogress, innerhalb der einzelnen Runden, besitzt, implementiert die Klasse den in Abschnitt 2.3.3 vorgestellten View Change Mechanismus. Da dazu ein Nachrichtenaustausch erforderlich ist, verfügt die Klasse über die Möglichkeit über ComSys BFT_PK_ViewChangeMessage-, beziehungsweise BFT_PK_NewViewMessage-Nachrichten zu versenden. Um den für das View Change notwendigen Timer-Mechanismus zu realisieren, wird ein periodisch startender Thread, implementiert durch die interne Klasse TimeoutTask, verwendet. Über die Methoden startTimer(), restartTimer() und stopTimer() wird ein externer Zugriff auf den Mechanismus ermöglicht. Als zusätzliche Funktion wird bei einem TIMEOUT nicht nur ein View Change eingeleitet, sondern es werden per agreement.forwardProposals() alle Proposals, die sich im Wartezustand auf ein erfolgreiches Propagieren für eine bestimmte Runde befinden, an alle Teilnehmer weitergeleitet. Dies geschieht um das Starten eines möglichen View Change bei einem Knoten zu ermöglichen, der seinen Timer eventuell noch nicht gestartet hat. Da BFT-PK zur Anführerbestimmung die aktuelle view benutzt, ermöglicht die Klasse durch die Methoden getLeader() den aktuellen Anführer, beziehungsweise den Anführer für eine bestimmte view, zu erfahren. BFT_PK_RoundBasedConsensusDisposer bietet zudem eine Schnittstelle um im Sinne der in Abschnitt 2.3.3 vorgestellten Garbage Collection konfiguriert zu werden: • Dazu steht die Methode setRoundWindow() zur Verfügung, um das durch minRoundNr und maxRoundNr beschränkte Fenster an akzeptierbaren Nachrichten für bestimmte Runden zu setzen. • Die Methode setCheckpoint() erlaubt die Übergabe eines Checkpoints, was einerseits für ein performantes View Change wichtig ist. Andererseits kann bei einer Übergabe eines stabilen Checkpoints der consensusPool und damit, im Sinne der Garbage Collection, das Log“ des Knotens aufgeräumt ” werden. 56 Kapitel 3. Entwurf und Implementierung Abbildung 3.23: UML-Klassendiagramm BFT PK Agreement 3.6.6 der Implementierung von Realisierung von BFT PK Agreement Die Klasse BFT_PK_Agreement implementiert zusammen mit GenericPaxosAgreement das AgreementInterface und bietet als primäre Funktionalität die Etablierung einer totalen Ordnung der an sie per propose() übergebenen Proposals. Um dies zu ermöglichen, stützt sich BFT_PK_Agreement zur Lösung einzelner Einigungsrunden auf Instanzen der Klasse BFT_PK_RoundBasedConsensus, welche transparent durch BFT_PK_RoundBasedConsensusDisposer verwaltet werden. Analog zu der Implementierung von MultiPaxosAgreement wird die nächste zu startende Runde intern durch roundNr und die nächste im Sinne einer totalen Ordnung zuzustellende Runde durch nextToBeDelivered repräsentiert. Die Klasse ist durch die Implementation von Runnable als Thread selbstständig lauffähig. Sie verfügt zur Realisierung ihrer Funktionalität unter anderem über eine Referenz auf eine Instanz consensusDisposer der Klasse BFT_PK_RoundBasedConsensusDisposer. Überhaupt sind die Funktionalitäten der beiden Klassen eng miteinander gekoppelt. Im Kontext der Funktionsweise von BFT-PK ist BFT_PK_Agreement zuständig für das Initiieren des Garbage Collection Prozesses und damit für das Anlegen 3.6. BFT-PK 57 von Checkpoints. Dies erfolgt, da die Klasse eine Sicht über die totale Ordnung der erfolgreichen Runden besitzt. Dazu ist, gemäß Abschnitt 2.3.3, der Austausch von Nachrichten, repräsentiert durch die Klasse BFT_PK_CheckpointMessage nötig. Um derartige Nachricht empfangen zu können, registriert sich die Klasse als Listener. Sie verwendet ComSys um Nachrichten zu senden. Im Folgenden wird die Funktionalität der Klasse kurz skizziert: 1. Wird per propose() ein Proposal übergeben, informiert sich der Knoten bei consensusDisposer, ob er der Anführer der aktuellen view ist. Ist er dies nicht, leitet er das Proposal per BFT_PK_UndeliveredMessage an diesen weiter und startet den Überwachungsmechanismus durch ein consensusDisposer.startTimer(). Wird dem aktuellen Anführer ein Proposal übermittelt, versucht dieser dafür eine neue Einigungsrunde roundNr zu initiieren, falls keine der beiden nachfolgenden Bedingungen erfüllt ist: (a) Das Proposal wird bereits für eine laufende Runde versucht wird zu propagieren, beziehungsweise es wurde bereits erfolgreich propagiert. Wäre das der Fall, würde der Anführer das Proposal verwerfen. (b) Die aktuelle maximale Anzahl an parallel ablaufenden Runden maxParallelRounds, beziehungsweise eine spezielle Runde stopRound ist erreicht. Wäre eine Runde stopRound erreicht, würde der laufende Thread der Klasse suspendiert werden. 2. Ist ein Propagieren für roundNr möglich, sendet der Knoten für das Proposal eine BFT_PK_PrePrepareMessage an alle Teilnehmer. 3. Eine erfolgreiche Einigung einer Runde erfährt BFT_PK_Agreement über die Methode processDecision(). Mittels des übergebenen BFT_PK_SuccessCertificate wird das darin enthaltene Proposal versucht im Sinne der totalen Ordnung zuzustellen. Der Beweis der erfolgreichen Einigung wird ebenfalls gespeichert. (a) Konnte das ursprünglich für roundNr vorgesehene Proposal nicht in der Runde erfolgreich propagiert werden, wird versucht das Proposal in einer späteren Runde erneut zur Einigung vorzuschlagen. (b) Wurde genau das Proposal für die Runde awaitingToBeDelivered übermittelt, wird dieses, im Sinne der totalen Ordnung, zugestellt und kann anschließend per getValue() abgerufen werden. i. Falls awaitingToBeDelivered der Periode zum Anlegen eines Checkpoints CHECKPOINTPERIOD entspricht, wird versucht einen stabilen Checkpoint zu kreieren. Dazu wird eine BFT_PK_CheckpointMessage an alle Knoten versendet. ii. Wurde ein stabiler Checkpoint erfolgreich etabliert, wird der consensusDisposer entsprechend konfiguriert. 58 Kapitel 3. Entwurf und Implementierung (c) Falls das Proposal für eine spätere Runde, als awaitingToBeDelivered, gültig ist, wird dieses zunächst intern gepuffert. Anschließend wird versucht sich bei dem aktuellen Anführer um ein Update“ zu ” bemühen, damit die entstandene Lücke, an empfangenen Einigungsrunden, geschlossen werden kann. Dazu wird eine BFT_PK_UpdateRequestMessage, die eine Anforderung für alle fehlenden Runden enthält, gesendet. Dabei wird, aus Gründen der Performanz, kein Update für eine Runde die vor der Instanziierung der Klasse liegt beantragt. 4. Wird ein Wunsch nach einem Update empfangen, wird dieser für alle Runden, über die eine Entscheidung bekannt ist, mittels einer BFT_PK_UpdateMessage beantwortet. Kapitel 4 Messungen In diesem Kapitel werden Messungen präsentiert, die durchgeführt wurden, um die Leistungsfähigkeit der Implementierung zu analysieren. 4.1 Rahmenbedingungen Im Folgenden werden die Rahmenbedingungen, unter denen die JavaImplementierung der generischen Protokollinstanz getestet wurde, kurz vorgestellt. Alle Messungen erfolgten im CIP-Pool des Informatik-Instituts, dessen Netzwerk mittels 100MBit-Ethernet verbunden ist. Dabei wurden die Messungen verteilt, auf bis zu 16 Linux PCs und während des normalen“ Netzwerkverkehrs, ” durchgeführt. Die Linux PCs arbeiten zusätzlich auf einem NFS1 . Als Laufzeitumgebung kam Java HotSpotT M Client VM (build 1.4.2 06-b03, mixed mode) zum Einsatz. Ein Knoten der Anwendung wurde dabei, jeweils exklusiv, auf einem PC instanziiert. Um die Implementierung im Kontext der sie umgebenden Gruppenkommunikationsarchitektur zu testen, steht in dem Paket org.aspectix.group.consensus.test ein generisches Testprogramm TestGC zur Verfügung. Das Programm erlaubt es, die Gruppenkommunikationsschicht mit jedem der implementierten Einigungsalgorithmen zu starten. Dabei werden drei Testfunktionen angeboten: • Ein Knoten sendet mittels eines Flutmechanismus beliebig viele Gruppennachrichten. • Ein Knoten simuliert ein periodisches Ein- und Austreten zu, beziehungsweise von der Gruppe. 1 Network File System 59 60 Kapitel 4. Messungen • Ein Knoten initiiert ein periodisches Austauschen des verwendeten Einigungsalgorithmus. Um eine Aussage über die Leistungsfähigkeit der verschiedenen Einigungsalgorithmen zu gewinnen, wurde, für die Messreihen, nur von der erstgenannten Option Gebrauch gemacht. Dabei wurden die einzelnen Testläufe nach folgendem Grundprinzip durchgeführt: • Initial wird eine Gruppe mit nur einem Teilnehmer, dem Initiator, kreiert. • Der Gruppe treten anschließend eine bestimmte Anzahl an Knoten bei. • Schließlich tritt ein Knoten bei, welcher, mittels des genannten Flutmechanismus, eine Fülle an Nachrichten an die Gruppe sendet. Dieser versucht dabei permanent so viele Nachrichten wie möglich zu senden, so dass das Gesamtsystem einem regelrechten Stresstest“ unterzogen wird. Dabei wird ” pro Testlauf jeweils gemessen: – Wie lange es dauert, bis die Einigungskomponente 1000 Einigungswerte(Proposals), in einer total geordneten Reihenfolge(TOZustellungen), zustellen kann. – Mit welchem Durchsatz die jeweils letzten 50 TO-Zustellungen verarbeitet werden konnten. Um einen Eindruck von einem laufenden Gruppenkommunikationssystem zu bekommen, wurden die Messungen jeweils ab Runde 100 gestartet. Dabei wurde von einem stabilen“ System ausgegangen, das heißt von einem ” einzigen korrekten Anführer während der gesamten Laufzeit einer Messung. Die Hauptkomponenten der einzelnen implementierten Einigungsvarianten wurden dabei mit folgenden Parameterwerten instanziiert, wobei alle Varianten auf eine maximale Anzahl von fünf parallelen Runden beschränkt liefen: • Multi-Paxos(crash-stop und crash-recovery) – Der Fehlerdetektor sendete alle 30 Sekunden eine I_AM_ALIVE_MSGNachricht. • BFT-PK – Das Checkpointing wurde für jeweils 100 absolvierte, total zugestellte, Runden gestartet. – Es wurde ein Nachrichtenfenster verwendet, das auf eine Größe von 400 limitiert war. 61 4.2. Ergebnisse Das Ziel der Messungen ist es zu evaluieren, inwiefern die Implementierung für eine verschiedene Anzahl an Teilnehmern am Entscheidungsprozess skaliert. Da dabei die Anzahl an erfolgreichen Einigungen und nicht der tatsächliche Einigungswert im Vordergrund stehen, wurde als Einigungswert effektiv ein kurzer String gesendet. 4.2 Ergebnisse #TO-Zustellungen 4 Knoten [ms] 6 Knoten [ms] 8 Knoten [ms] 10 Knoten [ms] 12 Knoten [ms] 14 Knoten [ms] 16 Knoten [ms] 100 150 200 250 300 350 400 450 500 1737 2465 3326 3983 4762 5510 6220 6948 7744 1681 2667 3585 4440 5390 6310 7274 8247 9151 1711 2847 3923 4996 6096 7188 8193 9272 10436 1764 3080 4235 5571 6949 8235 9577 10830 12098 1697 3311 4856 6237 7736 9099 10670 12262 13793 16807 18496 20123 22223 24007 25775 27466 29250 31132 1126 2904 4891 6715 8764 10586 12331 14278 16194 550 8524 10077 11486 13319 15256 32771 17914 600 9307 10946 12580 14745 16709 34728 19843 650 10036 11937 13679 16160 18170 36570 21399 700 10690 12921 14903 17448 19713 38375 23498 750 11545 13858 16049 18778 21227 40079 25472 800 12363 14867 17186 20128 22677 41826 27381 850 13201 15850 18318 21483 24179 43502 29255 900 13999 16849 19543 22812 25791 45486 31066 950 14720 17811 20702 24304 27368 47232 33024 1000 15522 18858 21833 25726 28889 49101 34951 Tabelle 4.1: Latenz der TO-Zustellungen des Multi-Paxos(crash-stop) #TO-Zustellungen 4 Knoten [ms] 6 Knoten [ms] 8 Knoten [ms] 10 Knoten [ms] 12 Knoten [ms] 14 Knoten [ms] 16 Knoten [ms] 100 150 200 250 300 350 4263 6794 9747 12411 15326 17698 3128 5171 6907 9513 11718 13658 7060 11435 15341 19637 24091 28571 6477 9857 14640 19032 22599 25465 51842 55903 60421 64415 69237 73085 23811 29467 34466 39419 43817 50646 3938 9392 17372 22480 27926 32267 400 20888 15854 31611 32274 78512 55100 36030 450 24573 18423 34450 36982 83099 59411 39858 500 27371 21245 40595 40552 86739 63639 44526 550 30144 24119 46288 44089 90779 68761 49697 600 33137 27347 48573 47698 94170 73407 53458 650 700 750 800 850 900 950 1000 36149 38941 41903 44928 49168 52465 55845 59509 30149 33658 36145 37766 39435 41661 43389 45101 50730 52773 54864 57086 60156 63430 66526 70606 50506 52885 55224 58813 62644 66251 69668 73988 98044 102401 106714 109894 112803 116168 119902 124729 77561 82853 88626 94624 101492 107707 113621 120521 56767 60897 65508 70398 74475 78160 82752 87375 Tabelle 4.2: Latenz der TO-Zustellungen des Multi-Paxos(crash-recovery) #TO-Zustellungen 4 Knoten [ms] 6 Knoten [ms] 8 Knoten [ms] 10 Knoten [ms] 12 Knoten [ms] 14 Knoten [ms] 16 Knoten [ms] 100 3729 4130 4111 5278 3694 3396 2311 150 5899 6399 6729 9802 7140 7171 7017 200 7961 8705 9332 13794 10281 10741 11195 250 9965 11093 11782 17936 13402 14406 15517 300 11970 13389 14444 21973 16613 17817 19915 350 14098 15947 16974 25601 19782 21341 24655 400 16115 18228 19672 30229 22840 24840 28934 450 18259 20692 22161 34661 26150 28592 33113 500 20251 22997 24739 38783 29395 32168 37484 550 22356 27753 27405 43123 32860 35842 42054 600 24410 25373 30209 47019 36896 39304 46475 650 26490 30186 32893 51791 40115 42967 50940 700 28628 32648 35569 56124 43334 46498 55483 750 30727 35090 38298 60938 46661 50359 59818 800 32968 37523 41157 65400 49850 53834 64359 850 35159 40068 43910 70246 53071 57439 68864 900 37326 42592 46711 75128 56575 61105 73418 950 39564 45115 49558 79718 59878 64669 78104 1000 41790 47780 52479 84459 63208 68203 82692 Tabelle 4.3: Latenz der TO-Zustellungen des BFT-PK Die Tabellen 4.1, 4.2 und 4.3 zeigen die für unterschiedliche Teilnehmermengen, jeweils alle 50 Runden, gemessene Verzögerung der Zustellung an Proposals in totaler Ordnung. Um einen Vergleich der drei Varianten zu ermöglichen, zeigt Abbildung 4.1 die gesamte Latenz, für je 1000 TO-Zustellungen eines Einigungsalgorithmus über verschiedene Knotenkonfigurationen. Die jeweiligen Messwerte für die einzelnen Varianten sind dabei im Diagramm, gemäß der Legende, markiert. Wie zu erwarten war, ist für eine größere Knotenanzahl in der Regel auch eine höhere Latenz zu verzeichnen. Allen Varianten ist dabei erfreulicherweise gemein, dass im Großen und Ganzen ein stetig wachsendes Latenzverhalten für eine steigende Teilnehmeranzahl zu beobachten ist. Der Grund für die anwachsende Latenz liegt in der Natur der Algorithmen selbst begründet. Für eine größere Teilnehmermenge vergrößert sich auch die Anzahl der ausgetauschten Nachrichten, sowie die notwendige Quorenmenge für eine 62 Kapitel 4. Messungen Einigung. Dies sollte sich durch eine höhere Verzögerung des Einigungsprozesses pro Runde niederschlagen. Als Flaschenhals des Systems ist dabei der Anführer zu betrachten, da dieser gewissermaßen einen zentralen Punkt“ im Einigungs” prozess einnimmt. Obwohl die crash-recovery Variante des Multi-Paxos in ihrer Funktionalität, im Bezug auf das Anlegen von persistenten Sicherungen, sehr optimiert implementiert ist2 , fällt sie gegenüber der crash-stop Variante deutlich ab. Zudem zeigt ihr Graph, in Abbildung 4.1, deutliche Sprünge“ in seinem Verlauf, wohingegen ” die Graphen der beiden anderen Algorithmen recht linear verlaufen. Dies kann man dadurch begründen, dass das Ablegen von Speicherinformationen, welches ja für jede einzelne Entscheidungsrunde erfolgen muss, derzeit noch sehr simpel geschieht. Es wird einfach pro Runde eine Datei angelegt. Dies hat zur Folge, dass ein erheblicher Overhead“ hinsichtlich des Festplattenzu” griffs entsteht. Dadurch das die Testumgebung zudem eine Synchronisation ihrer Dateistruktur via NFS vornimmt, wird dieser Effekt zusätzlich verstärkt. Dies könnte das schlechte Verhalten der crash-recovery Variante erklären. Dass der BFT-PK hinsichtlich seiner Latenz der crash-stop Version des MultiPaxos unterlegen ist, lässt sich an dem deutlich höheren Volumen an ausgetauschten Nachrichten festmachen, was sich besonders bei einer hohen Anzahl an Teilnehmerknoten bemerkbar machen sollte. Zum anderen ist der Overhead, der durch die notwendige Signierung und Verifizierung jeder Nachricht innerhalb des BFT-PK entsteht, nicht zu verachten. #TO-Zustellungen 4 Knoten [s−1 ] 6 Knoten [s−1 ] 8 Knoten [s−1 ] 10 Knoten [s−1 ] 12 Knoten [s−1 ] 14 Knoten [s−1 ] 16 Knoten [s−1 ] 100 54.112 47.573 40.064 33.178 29.463 3.548 44.404 150 68.681 50.709 44.014 37.993 30.978 29.603 28.121 200 250 300 350 400 450 500 550 600 650 700 750 800 58.072 76.103 64.184 66.844 70.422 68.681 62.814 64.102 63.856 68.587 76.452 58.479 61.124 54.466 58.479 52.631 54.347 51.867 51.387 55.309 53.995 57.537 50.454 50.864 53.304 49.554 46.468 46.598 45.454 45.787 50.251 46.339 42.955 47.619 45.703 45.495 40.849 43.630 43.975 43.290 37.425 36.284 38.880 37.257 39.904 39.432 40.950 35.063 35.335 38.819 37.593 37.037 32.362 36.205 33.355 36.683 31.826 31.407 32.658 34.176 34.411 34.223 32.404 33.025 34.482 30.731 23.809 28.026 28.280 29.568 28.026 26.567 30.506 25.549 27.144 27.700 29.342 28.620 25.163 27.412 24.402 27.442 28.653 25.680 26.096 29.069 25.920 32.133 13.679 25.329 26.191 850 59.665 50.864 44.169 36.900 33.288 29.832 26.680 900 62.656 50.050 40.816 37.622 31.017 25.201 27.609 950 1000 69.348 62.344 51.975 47.755 43.140 44.208 33.512 35.161 31.705 32.873 28.636 26.752 25.536 25.947 Tabelle 4.4: Durchsatz des Multi-Paxos(crash-stop) pro 50 TO-Zustellungen #TO-Zustellungen 4 Knoten [s−1 ] 6 Knoten [s−1 ] 8 Knoten [s−1 ] 10 Knoten [s−1 ] 12 Knoten [s−1 ] 14 Knoten [s−1 ] 16 Knoten [s−1 ] 100 22.401 23.934 8.665 8.265 5.058 2.622 12.696 150 19.755 24.473 11.428 14.792 12.312 8.840 9.167 200 16.931 28.801 12.800 10.453 11.066 10.002 6.265 250 300 350 400 450 18.768 17.152 21.079 15.673 13.568 19.186 22.675 25.773 22.768 19.462 11.638 11.225 11.160 16.447 17.611 11.384 14.017 17.445 7.343 10.620 12.518 10.369 12.993 9.213 10.900 10.094 11.368 7.321 11.225 11.598 9.788 9.181 11.518 13.287 13.061 500 550 600 650 17.869 18.031 16.705 16.600 17.717 17.397 15.489 17.844 8.1366 8.7827 21.881 23.180 14.005 14.136 13.854 17.806 13.736 12.376 14.744 12.906 11.825 9.761 10.761 12.036 10.711 9.669 13.294 15.110 700 750 800 850 900 950 17.908 16.880 16.528 11.792 15.165 14.792 14.249 20.104 30.845 29.958 22.461 28.935 24.473 23.912 22.502 16.286 15.271 16.149 21.017 21.376 13.931 13.051 13.861 14.632 11.475 11.592 15.723 17.188 14.858 13.390 9.448 8.661 8.336 7.280 8.045 8.454 12.106 10.843 10.224 12.263 13.568 10.888 1000 13.646 29.205 12.254 11.574 10.358 7.246 10.815 Tabelle 4.5: Durchsatz des Multi-Paxos(crash-recovery) pro 50 TO-Zustellungen In den Tabellen 4.4, 4.5 und 4.6 sind jeweils fortlaufend für unterschiedliche Knotenmengen der drei Varianten, die Durchsatzwerte der letzten 50 total zugestellten Runden angegeben. Man kann erkennen, dass nach einem Gewissen Anlaufen“, der Durchsatz ” der drei Varianten, innerhalb einer Messreihe mit fester Knotenanzahl, doch re” 2 Es werden nur dann persistente Speicherungen vorgenommen, wenn diese für die Konsistenzerhaltung zwingend erforderlich sind. 63 4.2. Ergebnisse Latenz[ms] pro 1000 TO-Zustellungen 2e+05 Multi-Paxos (crash-stop) Multi-Paxos (crash-recovery) BFT-PK 1,5e+05 1e+05 50000 0 0 10 # Knoten 5 15 20 Abbildung 4.1: Latenzvergleich der realisierten Paxos-Varianten #TO-Zustellungen 4 Knoten [s−1 ] 6 Knoten [s−1 ] 8 Knoten [s−1 ] 10 Knoten [s−1 ] 12 Knoten [s−1 ] 14 Knoten [s−1 ] 16 Knoten [s−1 ] 100 25.113 19.700 17.307 10.386 13.535 14.723 21.635 150 200 250 23.041 24.248 24.950 22.036 21.682 20.938 19.098 19.208 20.408 11.052 12.525 12.071 14.509 15.918 16.020 13.245 14.005 13.642 10.624 11.967 11.568 300 24.937 21.777 18.782 12.385 15.571 14.658 11.368 350 23.496 19.546 19.762 13.781 15.777 14.188 10.548 400 24.789 21.920 18.532 10.803 16.350 14.289 11.684 450 500 550 600 650 700 750 800 850 900 950 23.320 25.100 23.752 24.342 24.038 23.386 23.820 22.311 22.820 23.073 22.341 20.292 21.691 21.043 21.008 20.550 20.308 20.475 20.550 19.646 19.809 19.817 20.088 19.394 18.754 17.831 18.628 18.684 18.321 17.488 18.162 17.850 17.562 11.281 12.130 11.520 12.833 10.477 11.539 10.386 11.205 10.317 10.241 10.893 15.105 15.408 14.430 12.388 15.532 15.532 15.028 15.678 15.523 14.269 15.137 13.326 13.982 13.609 14.442 13.650 14.160 12.950 14.388 13.869 13.638 14.029 11.964 11.439 10.940 11.309 11.198 11.005 11.534 11.010 11.098 10.979 10.670 1000 22.461 18.761 17.117 10.546 15.015 14.148 10.897 Tabelle 4.6: Durchsatz des BFT-PK pro 50 TO-Zustellungen lativ“ konstant bleibt. Die Varianten scheinen somit für eine wachsende Anzahl an Einigungsrunden zu skalieren. Bei dem BFT-PK lässt sich zudem der Einfluss des Checkpointings gering” fügig“ erkennen. Da dieser, gemäß den Rahmenbedingungen des Tests, alle 100 Runden systemweit durchgeführt wird, ergeben sich immer wieder leichte Anund Abstiege im Verlauf der Durchsatzwerte pro Messreihe. In Abbildung 4.2 werden die einzelnen Varianten hinsichtlich ihres Durchsatzes vergleichend gegenübergestellt. Dabei wurde zur Dämpfung“ der Median der ” Durchsatzwerte pro Messreihe verwendet. Dieser ist in den Tabellen 4.4, 4.5 und 4.6 für eine Reihe jeweils hervorgehoben. Die einzelnen Medianwerte sind in der Abbildung, gemäß der Legende, markiert. Analog zu den angestellten Folgerungen hinsichtlich der Latenz, nimmt der Durchsatz der Varianten erwartungsgemäß, mit einer steigenden Teilnehmeranzahl, ab. Positiv ist zu sehen, dass die Gesamtperformanz relativ“ linear und ” nicht etwa exponentiell abfällt. Ein Nebeneffekt des durchgeführten Stresstestens war es, die Robustheit der 64 Kapitel 4. Messungen 70 Multi-Paxos (crash-stop) Multi-Paxos (crash-recovery) BFT-PK # TO-Zustellungen / Sekunde 60 50 40 30 20 10 0 0 5 10 # Knoten 15 20 Abbildung 4.2: Durchsatzvergleich der realisierten Paxos-Varianten Implementierung zu überprüfen. Erfreulicherweise traten während allen Testläufen keine Laufzeitfehler, oder andere unerwartete Probleme, wie beispielsweise Synchronisationsfehler, auf. Kapitel 5 Zusammenfassung und mögliche Ergänzungen 5.1 Zusammenfassung Die Hauptaufgabe der Arbeit bestand in dem Entwurf und der Implementierung einer generischen Protokollinstanz, geeignet für eine crash-stop und eine crashrecovery Variante von Multi-Paxos, sowie den BFT-PK-Algorithmus. Als zusätzliche Anforderung, sollte die Protokollinstanz in die Gruppenkommunikationsschicht von AspectIX eingebettet werden, um dieser als Modul zur Etablierung einer totalen Ordnung, über den ausgetauschten Gruppennachrichten, zur Verfügung zu stehen. Dabei sollte die Protokollinstanz die Möglichkeit bieten, die gewünschte Version eines Einigungsalgorithmus dynamisch rekonfigurieren zu können. Da die Gruppenkommunikationsschicht nach dem Modell einer offenen Gruppe“ funktioniert, sollten die realisierten Einigungsalgorithmen eine ” dynamische Adaption an eine sich ändernde Teilnehmermenge ermöglichen. Die für das Verständnis der Arbeit notwendigen allgemeinen Hintergründe werden in Kapitel 1 vermittelt. Neben speziell zu beachtenden Eigenschaften eines verteilten Kontext, wird insbesondere auf die Problematik des verteilten Konsensus weiter eingegangen. Am Ende des Kapitels wird die Funktionalität der Gruppenkommunikationsschicht von AspectIX näher erläutert. In Kapitel 2 werden die in der Arbeit betrachteten Einigungsalgorithmen vorgestellt. Dabei wird das einem jeden Algorithmus zu Grunde liegende Systemmodell modelliert. Anschließend wird die Funktionsweise eines Algorithmus präsentiert, bevor als Letztes auf dessen konkreten Ablauf eingegangen wird. Das Design und die Realisierung der generischen Protokollinstanz ist Inhalt von Kapitel 3. Abschnitt 3.1 benennt die Anforderungen an eine solche Protokollinstanz, in Abschnitt 3.2 wird deren Grundstruktur im Rahmen der Gruppenkommunikationsarchitektur gezeigt. Um eine generische Realisierung zu erleichtern, ist in Abschnitt 3.3 eine Möglichkeit einer Zerlegung der Protokollinstanz in ein65 66 Kapitel 5. Zusammenfassung und mögliche Ergänzungen zelne funktionale Schichten dargestellt. Die Problematiken einer dynamischen Rekonfiguration und deren Konsequenzen im Bezug auf die Einigungsalgorithmen werden in Abschnitt 3.4 gezeigt. Im Anschluss werden die Implementierungen der Einigungsalgorithmen illustriert, wobei speziell für Multi-Paxos die Realisierung mithilfe eines Frameworks gezeigt wird. Durch diese Design-Entscheidung wird eine Implementierung diverser Varianten des Algorithmus forciert. Die Beschreibung der Messungen und die Bewertung der erzielten Ergebnisse bilden den Abschluss der Arbeit. Zunächst werden in Kapitel 4 die Rahmenbedingungen der durchgeführten Messreihen genannt. Daran anschließend, werden die Ergebnisse der Messungen dargestellt und eine Analyse derer wird vorgenommen. Zusammenfassend ist zu sagen, dass alle an die generische Protokollinstanz gestellten Anforderungen erfüllt werden konnten. Dadurch wird es letztendlich ermöglicht einen, sich auf diese Instanz stützenden, rekonfigurierbaren total geordneten Gruppenkommunikationsdienst zu realisieren. 5.2 Mögliche Ergänzungen Im Folgenden werden Möglichkeiten zur Ergänzung und Verbesserung der Arbeit aufgeführt: • Aktuell wird der in den Klassen MultiPaxosAgreement und BFT_PK_Agreement eingesetzte Update-Mechanismus“ für jeden, nicht in einer totalen ” Ordnung empfangenen, erfolgreichen Einigungswert ein Update“ beantra” gen, um die Wissenslücke“ des Knotens zu schließen. Aus Gründen der ” Performanz wäre hier eine intelligentere“ Vorgehensweise wünschenswert. ” • Da die eingesetzten Einigungsprotokolle nicht alle Dienstgüte-Eigenschaften eines auf TCP-Verbindungen basierenden Kommunikationssystems benötigen, würde sich zum Beispiel ein auf UDP aufsetzendes Kommunikationssystem anbieten. Dies wäre im Sinne eines schnelleren“ Nachrichtenaustau” sches und damit im Sinne eines möglicherweise schnelleren Einigungsprogresses wünschenswert. • Wie bereits angesprochen, wurde Multi-Paxos mittels eines Frameworks implementiert. Dadurch würde es sich anbieten, weitere Varianten des Algorithmus, wie zum Beispiel den sogenannten Fast-Paxos, zu implementieren. • Die Messungen von Kapitel 4 offenbarten einen ineffizient arbeitenden Speichermechanismus“ der crash-recovery Variante von Multi-Paxos. Als ” Verbesserung wäre hier zum Beispiel das Speichern, der notwendigen Systeminformationen, mittels einer Flatfile-Datenbank“ möglich. ” • Damit auch für den BFT-PK die Unterstützung eines crash-recovery Modells ermöglicht wird, wäre eine entsprechende, auf einem persistenten Speichermedium operierende, Modifikation wünschenswert. 5.2. Mögliche Ergänzungen 67 • In der Implementierung des BFT-PK wird von einer statischen Kenntnis der öffentlichen Schlüssel aller Teilnehmer ausgegangen. Eine schöne Erweiterung wäre hier die Möglichkeit dieses Wissen zur Laufzeit zu beziehen. Über die simpel gehaltene Schnittstelle BFT_PK_SignatureInterface könnte eine solche Erweiterung leicht in den Kontext des BFT-PK integriert werden. Literaturverzeichnis [ASP05] AspectIX. http://www.aspectix.org/, Abruf am 01.02.2005 [BDF+01] Romain Boichat, Partha Dutta, Svend Frølund, Rachid Guerraoui. Deconstructing Paxos. DSC Technical Report 2001-06, Department of Communication Systems, Swiss Federal Institute of Technology, Lausanne, 2001 [Cas01] Miguel Castro. Practical Byzantine Fault Tolerance. PhD Thesis,Massachusetts Institute of Technologie (MIT), 2001. [CT96] Tushar Deepak Chandra, Sam Toueg. The weakest failure detector for solving consensus. Journal of the ACM, 43(4):685-722, Juli 1996. [FLP85] Michael J. Fischer, Nancy A. Lynch, Michael S. Paterson. Impossibility of Distributed Consenus with One Faulty Process. Journal of the Association for Computing Machinery, Vol.32, No. 2, 1985, S. 374-382. [Lam01] Leslie Lamport. Paxos Made Simple. ACM SIGACT News (Distributed Computing Column) 32, 2001. [Lam89] Leslie Lamport. The Part-Time Parliament. Technical Report, DEC Systems Research Center, 1989. [Löh04] Hans Löhr. Design and Implementation of a Group Communication Layer for the AspectIX Middleware Based on Fault-Tolerant Agreement Algorithms. Studienarbeit im Fach Informatik, FriedrichAlexander-Universität Erlangen-Nürnberg, Lehrstuhl für Informatik 4, 2004. [Lyn96] Nancy A. Lynch. Distributed Algorithms. Morgan Kaufmann, 1996. [NIST00] National Institute of Standards and Technology(NIST). Digital Signature Standard, FIPS 186-2, U.S. Department of Commerce, Januar 2000 68 LITERATURVERZEICHNIS 69 [NIST95] National Institute of Standards and Technology(NIST). Announcing the Secure Hash Standard, FIPS 180-1, U.S. Department of Commerce, April 1995 [PLL00] Roberto De Prisco, Butler Lampson, Nancy A. Lynch. Revisiting the Paxos algorithm. Theoretical Computer Science, 243(12):35-91, Juli 2000. [RK03] Hans P. Reiser, Rüdiger Kapitza. Verteilte Algorithmen. Skript zur Vorlesung, Friedrich-Alexander-Universität Erlangen-Nürnberg, Lehrstuhl für Informatik 4, 2003. [Sag03] Francesca Saglietti. Fehlertolerierende Softwarearchitekturen. Skript zur Vorlesung, Friedrich-Alexander-Universität ErlangenNürnberg, Lehrstuhl für Informatik 11, 2003.