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.