Effizientes Routing in Peer-to-Peer Netzwerken

P-Grid [2] oder SkipNet [16] verwendet werden. Kern dieser Ansätze ist eine über die ...... Universität Duisburg-Essen. [10] Ian Clarke, Oskar Sandberg, Brandon ...
861KB Größe 35 Downloads 310 Ansichten
Universit¨at des Saarlandes Naturwissenschaftlich-Technische Fakult¨at I Fachbereich Informatik

Diplomarbeit

Effizientes Routing in Peer-to-Peer Netzwerken

vorgelegt von

Dennis Schade

Angefertigt unter der Leitung von Prof. Dr. Gerhard Weikum Max-Planck-Institut f¨ ur Informatik AG5 Databases and Information Systems Group

Saarbr¨ ucken, 28. M¨arz 2005

Hiermit erkl¨are ich an Eides statt, dass ich diese Arbeit selbst¨andig verfasst und keine anderen als die im Literaturverzeichnis angegebenen Quellen benutzt habe.

Dennis Schade Saarbr¨ ucken, 28. M¨arz 2005

Inhaltsverzeichnis

Abbildungsverzeichnis

iv

Tabellenverzeichnis

vi

1 Einleitung

1

2 Einf¨ uhrung in Peer-to-Peer-Systeme

3

2.1

Was ist Peer-to-Peer? . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

2.2

Vor- und Nachteile von Peer-to-Peer-Systemen . . . . . . . . . . . . .

4

2.3

Verschiedene L¨osungsans¨atze . . . . . . . . . . . . . . . . . . . . . . .

5

2.3.1

Hybride P2P-Systeme . . . . . . . . . . . . . . . . . . . . . . .

5

2.3.2

Echte P2P-Systeme

6

2.4

. . . . . . . . . . . . . . . . . . . . . . . .

Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3 Der Chord-Algorithmus

15

3.1

Das Chord-Systemmodell . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.2

Das Auffinden von Schl¨ usseln im Chord-Ring . . . . . . . . . . . . . . 16

3.3

3.2.1

Einfache Suche . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.2.2

Skalierbare Suche mit Fingertabellen . . . . . . . . . . . . . . . 18

Der Chord-Peer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.3.1

Die Chord-Stabilisierungsalgorithmen . . . . . . . . . . . . . . 21

3.3.2

Erzeugen eines Chord-Rings und Integration von Peers . . . . . 21

3.3.3

Die Nachfolgerliste . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.3.4

Verlassen und Reparatur des Chord-Rings . . . . . . . . . . . . 27

3.3.5

Aktualisierung der Fingertabelle . . . . . . . . . . . . . . . . . 28

3.4

Lastbalancierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.5

Sicherheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.6

Verwandte Arbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

i

4 Implementierung 4.1

4.2

4.3

Klassendesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 4.1.1

Die Klasse DHTNode . . . . . . . . . . . . . . . . . . . . . . . 32

4.1.2

Die Klasse Location . . . . . . . . . . . . . . . . . . . . . . . . 34

4.1.3

Die Klasse LookupKeyThread und LookupFingerThread . . . . 35

4.1.4

Die Klasse FingerTableStabilizer . . . . . . . . . . . . . . . . . 36

4.1.5

Die Klasse Stabilizer . . . . . . . . . . . . . . . . . . . . . . . . 37

4.1.6

Die Klassen DHTServer, PeerConnectionServer und -Client . . 38

4.1.7

Die Klasse RemoteMessage . . . . . . . . . . . . . . . . . . . . 40

4.1.8

Die Klasse Mediator . . . . . . . . . . . . . . . . . . . . . . . . 40

Kommunikation und Interaktion . . . . . . . . . . . . . . . . . . . . . 42 4.2.1

Betreten und Verlassen des Chord-Rings . . . . . . . . . . . . . 42

4.2.2

Durchf¨ uhrung von Lookups . . . . . . . . . . . . . . . . . . . . 43

4.2.3

Aktualisierung der Fingertabelle . . . . . . . . . . . . . . . . . 48

4.2.4

Ausf¨ uhrung des Stabilisierungsprotokolls . . . . . . . . . . . . . 49

Datenvolumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 4.3.1

Datenvolumen je Lookup . . . . . . . . . . . . . . . . . . . . . 52

4.3.2

Datenvolumen je Stabilisierung . . . . . . . . . . . . . . . . . . 53

5 Experimentelle Analyse 5.1

5.2

5.3

32

55

Der statische Chord-Ring . . . . . . . . . . . . . . . . . . . . . . . . . 55 5.1.1

Lookups im statischen Chord-Ring

. . . . . . . . . . . . . . . 55

5.1.2

Nachrichtenaufkommen durch Lookups . . . . . . . . . . . . . . 59

Der dynamische Chord-Ring . . . . . . . . . . . . . . . . . . . . . . . . 61 5.2.1

Lookups im dynamischen Chord-Ring . . . . . . . . . . . . . . 61

5.2.2

Systemstabilit¨ at . . . . . . . . . . . . . . . . . . . . . . . . . . 68

Bandbreitenverbrauch . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 5.3.1

Bandbreitenverbrauch durch Lookups . . . . . . . . . . . . . . 77

5.3.2

Bandbreitenverbrauch durch Stabilisierung . . . . . . . . . . . 80

5.3.3

Mindestbandbreitenverbrauch . . . . . . . . . . . . . . . . . . . 82

6 Zusammenfassung und Ausblick

83

A UML-Darstellungen

vii

B Auswertung der Experimente

ix

C Nachrichten und Nachrichtengr¨ oßen

xiii

ii

D Die Konfigurationsdatei

xvi

Literaturverzeichnis

xvii

iii

Abbildungsverzeichnis

2.1

Arbeitsweise von Napster . . . . . . . . . . . . . . . . . . . . . . . . .

6

2.2

Suchen mit Gnutella . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.3

Aufbau von Super-Peer-Netzwerken . . . . . . . . . . . . . . . . . . . . 10

2.4

2-dimensionales CAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.1

Chord-Ring, 10 Peers und 6 Keys . . . . . . . . . . . . . . . . . . . . . 16

3.2

Einfache Suche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.3

Fingertabelle von Peer 14 . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.4

Suche mit Hilfe der Fingertabelle . . . . . . . . . . . . . . . . . . . . . 20

3.5

Integration eines neuen Peers . . . . . . . . . . . . . . . . . . . . . . . 24

3.6

Zyklus beim Weiterleiten einer Suche . . . . . . . . . . . . . . . . . . . 27

4.1

UML-Klassendiagramm: DHTNnode . . . . . . . . . . . . . . . . . . . 33

4.2

UML-Klassendiagramm: Location . . . . . . . . . . . . . . . . . . . . . 34

4.3

UML-Klassendiagramm: LookupThreads . . . . . . . . . . . . . . . . . 36

4.4

UML-Klassendiagramm: PeerConnectionClient und -Server . . . . . . 39

4.5

UML-Klassendiagramm: Mediator . . . . . . . . . . . . . . . . . . . . 41

4.6

UML-Sequenzdiagramm: Durchf¨ uhrung von Lookups . . . . . . . . . . 46

4.7

UML-Sequenzdiagramm: Antwort auf Lookups . . . . . . . . . . . . . 48

4.8

UML-Sequenzdiagramm: Aktualisierung eines Fingers . . . . . . . . . 49

4.9

Vererbung der Nachfolgerliste . . . . . . . . . . . . . . . . . . . . . . . 50

5.1

Durchschnittlich Suchdauer im statischen Chord-Ring . . . . . . . . . 56

5.2

Pfadl¨ange: Suche im statischen Chord-Ring (absolut) . . . . . . . . . . 57

5.3

Pfadl¨ange: Suche im statischen Chord-Ring (prozentual) . . . . . . . . 58

5.4

Nachrichtenanzahl (KEY LOOKUP) . . . . . . . . . . . . . . . . . . . 60

5.5

Anteil fehlgeschlagener Suchen im dynamischen Chord-Ring . . . . . . 63

5.6

Durchschnittliche Suchzeit f¨ ur dynamische Chord-Ringe . . . . . . . . 65

iv

5.7 5.8 5.9 5.10 5.11 5.12 5.13 5.14 5.15 5.16 5.17 5.18

Pfadl¨ange f¨ ur 16 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . Pfadl¨ange f¨ ur 64 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . Durchschnittliche Pfadl¨ange in dynamischen Chord-Ringen . . . . . . Stabilit¨at im Join-Leave-Fall, tstab = 1.5s . . . . . . . . . . . . . . . . Vom Ring getrennte Peers im Join-Leave-Fall, tstab = 1.5s . . . . . . . Stabilit¨at im Join-Fail-Fall, tstab = 1.5s . . . . . . . . . . . . . . . . . . Vom Ring getrennte Peers im Join-Fail-Fall, tstab = 1.5s . . . . . . . . Stabilit¨at im Join-Fail-Fall, tstab = 3s . . . . . . . . . . . . . . . . . . . Vom Ring getrennte Peers im Join-Fail-Fall, tstab = 3s . . . . . . . . . Bandbreite pro Lookup . . . . . . . . . . . . . . . . . . . . . . . . . . Bandbreite in KB/s f¨ ur Lookups pro Sekunde . . . . . . . . . . . . . . Bandbreite Stabilisierung . . . . . . . . . . . . . . . . . . . . . . . . .

66 67 67 70 71 73 73 75 75 79 80 81

A.1 UML-Klassendiagramme (1) . . . . . . . . . . . . . . . . . . . . . . . . vii A.2 UML-Klassendiagramme (2) . . . . . . . . . . . . . . . . . . . . . . . . viii B.1 Pfadl¨ange f¨ ur 8 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.2 Pfadl¨ange f¨ ur 32 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . B.3 Pfadl¨ange f¨ ur 48 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten . . . . . . . . . . . . . . . . . . . . . . . . . . .

x x xi

v

Tabellenverzeichnis

2.1

Das Gnutella Protokoll . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.1

Beispiele f¨ ur RemoteMessages . . . . . . . . . . . . . . . . . . . . . . . 40

B.1 B.2 B.3 B.4

Pfadl¨ange: Suche im statischen Chord-Ring (absolut) . . Pfadl¨ange: Suche im statischen Chord-Ring (prozentual) Durch Lookups belegte Bandbreite . . . . . . . . . . . . Durch Stabilisierung belegte Bandbreite . . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

8

. ix . ix . xii . xii

C.1 Nachrichtenaufbau und -gr¨oße . . . . . . . . . . . . . . . . . . . . . . . xv D.1 Parameter der Konfigurationsdatei . . . . . . . . . . . . . . . . . . . . xvi

vi

1 Einleitung Viele im Internet verf¨ ugbare Dienste, wie z. B. das World Wide Web (WWW) oder das Domain Name System (DNS) [30], sind durch das Client-Server-Prinzip und eine hierarchische Organisationsstruktur gepr¨agt. In den letzten Jahren kommt jedoch zunehmend eine andere Organisationsform zur Anwendung: Peer-to-Peer-Systeme (P2P-Systeme). P2P-Systeme schließen ihre Teilnehmer (Peers) zu einem virtuellen Netzwerk innerhalb des Internets zusammen, in dem jeder Peer als Client teilnimmt und gleichzeitig aber auch als Server agiert, indem er einen Teil seiner Ressourcen zur Verf¨ ugung stellt. Durch dieses Prinzip werden die Kosten“ f¨ ur die Speicherung und Vertei” lung von im P2P-System gespeicherten Daten auf die einzelnen Peers verteilt, was P2P-Systeme besonders f¨ ur die Speicherung und Verteilung von große Datenmengen interessant macht. So erfreuen sich P2P-Systeme einer derart großen Beliebtheit, dass sie mittlerweile den gr¨oßten Teil des Datenaufkommens im Internet verursachen [20]. Die anf¨anglich verwendeten P2P-Systeme hatten jedoch noch Designschw¨achen, wie mangelnde Skalierbarkeit und hohen Bandbreitenverbrauch. Um diesem Problem zu begegnen, hat sich ein neuer Ansatz herausgebildet, der auf verteilten Hashtabellen beruht. Die meisten P2P-Systeme, die verteilte Hashtabellen verwenden, benutzen recht komplizierte und nicht immer intuitiv nachvollziehbare Such- bzw. Routingalgorithmen. Die Chord-Architektur [43] ist hier jedoch eine positive Ausnahme. Aus diesem Grund soll Chord im Rahmen dieser Arbeit genauer untersucht werden. Kapitel 2 beschreibt zun¨achst kurz die grundlegenden Eigenschaften von P2P-Systemen und gibt einen ¨ Uberblick u ¨ber die verschiedenen P2P-Ans¨atze. Im Anschluss daran beschreibt Kapitel 3 das Chord-Systemmodell und erkl¨art die verwendeten Algorithmen. Eine Beschreibung der im Rahmen dieser Arbeit entstandenen Implementierung von Chord sowie der wichtigsten Klassen erfolgt in Kapitel 4. Kapitel 5 besch¨aftigt sich mit der experimentellen Analyse des Chord-Algorithmus. Zum Abschluss fasst Kapitel 6 die

1

1 Einleitung Ergebnisse dieser Arbeit kurz zusammen und zeigt weitere Arbeitsfelder auf.

2

2 Einfu ¨hrung in Peer-to-Peer-Systeme

2.1 Was ist Peer-to-Peer? Die Idee von Peer-to-Peer-Netzwerken (P2P) ist es, Ressourcen wie Rechenleistung oder Speicherplatz miteinander zu teilen. Die teilnehmenden Hosts (Peers) k¨onnen auf die Ressourcen anderer Peers zugreifen und bezahlen“ daf¨ ur, indem sie einen ” Teil ihrer Ressourcen im P2P-Netzwerk zur Verf¨ ugung stellen.

Der Unterschied zum klassischen Client-Server-Design besteht darin, dass ein Peer sowohl Client als auch Server sein kann. Ein Peer agiert dabei als Client, wenn er auf Ressourcen anderer Peers zugreift, und er agiert als Server, wenn er Ressourcen im Netzwerk bereitstellt.

Die klassischen Client-Server-Architekturen wie das DNS [31, 30] sind durch einen hierarchischen Aufbau mit zentralen Servern gekennzeichnet. P2P-Architekturen verzichten darauf und organisieren die Peers dezentral. Das P2P-Netzwerk entsteht dadurch, dass die Peers in irgendeiner Weise“ innerhalb des Internet zu einem virtuellen ” Netzwerk verbunden werden, in dem jeder Peer potenziell alle Aufgaben u ¨bernehmen kann.

Dar¨ uber hinaus sind P2P-Systeme darauf ausgelegt, dass insbesondere auch Heimanwender mit ihren privaten PC’s daran teilnehmen k¨onnen. Da viele Heimanwender jedoch nicht st¨andig mit dem Internet verbunden sind, nehmen diese nicht permanent am P2P-Netzwerk teil, sondern nur dann, wenn sie auch mit dem Internet verbunden sind. Schaltet der Heimanwender seinen PC ab, oder trennt er die Internetverbindung, so f¨allt der entsprechende Peer im P2P-Netzwerk aus. Daher ver¨andert sich die Topologie des P2P-Netzwerks fortw¨ahrend.

3

2.2 Vor- und Nachteile von Peer-to-Peer-Systemen

2.2 Vor- und Nachteile von Peer-to-Peer-Systemen Einer der Vorteile von P2P ist, dass zentrale Server durch die Dezentralisierung entfallen. Dies ist insoweit ein Vorteil, da in Client-Server-Architekturen das Funktionieren des gesamten Systems haupts¨achlich vom Betrieb des Servers abh¨angt. Kommt es an dieser Stelle, dem so genannten single-point-of-failure, zu einem Fehler, so ist das gesamte System nicht mehr verf¨ ugbar. Eine weiterer entscheidender Vorteil von P2P-Systemen ist, dass durch zentrale Server bedingte Performanzprobleme entfallen. Den Flaschenhals (bottle neck ) f¨ ur die Leistung eines Client-Server-Systems stellt meistens der Server dar. Ist der Server ¨ u ugbar. Eine Uberlastung ¨berlastet, so ist meist das gesamte System nicht mehr verf¨ des Servers kann z. B. dadurch entstehen, dass zu viele Clients gleichzeitig auf die von ihm angebotenen Dienste zugreifen m¨ochten. In P2P-Systemen wird einer sol¨ chen Uberlastung entgegengewirkt, da hier hier die Systemlast auf mehreren Peers verteilt werden kann. Der gr¨oßte Vorteil von P2P-Architekturen ist aber, dass sie, da sie ohne zentrale Server auskommen, besser skalierbar sind als herk¨ommliche Client-Server-Architekturen, wodurch potenziell die Anzahl der Peers fast beliebig erh¨oht werden kann. Ein Nachteil von P2P-Architekturen liegt darin, dass sich die Topologie des Netzwerks st¨andig ver¨andert. Wird ein Peer vom P2P-Netzwerk getrennt, so sind damit die Ressourcen des ausgefallenen Peers nicht mehr ansprechbar. Da st¨andig Peers vom Netzwerk getrennt werden, lassen sich in der Regel keine verl¨asslichen Aussagen u ¨ber die Verf¨ ugbarkeit einer bestimmten Ressource treffen. Hinzu kommt, dass die einzelnen Peers wegen der dezentralen Organisation und der sich st¨andig ver¨andernden Topologie des P2P-Netzwerks, in der Regel nicht alle anderen Peers im Netzwerk kennen. Insbesondere liegt, bedingt durch die Dynamik, zu keinem Zeitpunkt ein vollst¨andiges Abbild des aktuellen Netzwerkzustandes vor. W¨ urde jeder Peer ein vollst¨andiges Abbild besitzen, so m¨ usste auch jeder Peer informiert werden, wenn sich der Netzwerkzustand ¨andert. Das wiederum w¨ urde aber einen sehr hohen Ressourcenverbrauch hervorrufen. Aus diesem Grund kennt jeder Peer nur einen begrenzten Teil des Netzwerks, wodurch sich das Auffinden von Ressourcen komplexer darstellt als in herk¨ommlichen Client-Server-Architekturen. Auf Grund dieser Problematik haben sich mit der Zeit unterschiedliche L¨osungsans¨ atze zur Organisation der Peers sowie der Lokalisierung von Ressourcen heraus¨ gebildet. Im folgenden wird ein kurzer Uberblick u ¨ber diese gegeben. Einen solchen

4

2.3 Verschiedene L¨osungsans¨atze ¨ Uberblick geben auch [4] und [7].

2.3 Verschiedene L¨ osungsans¨ atze Das gemeinsame Problem aller P2P-Systeme ist die Lokalisierung von Ressourcen, das so genannte Lookup Problem. Dieses wird in [7] so formuliert: Gegeben sei ein Datenelement X, das von einer dynamischen Teilmenge von Peers im System gespeichert wird. Finde X.1 Im Laufe der Zeit entstanden unterschiedliche Ans¨atze zur L¨osung des Lookup Problems. Neben hybriden P2P-Systemen, einer Mischform aus Client-Server und P2P, bei der die Peers bei der Ressourcensuche von einem zentralen Server abh¨angig sind, gibt es die echten P2P-Systeme. Charakteristisch f¨ ur echte P2P-Systeme ist, dass sie, zumindest auf physikalischer Ebene ohne zentrale Verzeichnisse arbeiten und ein verteiltes Suchprotokoll implementieren.

2.3.1 Hybride P2P-Systeme Hybride P2P-Systeme wie Napster [46] verzichten nicht vollst¨andig auf die ClientServer-Struktur. Sie f¨ uhren die Suche nach Ressourcen mit Hilfe von zentralen Verzeichnissen durch, welche auf einem Server hinterlegt sind. Jeder Peer registriert die von ihm bereitgestellten Ressourcen in diesem zentralen Verzeichnis. Sucht ein Peer nun nach einer bestimmten Ressource, so erh¨alt er aus dem zentralen Verzeichnis die Information, welcher Peer diese zur Verf¨ ugung stellt. Der eigentliche Zugriff auf die Ressource erfolgt dann u ur P2P-Systeme charakteristischen, direkten Kon¨ber den f¨ takt zum entsprechenden Peer. Abbildung 2.1 stellt die Arbeitsweise von Napster grafisch dar. Diese Arbeitsweise birgt den Vorteil, dass sie die sonst in P2P-Systemen vorhandenen Probleme wie das Auffinden von Ressourcen und Routing von Suchen umgeht. Auch l¨asst sich zumindest eine verl¨assliche obere Schranke f¨ ur die Dauer einer Abfrage angeben, da man hinreichend Informationen u ¨ber das Netzwerk und den Ablauf der Suche besitzt. Der Nachteil dieser hybriden Architektur besteht darin, dass sie nicht so gut skalierbar ist wie echte P2P-Systeme. Alle Peers greifen bei der Suche nach und der Registrierung von Ressourcen auf einen zentralen Server zu, wobei die maximale Peeranzahl 1

Given a data item X stored at some dynamic set of nodes in the system, find it.

5

2.3 Verschiedene L¨osungsans¨atze

Napster Server

X wird von A angeboten registriere X

suche X

benutze X

Peer A

Peer B

Abbildung 2.1: Arbeitsweise von Napster von der Leistungsf¨ahigkeit des Servers abh¨angt. Wenn der Server u ¨berlastet ist, dann k¨onnen keine Ressourcen mehr gefunden werden. Ein weiterer Nachteil ist, dass auch ein zentrales Verzeichnis immer einen single-point-of-failure darstellt, wodurch das System anf¨alliger f¨ ur Angriffe wie DoS-Attacken wird.2

2.3.2 Echte P2P-Systeme Bei den echten P2P-Systemen existieren wiederum zwei unterschiedliche L¨osungsans¨ atze, die unstrukturierten und die strukturierten. Sie unterscheiden sich dadurch, dass unstrukturierte Ans¨atze auf physikalischer wie auf konzeptioneller Ebene auf zentrale Verzeichnisse verzichten und die Peers einfach in irgendeiner Weise“ mit” einander verbunden sind, wobei strukturierte Ans¨atze auf konzeptioneller Ebene sehrwohl mit zentralen Verzeichnissen arbeiten und die Peers in einer bestimmten Weise“ ” miteinander verbinden. Eine Sonderstellung unter den echten P2P-Netzwerken nehmen so genannte SuperPeer-Netzwerke [47] ein. Diese sind eine Mischform aus unstrukturierten und hybriden 2

Als DoS-Angriff (Denial of Service) bezeichnet man einen Angriff auf einen Server, mit dem Ziel einen oder mehrere seiner Dienste arbeitsunf¨ ahig zu machen. In der Regel geschieht das durch ¨ Uberlastung, indem eine gr¨ oßere Anzahl Anfragen gestellt wird, als der Server gleichzeitig bearbeiten kann, woraufhin ein Dienst eingestellt wird oder regul¨ are Anfragen so langsam beantwortet werden, dass diese abgebrochen werden.

6

2.3 Verschiedene L¨osungsans¨atze P2P-Systemen. Sie sind der Versuch, die Nachteile von unstrukturierten Ans¨atzen abzumildern. Unstrukturierte Ans¨ atze Unstrukturierte P2P-Ans¨atze wie Gnutella [15] oder Freenet [10] verwenden keine bestimmte Ordnung f¨ ur die Peers. Bei dieser Art der Organisation kennt jeder Peer eine gewisse Anzahl von anderen Peers (Nachbarn). Insbesondere ist es so, dass kein Peer alle Peers im Netzwerk kennt, da das Auffinden sowie das Aktualisieren aller Peers das Netzwerk mit hoher Wahrscheinlichkeit auslasten w¨ urde. Betrachtet man nun das P2P-Netzwerk als Graphen, so ergeben sich zwei M¨oglichkeiten Ressourcen und andere Peers in einem P2P-Netzwerk aufzufinden: Tiefensuche und Breitensuche. Bei der Tiefensuche wird ein Pfad im Graphen bis zur maximalen Pfadl¨ange abgesucht. Hierzu wird die Suche von Peer zu Peer weitergeleitet. Bei jeder Weiterleitung w¨ahlt der Peer, der gerade die Nachricht erhalten hat, einen Peer unter den mit ihm verbundenen Peers aus, und leitet ihm die erhaltene Nachricht weiter. Hierdurch werden bei einer Suchtiefe r genau r Peers erreicht. Bei der Breitensuche leiten die Peers eine erhaltene Nachricht jeweils an alle mit ihnen verbundenen Peers weiter. Hierdurch werden bei einer Suchtiefe r alle Peers erreicht, die vom Ausgangspunkt der Suche innerhalb des Radius r liegen, d. h. die Peers, die maximal r Weiterleitungen entfernt sind. Bei beiden Arten der Suche wird jede f¨ ur die Suche versandte Nachricht wird mit einer time-to-live (TTL) versehen. Diese gibt an, wie oft eine Nachricht weitergeleitet werden darf und bestimmt somit die Suchtiefe bzw. den Radius der Suche. Bei jeder Weiterleitung wird diese um eins verringert. Gilt T T L = 0, so wird die Nachricht nicht mehr weitergeleitet. Gnutella verfolgt den Ansatz der Breitensuche. Mit ihr ist es m¨oglich, mit einer Suche eine große Anzahl anderer Peers zu erreichen. Wenn ein Peer z. B. mit durchschnittlich C = 5 Peers verbunden ist, eine eingehende Nachricht also an 4 Peers weitergeleitet wird, so werden innerhalb einer T T L = 7 maximal 109225 verschiedene Peers erreicht. TX TL

C ∗ (C − 1)i = 109225

i=0

Ein Gnutella Peer unterscheidet bei der Breitensuche zwischen dem Auffinden anderer bzw. neuer Peers sowie der Suche nach Ressourcen. Dementsprechend sieht das Gnutella Protokoll auch zwei unterschiedliche Nachrichten Ping und Query vor. Ta¨ belle 2.1 gibt einen Uberblick u ¨ber die Nachrichten des Gnutella Protokolls.

7

2.3 Verschiedene L¨osungsans¨atze Das Auffinden neuer Peers durch einen Peer x erfolgt durch Versenden der mit einer TTL versehenen Nachricht Ping an alle Peers, die x bereits bekannt sind. Erh¨alt nun Peer y eine Ping-Nachricht von x, so sendet er an Peer x die Antwort Pong. Diese Nachricht wird dabei u uckgeroutet. ¨ber den Weg, u ¨ber den sie gekommen ist, zur¨ Sofern die TTL der erhaltenen Ping-Nachricht gr¨oßer als Null ist, verringert y diese um Eins und leitet dann die Ping-Nachricht wiederum an alle ihm bekannten Peers weiter. Da es bei diesem Vorgehen zu Zyklen kommen kann, erh¨alt jede Nachricht zus¨atzlich einen Identifier. Anhand dieses Identifiers k¨onnen Peers schon einmal erhaltene und weitergeleitete Nachrichten erkennen. Somit k¨onnen Zyklen vermieden werden, da bekannte Nachrichten nicht mehr weitergeleitet werden.

Nachricht

Beschreibung

Ping

Suche nach anderen Peers

Pong

Antwort auf Ping

Query

Suche nach einer Ressource

QueryHit

Antwort auf Query

Push

Download von Peers hinter einer Firewall Tabelle 2.1: Das Gnutella Protokoll

Bei der Suche nach einer bestimmten Ressource, wird eine dem Auffinden neuer Nachbarn analoge Verfahrensweise angewandt. Der suchende Peer sendet die Nachricht Query an alle ihm bekannten Peers. Diese leiten die Suchanfrage dann wiederum an alle ihnen bekannten Peers weiter, bis die TTL der Suchanfrage abgelaufen ist. Wird dabei innerhalb des Radius TTL kein Peer erreicht, der die gesuchte Ressource zur Verf¨ ugung stellt, so ist die Suche erfolglos. Existiert jedoch ein Peer, der die Ressource bereitstellt, innerhalb des durch TTL festgelegten Radius, so sendet dieser die Nachricht QueryHit an den Initiator der Suche zur¨ uck. Die Antwort wird dabei u ¨ber die gleichen Peers geroutet, u ¨ber die auch die Query-Nachricht gesendet wurde. Abbildung 2.2 zeigt den Ablauf einer Suche bei der Peer A nach Ressource X sucht. Im ersten Schritt sendet A die Nachricht Query an die Peers B und E. Diese wiederum leiten die Suche im zweiten Schritt an die Peers C, B, E und F weiter. Da B und E die Suche schon einmal weitergeleitet haben, wird diese dort nicht noch einmal weitergeleitet. In n¨achsten Schritt leitet Peer F die Suche an Peer D und C

8

2.3 Verschiedene L¨osungsans¨atze

X

G

C GET X

F Query X

A

B

D X

E 1 Hop 2 Hops 3 Hops

G‘s QueryHit D‘s QueryHit

Abbildung 2.2: Suchen mit Gnutella weiter, w¨ahrend C die Suche an F und G weiterleitet. Da G und D die Ressource X anbieten, senden sie jeweils die Nachricht QueryHit zur¨ uck. Ein typischer Wert f¨ ur die von den meisten Gnutella Clients verwendete time-to-live ist T T L = 7. Diese wurde gew¨ahlt, da Gnutella Netzwerke die Eigenschaften von small-world Graphen besitzen, weshalb eine Suche mit hoher Wahrscheinlichkeit innerhalb dieses Radius erfolgreich verl¨auft [29, 22]. Der Vorteil von unstrukturierten P2P-Architekturen wie Gnutella ist, dass sie besser skalieren als hybride Systeme und keinen single-point-of-failure mehr besitzen. Nachteile bestehen jedoch u. a. darin, dass durch die bei Gnutella verwendete Breitensuche viele bzw. auch unn¨otige Nachrichten versendet werden, was große Mengen Netzwerkbandbreite belegt [40]. Im Beispiel von Abbildung 2.2 leitet z. B. Peer B die Suche nach Ressource X in dem Moment an Peer E weiter, in dem E die gleiche Suche umgekehrt an B weiterleitet. Neben dem hohen Bandbreitenverbrauch besteht ein weiterer Nachteil darin, dass durch die willk¨ urliche Anordnung der Peers keine effiziente Lastbalancierung (load-balancing) zwischen den Peers erfolgt. Super-Peer-Netzwerke Super-Peer-Netzwerke [47] sind eine Mischform zwischen unstrukturierten und hybriden P2P-Systemen. Das Ziel von Super-Peer-Architekturen ist es, den sehr hohen

9

2.3 Verschiedene L¨osungsans¨atze Bandbreitenverbrauch, der z. B. durch die von Gnutella verwendete Breitensuche entsteht, zu senken. Dies wird durch die Unterteilung des Netzwerks in Cluster erreicht. In einem Cluster ist die Arbeitsweise ¨ahnlich der von Napster. So gibt es innerhalb eines Clusters zwei unterschiedliche Arten von Peers: Super-Peers und Clients. Wie bei Napster agieren die Super-Peers innerhalb eines Clusters f¨ ur die Clients als zentrale Server. Sie besitzen Informationen u ¨ber alle im Cluster bereitgestellten Ressourcen. Die Clients registrieren die von ihnen bereitgestellten Ressourcen bei den SuperPeers. Untereinander sind die Cluster durch ihre jeweiligen Super-Peers miteinander verbunden. Die Anzahl der Peers im Cluster, inklusive der Super-Peers, wird mit cluster size bezeichnet.3 Abbildung 2.3 zeigt den Aufbau eines Super-Peer-Netzwerks aus 4 Clustern mit ihren Super-Peers SP1 bis SP4.

SP2

SP3

SP1

SP4

Abbildung 2.3: Aufbau von Super-Peer-Netzwerken Sucht ein Client eine Ressource, so stellt er seine Anfrage an den Super-Peer des eigenen Clusters. Dieser u uft zun¨achst, ob innerhalb des Clusters ein Peer existiert, ¨berpr¨ der die Ressource bereitstellt. Ist dies der Fall, so sendet er eine entsprechende Antwort an den suchenden Peer. Erst wenn kein solcher Peer existiert, leitet der SuperPeer die Suche an die mit ihm verbundenen Super-Peers weiter. Diese u ufen ¨berpr¨ dann wiederum, ob in ihrem Cluster ein Peer existiert, der die gesuchte Ressource 3

Das P2P-Netzwerk Gnutella stellt ein degeneriertes“ Super-Peer-Netzwerk mit cluster size = 1 ” dar.

10

2.3 Verschiedene L¨osungsans¨atze bereitstellt. Wird die gesuchte Ressource nun gefunden, so wird eine entsprechende Antwort an den fragenden Super-Peer gesendet, der dann den suchenden Peer in seinem Cluster verst¨andigt. Kann die Ressource wiederum nicht gefunden werden, so leiten die Super-Peers die Suche erneut an andere Super-Peers in anderen Clustern weiter. Ein Beispiel f¨ ur ein auf einer Super-Peer-Architektur beruhendes P2P-Netzwerk ist KaZaA [32]. Super-Peer-Netzwerke sind durch die Verwendung von Client-Server innerhalb der Cluster jedoch keine echten P2P-Netzwerke im eigentlichen Sinne. Nicht zuletzt ergeben sich innerhalb der Cluster wieder die f¨ ur Client-Server-Architekturen typischen Probleme bez¨ uglich Skalierbarbeit und Ausfallsicherheit.4 Strukturierte Ans¨ atze Im Gegensatz zu unstrukturierten und Super-Peer-Architekturen versuchen die strukturierten Ans¨atze, die Anzahl der Nachrichten und damit die belegte Bandbreite dadurch zu verringern, dass sie versuchen Ressourcen effizient“ zu lokalisieren. Um ” effizient bzw. strukturiert suchen zu k¨onnen, werden die Ressourcen zun¨achst in entsprechenden Index-Strukturen erfasst. Hierzu bedienen sich die einzelnen Ans¨atze unterschiedlicher Indexing-Mechanismen. Eine M¨oglichkeit der Indizierung sind Skip-Listen bzw. Skip-Graphen [5], wie sie von P-Grid [2] oder SkipNet [16] verwendet werden. Kern dieser Ans¨atze ist eine u ¨ber die Peers verteilte sortierte Liste, in der alle bereitgestellten Ressourcen erfasst sind. F¨ ur jede Ressource wird in dieser Liste ein String hinterlegt, der die Ressource beschreibt. Die so angelegte Liste wird mittels eines Suchbaumes indiziert, in dem sich das Pr¨afix der indizierten Strings mit zunehmender Suchtiefe verl¨angert. Ein anderer verbreiteter Ansatz zur Indizierung sind verteilte Hashtabellen (distributed hashtables - DHTs), die von etlichen Projekten [12, 38, 23, 49] verwendet werden. In einer Hashtabelle werden, wie in einem Array, Werte gespeichert. Der Unterschied zum Array besteht darin, dass die Werte nicht u ¨ber einen Index referenziert werden, sondern durch einen Schl¨ ussel, der mit Hilfe einer Hashfunktion aus dem Wert selbst berechnet wird. Als Werte selbst kann, je nach Implementierung des P2P-Systems, wiederum die Ressource selbst, oder eine Beschreibung, wie auf die Ressource zugegriffen werden kann, abgelegt werden. 4

vgl.: Abschnitt 2.3.1

11

2.3 Verschiedene L¨osungsans¨atze Im Fall von Dateien kann also z. B. der Schl¨ ussel festgelegt werden, indem mit der Hashfunktion der Hashwert des Dateinamens berechnet wird. Der zum Hashwert des Dateinamens gespeicherte Wert kann dann sowohl die Datei selbst sein, als auch eine Beschreibung des Peers, der die Datei bereith¨alt. Im Fall von Ressourcen wie CPUZeit, welche nicht von einem Peer zum anderen u ¨bertragen werden kann, muss als Wert jedoch zwingend eine Beschreibung des Peers gespeichert werden, welcher die CPU-Zeit bereitstellt.

Die Idee von verteilten Hashtabellen (DHTs) ist es nun, alle in einem P2P-Netzwerk bereitgestellten Ressourcen logisch in einer einzigen Hashtabelle zu erfassen, diese jedoch physikalisch u ¨ber die Peers zu verteilen. Dabei wird zun¨achst jedem Peer x ein eindeutiges Teilintervall [ix ..jx ] des Wertebereichs der Hashfunktion zugewiesen. Ein Peer speichert nun die Werte f¨ ur alle Schl¨ ussel key f¨ ur die gilt key ∈[ix ..jx ]. Die Art der Verteilung der DHT, das Auffinden des f¨ ur einen bestimmten Schl¨ ussel zust¨andigen Peers, sowie die dazu verwendeten Verteil- und Routingalgorithmen sind dabei jedoch sehr unterschiedlich. So benutzen z. B. die P2P-Systeme Pastry [39], Tapestry [18] und Kademlia [27] auf B¨aumen basierende Algorithmen, w¨ahrend Viceroy [26] auf Butterfly-Netzwerken [25] beruht. CAN [36] hingegen implementiert einen mehrdimensionalen Routingalgorithmus.

CAN (Content-Addressable-Network) benutzt eine mehrdimensionale Datenstruktur und unterteilt den Wertebereich f¨ ur die Schl¨ ussel in den d -dimensionalen Koordinatenraum eines d -Torus. Jeder Peer speichert Routinginformationen u ¨ber seine direkten Nachbarn im Koordinatenraum. Zwei Peers sind dabei benachbart, wenn ihre Koordinatenbereiche entlang d -1 Dimensionen u ¨berlappen und in einer Dimension aneinander grenzen. In einem d -dimensionalen Raum besitzt somit jeder Peer O(d ) Nachbarn. Bei der Suche wird ein greedy-Algorithmus angewandt: Liegt der gesuchte Schl¨ ussel nicht in der Koordinatenzone eines Peers, so leitet er die Suche an denjenigen seiner Nachbarn weiter, dessen Koordinatenzone am n¨achsten an der gesuchten liegt. Ist der d -dimensionale Raum in n Teile aufgeteilt und besitzt jeder Peer O(d ) Nachbarn, so wird eine Suche von O(dn1/d ) Peers weitergeleitet, bis sie ihr Ziel erreicht. Abbildung 2.4 zeigt ein CAN mit 2-dimensionalem [0,1]×[0,1] Koordinatenraum. Zur Vereinfachung wurde der entsprechende 2-Torus in die Ebene projiziert. Die Pfeile zeigen einen m¨oglichen Suchpfad f¨ ur eine von Peer 8 gestartete Suche nach Schl¨ ussel s=(0.6,0.6), welcher im Zust¨andigkeitsbereich von Peer 5 liegt.

12

2.4 Fazit

(0,1)

(1,1)

(0,0.25,0.75,1)

(0,0.25,0.5,0.75)

(0.5,0.75,0.75,1)

(0.75,1,0.75,1)

5

(0.75,1,0.5,0.75)

2

(0.25,0.5,0.5,0.75) (0.5,0.75,0.5,0.75)

6 1

3

(0.25,0.5,0.25,0.5)

(0.75,1,0.25,0.5)

7

8

4

9

(0,0.25,0,0.25)

(0.25,0.5,0,0.25)

(0.5,0.75,0,0.25)

(0,0)

(0.75,1,0,0.25)

(1,0)

Abbildung 2.4: 2-dimensionales CAN

2.4 Fazit Unter den verschiedenen P2P-Ans¨atzen erm¨oglichen es strukturierte Ans¨atze als einzige, verl¨assliche Aussagen u ugbarkeit einer Ressource zu ¨ber die tats¨achliche Verf¨ treffen, da der Peer, der f¨ ur den Schl¨ ussel, der die gesuchte Ressource beschreibt, verantwortlich ist, auf jeden Fall gefunden wird. Insbesondere ist es jedoch m¨oglich, Angaben dar¨ uber zu machen, u ¨ber wie viele Peers eine Suche weitergeleitet werden muss, bis die gesuchte Ressource gefunden wird. So wird in CAN eine Suche von O(dn1/d ) Peers weitergeleitet bis sie ihr Ziel erreicht, w¨ahrend Architekturen wie Kademlia erreichen, dass in Netzwerken mit n Peers eine Suche mit hoher Wahrscheinlichkeit O(log n) mal weitergeleitet werden muss.5 Skip-Listen basierte Algorithmen haben gegen¨ uber DHT basierten Ans¨atzen den Vorteil, dass die Sortierung der Strings, die die Ressourcen beschreiben, nicht durch eine Hashfunktion ver¨andert wird. So werden einander ¨ahnliche Ressourcen, also der Ressourcen deren Beschreibung mit dem gleichen Pr¨afix beginnt, von einander benach¨ barten Peers verwaltet, so dass eine Ahnlichkeitssuchen bzw. Range-Queries f¨ ur Ressourcen m¨oglich sind. DHT-Ans¨atze wiederum haben gerade durch die Verwendung der Hashfunktion den Vorteil, dass sie eine bessere Lastbalancierung (load-balancing) als Skip-Listen basierte Algorithmen unter den Peers herstellen, da die Hashfunktion die Zust¨andigkeit f¨ ur die Ressourcen besser auf die Peers verteilt [6].6 5 6

mit d = (log2 n)/2 ist auch bei CAN eine Pfadl¨ ange von O(log n) m¨ oglich vgl.: Abschnitt 3.4

13

2.4 Fazit

Eine Gemeinsamkeit den meisten strukturierten Ans¨atzen ist jedoch, dass sie nicht immer sehr intuitiv nachzuvollziehen sind und recht komplizierte Routingalgorithmen implementieren. Chord ist neben den bereits erw¨ahnten Ans¨atzen ein weiterer strukturierter DHT-Ansatz. Wie z. B. Kademlia bietet Chord dabei auch ein Routing in O(log n) Schritten, ist aber wesentlich intuitiver nachvollziehbar.

14

3 Der Chord-Algorithmus Chord ist ein strukturierter, auf verteilten Hashtabellen (DHT) beruhender P2PAnsatz. Unter den DHT-Ans¨atzen ist Chord einer der intuitivsten. Zur Verteilung der Schl¨ ussel auf die Peers nutzt Chord consistent hashing [21]. Chord stellt nur eine einzige Funktion zur Verf¨ ugung: die effiziente Lokalisierung von Schl¨ usseln. Dabei findet Chord aus n Peers den f¨ ur einen Schl¨ ussel zust¨andigen Peer in O(log n) Schritten. Hierbei ben¨otigt ein Peer Informationen u ¨ber O(log n) andere Peers.

3.1 Das Chord-Systemmodell Die Grundidee von Chord l¨asst sich folgendermaßen veranschaulichen: Die Peers werden in einer Ringstruktur, dem Chord-Ring organisiert. Hierzu erh¨alt jeder Peer x eine eindeutige m-bit lange IDx (ChordID). Daf¨ ur wird zun¨achst mit Hilfe eines Hash-Algorithmus wie SHA-1 [1] der Hashwert hx der IP-Adresse des Peers x berechnet. Die so gebildeten Hashwerte hx sind jedoch m¨oglicherweise l¨anger als m-bit und werden deshalb auf einen Ring IDx = hx mod 2m abgebildet. Der durch diese Abbildung entstehende Ring heißt Chord-Ring. Der dabei verwendete Parameter m heißt Exponent des Chord-Rings. Er bestimmt die maximal m¨ogliche Anzahl Peers N = 2m . Die ID des Peers x (x.ID) bestimmt, an welcher Stelle des Chord-Rings sich x befindet. Die Nachbarn, d.h. der Vorg¨anger (predecessor ) und der Nachfolger (successor ) von x, ergeben sich aus der auf den IDs definierten Ordnung. Der letzte Peer y f¨ ur den gilt y.ID < x.ID ist der Vorg¨anger von x (x.predecessor). Der Nachfolger z von x (x.successor) ist der erste Peer f¨ ur den gilt z.ID > x.ID. Die im DHT-Konzept vorgesehene Verteilung der Schl¨ ussel erfolgt bei Chord so, dass der Peer f¨ ur den Schl¨ ussel key zust¨andig ist, der key als erster auf dem Chord-Ring folgt. Schl¨ ussel key wird also dem ersten Peer x zugeordnet, f¨ ur den gilt: x.ID ≥ key. Der so bestimmte Peer x wird successor(key) genannt. Sei y = x.predecessor, dann gilt:

15

3.2 Das Auffinden von Schl¨ usseln im Chord-Ring ∀key ∈ (y.ID, x.ID] : successor(key) = x Abbildung 3.1 zeigt einen Chord-Ring mit dem Exponenten m = 6 und 10 Peers, die 6 Schl¨ ussel verwalten. So ist z. B. der Schl¨ ussel S34 Peer P35 zugeordnet, da P35 der erste Peer ist, der S34 folgt. P1

P62

S12

P57

P14

S57 S54

P53

P48

P22

P40 S24 P35

S28 S34

P31

Abbildung 3.1: Chord-Ring, 10 Peers und 6 Keys

3.2 Das Auffinden von Schl¨ usseln im Chord-Ring Die einzige Funktion, die Chord nach Außen bereitstellt, ist die Funktion lookup(key). Diese Funktion findet den f¨ ur den Schl¨ ussel key zust¨andigen Peer. Sucht Peer x nach Schl¨ ussel key, so wird der Suchprozess durch den Aufruf der Funktion x.lookup(key) gestartet. Im folgenden wird der genaue Ablauf der Suche beschrieben.

3.2.1 Einfache Suche Bei der einfachen Suche nach einem Schl¨ ussel key, wie sie von Algorithmus 1 durchgef¨ uhrt wird, u uft Peer x zun¨achst, ob sein Nachfolger der verantwortliche Peer ¨berpr¨ ist. Ist dies der Fall, so ist der Suchprozess beendet, das Ergebnis ist x.lookup(key) = x. Ist der Nachfolger von x jedoch nicht selbst verantwortlich, so fragt x seinen Nachfolger y = x.successor, indem er dessen Suchfunktion y.lookup(key) aufruft. Dies geschieht solange, bis der f¨ ur key zust¨andige Peer gefunden wurde.

16

3.2 Das Auffinden von Schl¨ usseln im Chord-Ring In einem Chord-Ring mit n Peers betr¨agt die Pfadl¨ange der Suche somit O(n), wobei die Pfadl¨ange angibt, wie oft der Lookup an einen anderen Peer weitergeleitet wurde. Abbildung 3.2 stellt den Verlauf der Suche dar, wenn Peer P14 den Schl¨ ussel 58 sucht und der Lookup jeweils an den Nachfolger weitergeleitet wird. Insgesamt wird die Suche 7 mal weitergeleitet.

Algorithmus 1 Einfache Suche x.lookup(key) if key ∈ (x.ID,successor.ID] return successor; else return successor.lookup(key);

Diese Art der Suche ist zwar intuitiv, jedoch nicht sehr effizient. Da die Pfadl¨ange f¨ ur die Suche linear zu der Anzahl der Peers im Chord-Ring steigt, steigt auch die Anzahl der Nachrichten linear mit der Anzahl der Peers an, so dass dieses Vorgehen die Skalierbarkeit eines Chord-Rings stark einschr¨ankt.

P1

P62

S12

P57 lookup(58) P14

S57 S54

P53

P48

P22

P40 S24 P35

S28 S34

P31

Abbildung 3.2: Einfache Suche

17

3.2 Das Auffinden von Schl¨ usseln im Chord-Ring

3.2.2 Skalierbare Suche mit Fingertabellen Eine M¨oglichkeit, effizienter als linear zur Anzahl der Peers zu suchen, besteht darin, Peers beim Weiterleiten einer Suche zu u ¨berspringen und so mit einer Weiterleitung gr¨oßere Stecken zur¨ uckzulegen. Hierzu muss ein Peer jedoch mehr Peers als nur seinen direkten Nachfolger kennen bzw. mehr u ¨ber die Verteilung der Peers im Chord-Ring wissen. Bei der skalierbaren Suche verwaltet deshalb jeder Peer eine Tabelle mit Informationen u ¨ber O(log N ) andere Peers im Chord-Ring. Die Eintr¨age dieser Tabelle heißen Finger, die Tabelle selbst heißt Fingertabelle. In Chord umfasst die Gr¨oße der Fingertabelle m Eintr¨age, wobei m der Exponent des Chord-Rings ist. Die Finger dienen bei der skalierbaren Suche als Sprungmarken zu anderen Peers im Chord-Ring. Mit ihrer Hilfe kann ein Lookup nun u ¨ber gr¨oßere Distanzen weitergeleitet werden. Der i -te Finger von x ist der Peer, der f¨ ur den Schl¨ ussel key verantwortlich ist, welcher i−1 um 2 gr¨oßer ist als der gr¨oßte Schl¨ ussel, f¨ ur den x verantwortlich ist. Der gr¨oßte Schl¨ ussel, f¨ ur den x verantwortlich ist, ist x.ID. Somit gilt f¨ ur die Fingertabelle von Peer x : x.f inger[i] = successor(keyi ) : keyi = x.ID + 2i−1 , i ∈ [0, m] Insbesondere gilt, dass der erste Finger von x der Nachfolger von x ist. x.f inger[0] = x.successor Mit dieser Strategie legt ein Lookup mit jeder Weiterleitung mindestens die H¨alfte der Distanz zum gesuchten Peer zur¨ uck. Abbildung 3.3 zeigt die Fingertabelle von Peer P14 sowie die Lage der f¨ ur die Finger berechneten Schl¨ ussel. Der entsprechende Finger ist immer der folgende Peer. So ist z. B. der f¨ ur Finger 6 berechnete Schl¨ ussel 6−1 P 14 + 2 = 46 und P48 der entsprechende Finger. Bei der skalierbaren Suche kommen die Methoden von Algorithmus 2 zum Einsatz. Ist der Nachfolger von Peer x nicht zust¨andig, so w¨ahlt er aus der Fingertabelle denjeussel key am nigen Finger aus (closest preceeding node(key)), der dem gesuchten Schl¨ n¨achsten ist und im Chord-Ring noch vor key liegt. An diesen leitet x den Lookup weiter. Mit jeder Weiterleitung wird so die Distanz zum gesuchten Peer mindestens halbiert. Hierdurch entspricht dies einer bin¨ aren Suche, welche bei einer Menge von n Eingabewerten, innerhalb von O(log n) Schritten beendet wird. Somit wird erreicht,

18

3.2 Das Auffinden von Schl¨ usseln im Chord-Ring

P1

P62

Finger Tabelle

P57

P14+1

P22

P14+2

P22

P14+4

P22

P14+8

P22

P14+16 P31 P14+32 P48

P14 P53

+1 +2 +32 +4

P48 +8

+16

P22

P40

P35 P31

Abbildung 3.3: Fingertabelle von Peer 14

Algorithmus 2 Skalierbare Suche x.lookup(key) if key ∈ (x.ID,successor.ID] return successor; else y = x.closest preceding node(key); return y.lookup(key); x.closest preceding node(key) for i = m downto 1 if finger[i].ID ∈ (x.ID, key) return finger[i]; return x;

19

3.3 Der Chord-Peer dass ein Lookup in einem Chord-Ring mit n Peers nur noch O(log n) mal weitergeleitet werden muss. Abbildung 3.4 zeigt den Verlauf einer Suche mit Hilfe der Fingertabelle. Sucht P14 nach Schl¨ ussel 58, so ist P48 der Peer in der Fingertabelle von P14, der Schl¨ ussel 58 am n¨achsten ist, weshalb dieser die Suche als n¨achstes erh¨alt. Aus der Fingertabelle von P48 ist P57 dem gesuchten Schl¨ ussel am n¨achsten, so dass P48 an P57 weiterleitet. Da der Nachfolger von P57 der zust¨andige Peer ist, wird die Suche erfolgreich beendet. Insgesamt wurde die Suche 2 mal weitergeleitet, w¨ahrend sie bei der einfachen Suche 7 mal weitergeleitet wurde. P1

P62

P57

Finger Tabelle P14+1

P22

P14+2

P22

P14+4

P22

P14+8

P22

P14+16 P31 P14+32 P48

P48+8

P14+32

P53

P14 lookup(58)

P48

P22

Finger Tabelle P48+1

P22

P48+2

P53

P48+4

P53

P48+8

P57

P40

P48+16 P1 P48+32 P22

P35 P31

Abbildung 3.4: Suche mit Hilfe der Fingertabelle

3.3 Der Chord-Peer P2P-Netzwerke wie Chord sind darauf ausgelegt, dass st¨andig Peers hinzukommen oder ausfallen k¨onnen. Da sich dabei die Topologie des Netzwerkes ¨andert, implementieren die Peers Algorithmen, die die Integration neuer Peers erm¨oglichen oder die Reparatur“ des Chord-Rings und der Fingertabellen vornehmen, wenn Peers ” ausfallen. Zusammen bilden diese Algorithmen das Chord-Stabilisierungsprotokoll.

20

3.3 Der Chord-Peer

3.3.1 Die Chord-Stabilisierungsalgorithmen Die Algorithmen des Chord-Stabilisierungsprotokolls werden von jedem Peer in periodischen Zeitabst¨anden aufgerufen. Der Zeitabstand zwischen zwei Durchf¨ uhrungen des Stabilisierungsprotokolls ist das Stabilisierungsintervall. Die Ausf¨ uhrung der Stabilisierungsalgorithmen findet im Hintergrund statt. Die Algorithmen des Stabilisierungsprotokolls sind: • x.stabilize(): Pr¨ uft, ob der Vorg¨anger y’ des Nachfolgers y von Peer x zwischen x selbst und seinem aktuellen Nachfolger y liegt. Ist der Vorg¨anger des Nachfolgers nicht der fragende Peer selbst (y 0 6= x), und liegt y’ zwischen x und y so ¨andert x seinen Nachfolger dementsprechend ab (x.successor = y 0 ).1 • y.getPredecessor(): Wird von x w¨ahrend x.stabilize() aufgerufen, wobei y der Nachfolger von x ist. Die Funktion liefert den Vorg¨anger y’ des Nachfolgers y.predecessor. • y.notify(x): Wird von x w¨ahrend x.stabilize() aufgerufen und k¨ undigt Peer y die Existenz von x an. Liegt x zwischen dem aktuellen Vorg¨anger y’ von y und y selbst, so wird x der neue Vorg¨anger von y (y.predecessor = x).2 • x.checkPredecessor(): Testet ob x.predecessor ausgefallen ist.3 • x.fix fingers(): Aktualisiert die Eintr¨age der Fingertabelle.4 Die Arbeitsweise dieser Funktionen wird im verbleibenden Teil dieses Abschnitts anhand von Beispielen erl¨autert. So dienen die Funktionen stabilize() sowie getbzw. check Predecessor() und notify() der Erhaltung und Wiederherstellung der korrekten Vorg¨anger-Nachfolger-Beziehungen wenn Peers hinzukommen oder ausfallen, w¨ahrend fix fingers() die Fingertabelle aktuell h¨alt.

3.3.2 Erzeugen eines Chord-Rings und Integration von Peers Dieser Abschnitt erl¨autert das Erzeugen eines neuen Chord-Rings mit zun¨achst nur einem Peer. Im Anschluss daran wird das Hinzuf¨ ugen weiterer Peers, sowie die Rolle, die das Stabilisierungsprotokoll dabei spielt, veranschaulicht. 1

siehe siehe 3 siehe 4 siehe 2

Algorithmus Algorithmus Algorithmus Algorithmus

5 5 6 7

21

3.3 Der Chord-Peer Erzeugen des Chord-Rings Soll ein neuer Chord-Ring erzeugt werden, so geschieht dies mit Hilfe der Funktion create(). Ruft ein Peer x diese Funktion auf, so wird damit ein neuer Chord-Ring, der nur aus Peer x besteht, erzeugt. In diesem Fall ist x f¨ ur alle Schl¨ ussel zust¨andig, dementsprechend ist x sein eigener Nachfolger (x.successor = x). Algorithmus 3 create()-Funktion x.create successor = x; predecessor = null;

Integration weiterer Peers Zur Integration eines Peers x in einen bestehenden Chord-Ring wird die Funktion join() benutzt. Hierbei muss Peer x bereits ein beliebiger Teilnehmer v des Rings bekannt sein.

Algorithmus 4 join()-Funktion x.join(v) predecessor = null; successor = v.lookup(x.ID); In Abbildung 3.5 werden die Phasen der Integration eines Peers P25 in einen bestehenden Chord-Ring gezeigt. Peer P25 belegt dabei den Platz zwischen den Peers P31 und P22. Zun¨achst erfragt P25 den Exponenten des Chord-Rings von einem beliebigen ihm bekannten Peer v des Chord-Rings. Danach ermittelt P25 seine eigene ID (P 25.ID = 25), indem er diese aus seiner IP-Adresse mittels der Hashfunktion und dem Exponenten bestimmt.5 Die ID von P25 gibt nun den Platz vor, welchen P25 sp¨ater im Chord-Ring belegt. Nachdem Peer P25 seine ID bestimmt hat, ermittelt er seinen Nachfolger. Dies geschieht, indem P25 den Peer bestimmt, der f¨ ur den Schl¨ ussel key = 25 zust¨andig ist. Hierzu ben¨otigt er nun Peer v, dessen Lookup-Funktion dazu benutzt wird, Peer P 31 = v.lookup(25) zu finden. Der so ermittelte Peer P31 ist der Nachfolger von P25, weshalb P25 den Zeiger P25.successor = P31 setzt (Abbildung 3.5b). Die Peers P25, P31 und P22 haben nun die folgenden Zust¨ande: 5

vgl.: Abschnitt 3.1

22

3.3 Der Chord-Peer Algorithmus 5 stabilize() und notify() x.stabilize() s = successor.get predecessor; if s ∈ (x.ID, successor.ID) then successor = s; successor.notify(x); x.notify(y) if predecessor == null or y.ID ∈ (predecessor.ID, x.ID) then predecessor = y;

P25.successor = P31 P31.successor P22.successor = P31

P25.predecessor = null P31.predecessor = P22 P22.predecessor

Nachdem P25 seinen Nachfolger P31 ermittelt hat, teilt er diesem mit, dass er annimmt, dessen neuer Vorg¨anger zu sein. Dies geschieht durch Aufruf der NotifyFunktion P31.notify(P25). Peer P31 erh¨alt diese Notify-Nachricht und pr¨ uft nun, ob P25 wirklich zwischen ihm und seinem aktuellen Vorg¨anger P22 liegt und somit als neuer Vorg¨anger u ¨bernommen werden kann (P 25.ID ∈ (P 22.ID, P 31.ID)). Ist dies der Fall, so ¨andert P31 seinen Vorg¨anger auf P 31.predecessor = P 25 ab (Abbildung 3.5c). Die Peers P25, P31 und P22 haben nun die folgenden Zust¨ande: P25.successor = P31 P31.successor P22.successor = P31

P25.predecessor = null P31.predecessor = P25 P22.predecessor

Zum jetzigen Zeitpunkt besitzen Peer P25 und Peer P22 noch den gleichen Nachfolger Peer P31. Damit die Integrit¨at des Chord-Rings wiederhergestellt wird und alle Peers auf den richtigen Nachfolger verweisen, muss P22 seinen Nachfolger auf den neu hinzugekommenen Peer P25 ab¨andern. Dies geschieht bei der n¨achsten Ausf¨ uhrung des Stabilisierungsprotokolls durch P22. Hierbei f¨ uhrt P22 die Funktion P22.stabilize() aus. Dabei fragt P22 den Vorg¨anger seines aktuellen Nachfolgers P31 durch P31.getPredecessor() ab. Hierdurch erh¨alt P22 die Information, dass Peer P25 der neue Vorg¨anger von P31 ist. Jetzt pr¨ uft P22, ob P25 tats¨achlich zwischen ihm und seinem aktuellen Nachfolger P31 liegt und somit als neuer Nachfolger u ¨bernommen werden kann (P 25.ID ∈ (P 22.ID, P 31.ID)). Ist

23

3.3 Der Chord-Peer dies der Fall, so setzt P22 seinen Nachfolger auf P 22.successor = P 25 (Abbildung 3.5d). Die Peers P25, P31 und P22 haben nun die folgenden Zust¨ande: P25.successor = P31 P31.successor P22.successor = P25

P25.predecessor = null P31.predecessor = P25 P22.predecessor

Zum Abschluss der Stabilisierung ruft P22 die Funktion notify() auf. Da er gerade seinen Nachfolger auf P25 abge¨andert hat, lautet der entsprechende Aufruf also P25.notify(P22). Da P25 bis zu diesem Zeitpunkt noch keinen Vorg¨anger besitzt, P1 P1 P1 P62 P62 auf P25.predecessor = P62 setzt P25 seinen Vorg¨anger P22 (Abbildung 3.5e). Die Peers P25, P31 und P22 haben nun die folgenden Zust¨ande: P57

P57

P53

P53

P48

P57

P25.successor = P31 P25.predecessor = P22 P14 P14 P31.successor P31.predecessor = P25 P53 P22.successor = P25 P22.predecessor

P48 P62

P48 P62

P1

P1

P22 P57

P14

P22

P22

P57

P40

P40

P40 P14

P14 P25

P25 P53

P53

P35

P35 (a) P48

P35 (b) P48

P31

(c)

P31

P31

P22

P40

P22

P40 P25 P35

P25 P35 (d)

P31

(e) P31

Abbildung 3.5: Integration eines neuen Peers Hiermit verweisen nun alle Vorg¨anger und Nachfolger der Peers P31, P25 und P22 auf die richtigen Peers. Die Integration von P25 ist somit abgeschlossen. Integration des zweiten Peers Die Integration des zweiten Peers in den Chord-Ring stellt einen Sonderfall dar. Wie schon erw¨ahnt besteht der Chord-Rings nach seiner Erzeugung zun¨achst aus nur

24

3.3 Der Chord-Peer einem Peer x, der sich selbst zum Nachfolger und keinen Vorg¨anger hat. Tritt nun ein zweiter Peer y in den Chord-Ring ein, so l¨asst y zun¨achst seinen Nachfolger von x bestimmen. Peer y erh¨alt auf diese Weise seinen Nachfolger Peer x. Zu diesem Zeitpunkt haben die Peers x und y die folgenden Zust¨ande: x.successor = x y.successor = x

x.predecessor = null y.predecessor = null

Bei der Ausf¨ uhrung des Stabilisierungsprotolls ruft y die Funktion x.getPredecessor() sowie die Funktion x.notify(y) auf. W¨ahrend x.getPredecessor() keine Ver¨anderung bei y bewirkt (x ist bereits der Nachfolger von y) so wird x durch den Aufruf von x.notify(y) dazu veranlasst, y zu seinem Vorg¨anger zu machen. Nun haben die Peers x und y die Zust¨ande: x.successor = x y.successor = x

x.predecessor = y y.predecessor = null

In diesem Zustand kommt es nun zu einem Stillstand. Da x sein eigener Nachfolger ist, ruft x bei der Durchf¨ uhrung des Stabilisierungsprotokolls x.getSuccesor() und x.notify(x) auf. Beide Aufrufe ¨andern weder den Zustand von x, noch den Zustand von y. Peer y ruft bei der Stabilisierung x.getSuccessor() und x.notify(y) auf. Auch hier ¨andern beide Aufrufe weder den Zustand von x noch den Zustand von y. Die korrekten Vorg¨anger-Nachfolgerbeziehungen zwischen den Peers werden also nicht hergestellt. Insbesondere wird x denken, dass er immer noch f¨ ur alle Schl¨ ussel verantwortlich ist, so dass es zu falschen Lookups kommt. Dieses Problem kann gel¨ost werden, indem x seinen Nachfolger auf y setzt, sobald y von ihm seinen Nachfolger bestimmen l¨asst. Hierzu verwendet y den normalen Lookup-Mechanismus. Wird jedoch der normale Lookup-Mechanismus verwendet, so besteht f¨ ur Peer x kein Unterschied zwischen der Bestimmung des Nachfolgers und der Suche nach einen Schl¨ ussel. Dementsprechend a¨ndert x auch seinen Nachfolger nicht direkt ab. Aus diesem Grund m¨ ussen konventionelle Lookups von der Suche nach dem Nachfolger unterscheidbar sein.6 Sind konventionelle Lookups von der Bestimmung des Nachfolgers unterscheidbar und erh¨alt x nun von y den Auftrag, dessen Nachfolger zu bestimmen, so ¨andert 6

vgl.: Abschnitt 4.2.1

25

3.3 Der Chord-Peer x seinen Nachfolger auf x.successor = y ab. Die Peers x und y haben somit die folgenden Zust¨ande: x.successor = y y.successor = x

x.predecessor = null y.predecessor = null

Nachdem x und y jeweils einmal das Stabilisierungsprotokoll ausgef¨ uhrt haben, besitzen beide die korrekten Vorg¨anger und Nachfolger. Das beschriebene Problem tritt jedoch nur in diesem speziellen Fall auf. Tritt nun ein dritter Peer z in den Chord-Ring ein, so f¨ uhrt das in Abschnitt 3.3.1 beschriebene Stabilisierungsprotokoll zu korrekten Ergebnissen.

3.3.3 Die Nachfolgerliste Das Funktionieren des Chord-Algorithmus basiert darauf, dass jeder Peer den korrekten Nachfolger kennt. Wenn z. B. im Chord-Ring aus Abbildung 3.6 Peer P22 ausf¨allt, besitzt P14 keinen Nachfolger mehr. Dar¨ uber hinaus wird er nicht wissen, dass P32 sein neuer Nachfolger ist. In der Folge wird P14 nicht wissen, dass er selbst f¨ ur Schl¨ ussel 30 verantwortlich ist. Einen entsprechenden Lookup wird er verwerfen, da die Finger P32 und P48 hinter dem gesuchten Schl¨ ussel liegen. F¨ ur den Fall, dass P14 dennoch den Lookup z. B. an P32 weiterleitet, wird P32 den Lookup gem¨aß seiner Fingertabelle an P1 weiterleiten. Da P22 ausgefallen ist, ist von den Fingern von P1 wiederum P14 dem gesuchten Schl¨ ussel 30 am n¨achsten, womit der Lookup wieder an seinem Ausgangspunkt angelangt. So k¨onnen falsche oder fehlende Nachfolger zu falschen Lookups, bzw. zu Zyklen f¨ uhren.7 Um Chord dahingehend robuster zu machen, besitzt jeder Peer nicht nur einen Nachfolger, sondern eine Liste mit den ersten j Nachfolgern. F¨allt der Nachfolger aus, so wird der erste nicht ausgefallene Peer in der Nachfolgerliste der neue Nachfolger. Der Fall, dass ein Peer keinen Nachfolger mehr hat, tritt somit nur noch dann ein, wenn alle j Nachfolger gleichzeitig ausfallen. Wenn jeder Peer mit der Wahrscheinlichkeit p ausf¨allt und jeder Peer j Nachfolger besitzt, dann ist die Wahrscheinlichkeit, dass ein Peer in seiner Nachfolgerliste keinen nicht ausgefallenen Nachfolger mehr findet gleich pj . Bei einer ausreichend langen Nachfolgerliste wird dadurch der Chord-Ring sehr robust. So zeigen die Autoren von [43], dass die Peers sogar dann 7

Beginnt P14 die Suche bei P48, so entsteht ebenfalls ein Zyklus, da P48 auch an P1 weiterleitet.

26

3.3 Der Chord-Peer P1

P62

Finger Tabelle P14+1

P22

P14+2

P22

P14+4

P22

P14

P14+8

P22

P14

P14+16 P32

P1+8

P14

P14+32 P48

P1+16

P22

P1+32

P35

Finger Tabelle P1+1

P57

P14

P1+2 P1+4

P14

P53

P48

P22

P40 Finger Tabelle

P35 P32

P32+1

P35

P32+2

P35

P32+4

P40

P32+8

P40

P32+16 P48 P32+32 P1

Abbildung 3.6: Zyklus beim Weiterleiten einer Suche mit hoher Wahrscheinlichkeit einen nicht ausgefallenen Nachfolger in der Nachfolgerliste finden, wenn die L¨ange der Nachfolgerliste j = Ω(logN ) betr¨agt und die Peers mit der Wahrscheinlichkeit p = 21 ausfallen. Da jederzeit neue Peers im Chord-Ring hinzukommen oder wegfallen k¨onnen, muss jeder Peer in regelm¨aßigen Zeitabst¨anden die Liste der Nachfolger aktualisieren. Anstatt die ersten j Nachfolger mit Hilfe der Lookup-Funktion8 zu bestimmen, gehen Peers bei der Aktualisierung davon aus, dass ihr Nachfolger generell aktuellere Informationen u ¨ber seine Nachfolger besitzt als sie selbst, da er diesen n¨aher ist und so wiederum von seinen Nachfolgern aktuellere Informationen bezieht. Aus diesem Grund aktualisieren die Peers ihre Nachfolgerliste, indem sie bei ihrem Nachfolger eine Kopie von dessen Nachfolgerliste beziehen. Aus dieser Liste wird der letzte Eintrag gel¨oscht und daf¨ ur der eigene Nachfolger, also der Spender“ der Liste, an der ” ersten Stelle eingef¨ ugt. Auf diese Weise beh¨alt die Nachfolgerliste die L¨ange j.

3.3.4 Verlassen und Reparatur des Chord-Rings Wie bereits erw¨ahnt, kommen in einem Chord-Ring nicht nur neue Peers hinzu. Die Peers k¨onnen auch absichtlich oder aber auch ohne vorherige Ank¨ undigung ausfallen. Letzteres kann z. B. dann eintreten, wenn Netzwerkverbindungen zwischen den Peers 8

succesori = lookup(successori−1 .ID + 1)

27

3.3 Der Chord-Peer ausfallen oder der Rechner abst¨ urzt“. In diesem Fall sorgen die Chord-Algorithmen ” daf¨ ur, dass alle Peers wieder die korrekten Nachfolger und Vorg¨anger erhalten, d. h. sich der bestehende Chord-Ring wieder stabilisiert. F¨allt z. B. wie Abbildung 3.6 Peer P22 aus, so wird P32 der neue Nachfolger von P14, da P32 der erste nicht ausgefallene Peer in der Nachfolgerliste von P14 ist. Bei der n¨achsten Durchf¨ uhrung des Stabilisierungsprotokolls ruft P32 neben stabilize() auch die Funktion check predecessor() auf. Damit erkennt P32, dass P22 ausgefallen ist und setzt seinen Vorg¨anger P32.predecessor = NULL. Bei der n¨achsten Durchf¨ uhrung des Stabilisierungsprotokolls durch P14 ruft dieser P32.notify(P14) auf. Damit erh¨alt P32 die Mitteilung, dass P14 der neue Vorg¨anger von P32 ist. Somit und setzt P32 seinen Vorg¨anger auf P32.predecessor = P14.

Algorithmus 6 check predecessor() x.check predecessor() if predecessor has failed predecessor = null;

Verl¨asst ein Peer x den Chord-Ring absichtlich, so kann dies von den verbleibenden Peers als Ausfall behandelt werden. Da x den Chord-Ring jedoch absichtlich verl¨asst, l¨asst sich der Chord-Algorithmus dadurch optimieren, dass x seine Nachbarn vorher dar¨ uber informiert“ dass er den Chord-Ring verl¨asst. Wenn u der Vorg¨anger und v ” der Nachfolger von x ist, so sendet x an u eine Nachricht mit dessen neuen Nachfolger v. Der Nachfolger v erh¨alt dementsprechend eine Nachricht mit seinem neuen Vorg¨anger u. Dies ist vor allem aber auch deshalb sinnvoll, da ein Peer die Schl¨ ussel, f¨ ur die er verantwortlich ist, vor Verlassen des Chord-Rings an einen anderen Peer u ¨bertragen sollte.

3.3.5 Aktualisierung der Fingertabelle Da sich die Topologie des Chord-Rings ver¨andern kann, ist es m¨oglich, dass Eintr¨age der Fingertabelle auf nicht mehr existierende Peers verweisen oder dass ein neuer Peer zwischen den Fingern i − 1 und i in den Chord-Ring integriert wurde. Um die Korrektheit der Fingertabelle sicherzustellen, muss in beiden F¨allen eine Aktualisierung der Fingertabelle vorgenommen werden. Aus diesem Grund werden die Eintr¨age der Fingertabelle wie in Algorithmus 7 in regelm¨aßigen Abst¨anden aktualisiert, wobei

28

3.4 Lastbalancierung bei jeder Aktualisierung jeweils nur ein Finger i aktualisiert wird. Der Finger i von Peer x wird dabei durch eine Suche nach dem Schl¨ ussel keyi = x.ID + 2i−1 ermittelt. finger[i] = lookup(x.ID + 2i−1 ) Algorithmus 7 Aktualisieren der Fingertabelle x.fix fingers() i = i + 1; if i > m i = 1; finger[i] = lookup(x.ID + 2i−1 ); Das Aktualisieren der Finger wird unabh¨angig von eventuellen anderen Suchen im Hintergrund ausgef¨ uhrt. Da in jedem Durchlauf nur ein Finger aktualisiert wird, dauert es bei einer Fingertabelle mit m Eintr¨agen m Zeitintervalle bis alle Finger aktualisiert wurden.

3.4 Lastbalancierung Durch die Verwendung einer Hashfunktion wie SHA-1 sind die berechneten ChordIDs mit hoher Wahrscheinlichkeit gleichm¨aßig auf dem Chord-Ring verteilt. Dadurch ist jeder Peer f¨ ur ann¨ahernd die gleiche Anzahl Schl¨ ussel zust¨andig. Setzt man voraus, dass alle Schl¨ ussel mit der gleichen H¨aufigkeit gesucht werden, dann erh¨alt jeder Peer ungef¨ahr die gleiche Anzahl an Lookups, und es kommt zu einen guten Lastbalancierung load-balancing zwischen den Peers. Meistens sind jedoch nicht alle Ressourcen bei den Benutzern des P2P-Netzwerks gleich popul¨ar. So ist es z. B. sehr wahrscheinlich, dass in einem P2P-Netzwerk, dass dem Austausch von Musikdateien dient, der Schl¨ ussel besonders h¨aufig gesucht wird, der den Titel beschreibt, der gerade an der Spitze der H¨orercharts steht. Hierdurch werden, unabh¨angig davon, dass jeder Peer f¨ ur die gleiche Anzahl an Schl¨ usseln verantwortlich ist, die Peers, die f¨ ur popul¨are Schl¨ ussel verantwortlich sind, wesentlich st¨arker belastet als andere. Man spricht in diesem Zusammenhang von Routing Hot Spots. Es existieren zwei Strategien mit denen es m¨oglich ist, die Belastung einzelner Peers durch Routing Hot Spots zu verringern [36]: • Caching: Beim Caching speichern die Peers zus¨atzlich zu den Schl¨ usseln, die sie selbst verwalteten, die Schl¨ ussel, nach denen sie in letzter Zeit selbst gesucht

29

3.5 Sicherheit haben. Erreicht sie dann eine Suche nach einem solchen Schl¨ ussel, so k¨onnen die Peers direkt antworten, so dass der Lookup nicht mehr weitergeleitet werden muss. Da die Peers die Schl¨ ussel cachen, die sie selbst gesucht haben, werden so gerade popul¨are Schl¨ ussel von vielen Peers gespeichert. • Replikation: Durch Replikation kann ein Peer x einen popul¨aren Schl¨ ussel bei seinen Nachbarn replizieren, so dass diese dann auch daf¨ ur zust¨andig sind. Diese k¨onnen dann wiederum den Schl¨ ussel bei ihren Nachbarn replizieren, so dass im Idealfall die gesamte Umgebung von x f¨ ur den Schl¨ ussel verantwortlich ist und sich die Last gleichm¨aßig darin verteilt. Ein Umstand, der ein effektives load-balancing erschwert, sind heterogene Peer Populationen.9 Es sollte m¨oglich sein, dass leistungsf¨ahigere Peers f¨ ur mehr Schl¨ ussel verantwortlich sind als Peers mit geringer Leistung. Dies kann z. B. dadurch erreicht werden, indem jeder Peer mehrere virtuelle Peers ausf¨ uhrt, wobei die Schl¨ ussel bzw. die Hashtabelle gleichm¨aßig unter den virtuellen Peers aufgeteilt werden. Leistungsstarke Peers k¨onnen die Gesamtanzahl der Schl¨ ussel f¨ ur die sie zust¨andig sind, dadurch erh¨ohen, indem sie mehr virtuelle Peers ausf¨ uhren als leistungsschwache Peers.

3.5 Sicherheit Die hier beschriebene Spezifikation von Chord geht nicht auf m¨ogliche Schwachstellen ein, die ein Angreifer ausnutzen k¨onnte. In [41] werden verschiedene denkbare Attacken vorgestellt. Suchen sind z. B. dadurch verwundbar, dass ein Peer b¨oswillig falsche Routinginformationen zur¨ uck liefert oder indem er einen Lookup einfach nicht weiterleitet. Die Integrit¨at eines Chord-Rings l¨asst sich durch h¨aufiges Eintreten und schnelles Verlassen des Rings beeintr¨achtigen. Wie sich das auswirkt, wird u. a. in Kapitel 5 untersucht. Ein Effekt einer solchen Attacke ist, dass sich die Bereiche, f¨ ur die die Peers zust¨andig sind, st¨andig ¨andern. Deshalb m¨ ussen permanent große Mengen an Schl¨ usseln und den dazu geh¨orenden Informationen zwischen den Peers ausgetauscht ¨ werden. Dies kann zu einer Uberlastung von Teilen des Netzwerks f¨ uhren. Hierdurch kann es dann wiederum zur Verz¨ogerung von Lookups kommen. Eine weitere Auswirkung einer solchen Attacke ist, dass es vermehrt zu nicht mehr aktuellen Eintr¨agen in den Fingertabellen kommen kann und ein Lookup ¨ofter weitergeleitet werden muss, d. h. dass die Pfadl¨ange f¨ ur den Lookup ansteigt. 9

In heterogenen Populationen besitzen nicht alle Peers die gleiche Hardwareausstattung. So beobachtet [40] besonders bei der Netzwerkbandbreite große Unterschiede.

30

3.6 Verwandte Arbeiten

3.6 Verwandte Arbeiten S-Chord [28] ist eine Erweiterung von Chord. Im Unterschied zu Chord kann hier ein Lookup nicht nur an den Nachfolger weitergeleitet werden, sondern auch an den Vorg¨anger. Somit erzielt S-Chord eine gegen¨ uber Chord um bis zu 25% verringerte Pfadl¨ange bei Lookups. Durch die Verwendung dieses symmetrischen Routingprotokolls besitzt S-Chord besondere Eigenschaften wie die der routing-entry-symmetry. Das bedeutet, dass f¨ ur zwei beliebige Peers x und y gilt: Zeigt von x ein Finger auf y, so zeigt auch einer von y auf x. Die routing-entry-symmetry erm¨oglicht eine schnellere Aktualisierung der Fingertabellen durch in-place-notification. Das bedeutet, dass ein Peer x, der absichtlich das Netzwerk verl¨asst, alle Peers deren Finger auf x zeigen, dar¨ uber informieren kann. Die informierten Peers k¨onnen dann direkt ihre Fingertabellen entsprechend ab¨andern. Neben Erweiterungen von Chord existieren auch auf Chord basierende P2P-RoutingAlgorithmen. Koorde [19] ist ein solcher auf Chord basierender Routing Algorithmus, der de Bruijn Graphen [13] verwendet. Wie Chord erreicht dieser Algorithmus in einem Netzwerk mit n Peers eine Pfadl¨ange f¨ ur Lookups von O(log n). Im Unterschied zu Chord erreicht Koorde diese Schranke jedoch mit Informationen u ¨ber nur zwei weitere, also O(1) Peers, jedoch sind die M¨oglichkeiten der Lastbalancierung einschr¨ankt und die verwendeten Algorithmen weniger intuitiv als bei Chord.

31

4 Implementierung Dieses Kapitel dient der Erl¨auterung der im Rahmen dieser Arbeit durchgef¨ uhrten Implementierung des in Kapitel 3 vorgestellten Chord-Protokolls. Es beschr¨ankt sich dabei auf die wichtigsten Klassen sowie die grundlegenden Merkmale des Klassendesigns. Zur grafischen Darstellung der wichtigsten Sachverhalte wurde die Unified Modeling Language (UML) [42] verwendet. Die vorliegende Implementierung realisiert die effiziente Lokalisierung von Schl¨ usseln, und somit die Grundlagen einer auf einer verteilten Hashtabelle beruhenden P2PAnwendung. Die Architektur einer auf Chord basierenden P2P-Anwendung, wird in [11] skizziert. Die Implementierung von Chord erfolgte in Java und bildet das in sich abgeschlossene Package Chord. Insgesamt besteht die Implementierung aus rund 6100 Zeilen JavaQuellcode, wobei ca. 1600 Zeilen auf Testklassen entfallen, welche der Durchf¨ uhrung und Auswertung der in Kapitel 5 beschriebenen Experimente dienten. Neben der im Rahmen dieser Arbeit durchgef¨ uhrten Java-Implementierung existiert bereits eine in C++ durchgef¨ uhrte Implementierung, die f¨ ur CFS (Cooperative File System)[12] verwendet wird. Diese kann unter [34] bezogen werden.

4.1 Klassendesign Im Folgenden werden die wichtigsten Klassen des Packages Chord kurz dargestellt. Im Einzelnen sind das die Klassen: DHTNode, Location, LookupKeyThread, LookupFingerThread, FingerTableStabilizer, Stabilizer, DHTServer, PeerConnectionServer, PeerConnectionClient, RemoteMessage und Mediator.

4.1.1 Die Klasse DHTNode Die Klasse DHTNode ist die zentrale Klasse von Chord. Sie bildet einen Chord-Peer mit seinen einzelnen Komponenten wie Nachfolgerliste und Fingertabelle ab und stellt

32

4.1 Klassendesign die Funktionen, die außerhalb des Packages Chord verf¨ ugbar sind, bereit. Ein Chord-Peer besitzt eine Nachfolgerliste successors vom Typ SuccessorList und eine Fingertabelle fingertable vom Typ FingerTable. Die Aktualisierung der Fingertabelle und die Ausf¨ uhrung des Stabilisierungsprotokolls erfolgen durch die eigenst¨andigen Threads fstabilizer und stabilizer, Instanzen der Klasse Stabilizer bzw. FingerTableStabilizer. Wird ein Chord-Peer von einem anderen Chord-Peer kontaktiert, so wird die eingehende Verbindung von Komponente serverclass einer Instanz der Klasse DHTServer angenommen. Eine detaillierte Beschreibung der Klassen Stabilizer, FingerTableStabilizer und DHTServer erfolgt in den gleichnamigen Abschnitten dieses Kapitels.1 DHTNode successors: SuccessorList fingertable: FingerTable mediator: Mediator stabilizer: Stabilizer fstabilizer: FingerTableStabilizer serverclass: DHTServer DHTNode() create() join(in Location) lookup(in long) getAppPort() setAppPort(in int) finalize() isConnected()

Abbildung 4.1: UML-Klassendiagramm: DHTNnode Die vom Chord-Peer durch die Klasse DHTNode bereitgestellten Funktionen sind: Suche nach Schl¨ usseln (lookup()), Instantiieren eines neuen Chord-Rings (create()), Eintritt in einen bestehenden Chord-Ring (join()) und Verlassen des Chord-Rings (finalize()). Chord ist eine reine Lookup-Anwendung, die von anderen P2P-Anwendungen zur Lokalisierung von Schl¨ usseln bzw. zur Lokalisierung der f¨ ur die Schl¨ ussel verantwortlichen Peers genutzt wird. M¨ ochte eine P2P-Anwendung mit einer anderen P2PAnwendung direkt kommunizieren und Daten austauschen, so ben¨otigt sie daf¨ ur 1

Die Klassen SuccessorList und FingerTable dienen ausschließlich der Kapselung der Referenzen auf die jeweiligen Peers und stellen außer get- und set-Methoden keine weitere Funktionalit¨ at bereit.

33

4.1 Klassendesign einen von Chord unabh¨angigen Kommunikationskanal bzw. Netzwerkport. Da die Peers jedoch nur auf der Ebene von Chord (Chordebene) und nicht auf der Ebene der auf Chord beruhenden P2P-Anwendung (Anwendungsebene) von der Existenz anderer Peers erfahren k¨onnen, muss der auf Austausch, des auf Anwendungsebene zum Einsatz kommenden Netzwerkports, auf Chordebene stattfinden. Aus diesem Grund implementiert DHTNode, zus¨atzlich zur eigentlichen Chord-Funktionalit¨at, ¨ die Funktion setAppPort(). Diese erm¨oglicht die Ubergabe des auf Anwendungsebene benutzten Netzwerkports (ApplicationPort) an den Chord-Peer. Des Weiteren ist es auf Anwendungsebene wichtig zu wissen, ob der benutzte ChordPeer u ¨berhaupt mit dem Chord-Ring verbunden ist. Aus diesem Grund wurde die Funktion isConnected() implementiert. Durch sie l¨asst sich u ufen, ob der DHT¨berpr¨ Node mit dem Chord-Ring verbunden ist.

4.1.2 Die Klasse Location Ein Objekt der Klasse Location bildet die Adresse“ eines Peers ab und dient da” mit der Beschreibung eines Chord-Peers. Zur Adresse eines Chord-Peers geh¨oren die ChordID des Peers, sowie die IP-Adresse und der (Chord-)Port, auf dem der abgebildete Peer von anderen Peers kontaktiert werden kann.

Location Location() setChordPort() getChordPort() setChordId() getChordId() setIP() getIP() setApplicationPort() getApplicationPort()

Abbildung 4.2: UML-Klassendiagramm: Location Da in Location alle wichtigen Informationen u ¨ber einen Peer erfasst sind, eignet sich diese Klasse zur Speicherung von Zeigern auf andere Peers. So werden der Vorg¨anger sowie die Nachfolger und die Finger eines Peers durch Objekte der Klasse Location repr¨asentiert. Ferner bietet sich Location als Informationstr¨ager bei der Ausf¨ uhrung des Stabilisierungsprotokolls an. Wird z. B. ein Peer nach seinem Vorg¨anger gefragt, so versendet er als Antwort darauf ein Objekt der Klasse Location, welches

34

4.1 Klassendesign den Vorg¨anger beschreibt. Neben dem Stabilisierungsprotokoll verwendet auch der Lookup-Mechanismus die Klasse Location. Hierbei wird Location einerseits verwendet, um in der Lookup-Nachricht den Ausgangspunkt des Lookups zu vermerken, andererseits ist der R¨ uckgabewert von DHTNode.lookup() vom Typ Location. Da der R¨ uckgabewert von DHTNode.lookup() vom Typ Location ist, ist Location neben DHTNode die einzige Klasse, die Funktionen bereitstellt, die außerhalb des Packages Chord aufgerufen werden k¨onnen. So kann eine auf Chord basierende P2PAnwendung mit den Funktionen getIP() und getApplicationPort() die Daten (IPAdresse, ApplicationPort) aus dem von DHTNode.lookup() zur¨ uckgegebenen Objekt Location herauslesen, die auf Anwendungsebene ben¨otigt werden, um auf die gesuchte Ressource zuzugreifen.2

4.1.3 Die Klasse LookupKeyThread und LookupFingerThread Die Klasse LookupKeyThread implementiert die Suche nach Schl¨ usseln. Die Realisierung dieser Klasse als Thread war deshalb n¨otig, da das Auffinden von Fingern ebenfalls u usseln erfolgt. W¨are die Suche nicht als Thread ¨ber die Suche nach Schl¨ realisiert, so h¨atte die Aktualisierung der Finger den Suchmechanismus blockiert“. ” Ein Benutzer h¨atte dann w¨ahrend der Aktualisierung eines Fingers keine Lookups durchf¨ uhren k¨onnen. H¨atte ein Benutzer auf der anderen Seite einen Lookup durchgef¨ uhrt, so w¨are die Aktualisierung der Finger f¨ ur diese Zeit nicht m¨oglich gewesen. Durch die Realisierung als Thread k¨onnen mehrere Schl¨ ussel gleichzeitig gesucht werden, so dass die Aktualisierung der Finger parallel zu den vom Benutzer durchgef¨ uhrten Suchen ablaufen kann. Bei der Durchf¨ uhrung des Lookups selbst wird zun¨achst eine Instanz von LookKeyThread erzeugt und mit run() gestartet. Zur eigentlichen Durchf¨ uhrung des Lookups wird die Methode lookup() aufgerufen. Ist die Suche erfolgreich, so gibt lookup() ein Objekt vom Typ Location zur¨ uck, welches den verantwortlichen Peer beschreibt. Ist die Suche nicht erfolgreich, liefert lookup() den Wert NULL. Die maximale Pfadl¨ange, die ein Lookup erreichen kann, wurde begrenzt, da wie bereits in Abschnitt 3.3.3 gezeigt, in einem Chord-Ring Zyklen entstehen k¨onnen, so dass ein Lookup permanent zwischen zwei oder mehreren Peers hin- und her gesen2

Der ApplicationPort wird u ¨ber die Methode setAppPort() der Klasse DHTNode gesetzt, vgl. Abschnitt 4.1.1

35

4.1 Klassendesign LookupFingerThread LookupKeyThread

mediator: Mediator

result: boolean

fingerkey: long

mediator: Mediator

fingerindex: int

LookupKeyThread(in Mediator)

LookupFingerThread(in Mediator, in FingerTableStabilizer)

setResult()

setFingerindex(in int)

lookup(in long)

setFingerkey(in long)

run()

updateFinger() run()

Abbildung 4.3: UML-Klassendiagramm: LookupThreads ¨ det wird. Der zust¨andige Peer dabei jedoch nie erreicht. Um eine Uberlastung der Peers durch das Weiterleiten solcher toter Lookups“ zu vermeiden, werden diese ” nach maximal 2m Schritten nicht mehr weitergeleitet. Dies ist ein sinnvoller Wert, da Chord eine Pfadl¨ange von O(log n) verspricht, wobei n ∈ N ∧ N = 2m . Es ist also sehr wahrscheinlich, dass ein Lookup innerhalb von 2m Schritten sein Ziel erreicht. Die Klasse LookupFingerThread wurde von LookupKeyThread abgeleitet und hinsichtlich der Aktualisierung der Finger erweitert. So wird vor der Suche der Index des zu aktualisierenden Fingers u ussel ¨ber setFingerindex() und der zu suchende Schl¨ durch setFingerkey() u ¨bergeben. Gestartet wird der Thread durch den Aufruf der Methode run(). Die von run() aufgerufene Methode updateFinger() ruft sodann die von LookupKeyThread geerbte Funktion lookup() auf, welche den gesuchten Finger zur¨ uck gibt. Das Ergebnis wird anschließend durch Aufruf der Methode Mediator.setFinger() in die Fingertabelle geschrieben.3

4.1.4 Die Klasse FingerTableStabilizer Die Klasse FingerTableStabilizer dient der regelm¨aßigen Aktualisierung der Fingertabelle. Diese Klasse wurde, wie die Suche der Finger selbst, als eigenst¨andiger Thread konzipiert, da auch die Aktualisierung der Fingertabelle unabh¨angig von eventuellen Benutzerinteraktionen ausgef¨ uhrt werden muss. Die von java.lang.Thread geerbte Methode run() wurde so implementiert, dass sie in regelm¨aßigen Zeitabst¨anden eine Instanz von LookupFingerThread erzeugt, die einen 3

vgl:: Abschnitt 4.1.8

36

4.1 Klassendesign der Finger aktualisiert. Soll Finger i des Peers x aktualisiert werden, so wird zun¨achst eine Instanz von LookupFingerThread erzeugt. Anschließend werden dieser Instanz der Index des Fingers und der entsprechende zu suchende Schl¨ ussel mit den Methodenaufrufen setFingerini−1 dex(i) und setFingerKey(x.ID +2 ) u ¨bergeben. Nun wird der Thread durch Aufruf der Methode run() gestartet. Dieser sucht dann selbst¨andig den gew¨ unschten Finger und aktualisiert den entsprechenden Eintrag in der Fingertabelle. Dadurch, dass f¨ ur jeden zu aktualisierenden Finger ein eigener Thread gestartet wird, der selbst¨andig den entsprechenden Peer sucht und dann den Eintrag in der Fingertabelle ab¨andert, kann die Aktualisierung von Finger i + 1 unabh¨angig von der Aktualisierung des Fingers i durchgef¨ uhrt werden. Dies hat den Vorteil, dass es nicht vorkommen kann, dass sich die Aktualisierung von Finger i + 1 dadurch verz¨ogert, dass die Aktualisierung von Finger i noch nicht abgeschlossen ist, weil der entsprechende Peer noch nicht gefunden wurde. Diese voneinander unabh¨angige und mitunter parallele Aktualisierung der Finger ist aber nur dann m¨oglich, wenn auch die Suche nach Schl¨ usseln parallel erfolgen kann, wie es durch die Implementierung von LookupKeyThread und LookupFingerThread erm¨oglicht wird. Das Zeitintervall, das zwischen der Aktualisierung von Finger i und i+1 ist in einer Konfigurationsdatei einstellbar. Es wird in Millisekunden u ¨ber den Parameter FIX FINGERS INTERVAL angegeben.4

4.1.5 Die Klasse Stabilizer Die Klasse Stabilizer dient der Ausf¨ uhrung des Stabilisierungsprotokolls (Stabilisierung) wie es bereits in Abschnitt 3.3.1 beschrieben wurde. Die Stabilisierung wird in regelm¨aßigen Zeitabst¨anden ausgef¨ uhrt. Sie stellt die Korrektheit des Nachfolgers und des Vorg¨angers sicher, indem ein neu hinzugekommener Peer zwischen dem Peer selbst und seinem Nachfolger zum neuen Nachfolger gemacht wird. Die Korrektheit des Vorg¨angers wird sichergestellt, indem dieser auf Erreichbarkeit gepr¨ uft und wenn n¨otig gel¨oscht wird. Die Zeit zwischen zwei Stabilisierungen, wird in Millisekunden u ¨ber den Parameter STABILIZATION INTERVALL in der Konfigurationsdatei angegeben. 4

Eine Aufstellung der in der Konfigurationsdatei einstellbaren Parameter befindet sich in Anhang D.

37

4.1 Klassendesign Nach der eigentlichen Stabilisierung f¨ uhrt Stabilizer die in Abschnitt 3.3.3 beschriebene Aktualisierung der Nachfolgerliste durch. Die Nachfolgerliste wird dabei jedoch nicht nach jeder Stabilisierung aktualisiert. Sie wird dann aktualisiert, wenn sich durch die Stabilisierung der Nachfolger ¨andert, sp¨atestens jedoch wenn eine bestimmte Anzahl Stabilisierungen durchgef¨ uhrt worden ist. Die Anzahl der Stabilisierungen, die durchgef¨ uhrt werden bevor die Nachfolgerliste aktualisiert wird, ist durch den Parameter FIND SUCCS INTERVAL in der Konfigurationsdatei einstellbar. Ebenso wie die H¨aufigkeit, mit der die Nachfolgerliste aktualisiert wird, l¨asst sich auch die H¨aufigkeit angeben, mit der bei der Stabilisierung der Vorg¨anger auf Erreichbarkeit getestet wird. Dies erfolgt u ¨ber den Parameter CHECK PRED INTERVAL in der Konfigurationsdatei. Wie die Aktualisierung der Finger soll auch die Stabilisierung unabh¨angig von Benutzerinteraktionen wie der Durchf¨ uhrung eines Lookups sein und wurde aus diesem Grund als eigenst¨andiger Thread realisiert. Auch hier w¨ urde die Ausf¨ uhrung der Stabilisierung die Durchf¨ uhrung eines Lookups f¨ ur die Dauer der Stabilisierung blockieren.

4.1.6 Die Klassen DHTServer, PeerConnectionServer und -Client Die Klassen DHTServer, PeerConnectionServer und PeerConnectionClient realisieren die Kommunikationschnittstelle zu anderen Peers. Die Klasse DHTServer nimmt ankommende Verbindungen an. Die Klasse PeerConnectionServer verarbeitet von anderen Peers eingehenden Nachrichten, w¨ahrend Anfragen an andere Peers durch die Klasse PeerConnectionClient realisiert werden. ¨ Aus Gr¨ unden der Vereinfachung wurde das TCP-Protokoll [37] zur Ubertragung von Nachrichten u ¨ber das Netzwerk verwendet. Es bietet den Vorteil, dass es die Verwendung von Java-ObjectStreams erm¨oglicht. Mit Hilfe von Java-ObjectStreams ist es m¨oglich, Instanzen von Java-Objekten zu serialisieren und u ¨ber das Netzwerk zu versenden. Des Weiteren bietet das TCP-Protokoll den Vorteil, dass die u ¨ber das Netzwerk u ¨bermittelten Daten, im Gegensatz zum UDP-Protokoll [33], immer und in der Reihenfolge beim Empf¨anger eintreffen, in der sie gesendet wurden. Eingehende Verbindungen von anderen Chord-Peers werden zun¨achst von der Instanz DHTNode.serverclass der Klasse DHTServer angenommen. Die einzige Aufgabe von DHTServer ist es, einen Socket bereitzustellen, auf dem andere Peers Kontakt auf-

38

4.1 Klassendesign nehmen k¨onnen. Dabei erzeugt DHTServer f¨ ur jede neu eingehende Verbindung eine neue Instanz von PeerConnectionServer. Die so erzeugte Instanz von PeerConnectionServer verarbeitet die eingehenden Nachrichten des damit verbundenen Peers und sendet entsprechende Antworten zur¨ uck.5 Nimmt ein Peer aktiv Verbindung zu einem anderen Peer auf, so geschieht dies mit Hilfe der Klasse PeerConnectionClient. Dies ist immer dann der Fall, wenn ein Lookup oder das Stabilisierungsprotokoll durchgef¨ uhrt wird. Zur Durchf¨ uhrung von Lookups wird die Funktion lookup() vom entsprechenden LookupKeyThread oder LookupFingerThread aufgerufen. Bei der Ausf¨ uhrung des Stabilisierungsprotokolls werden die Funktionen stabilizeNode(), notifyNode() und getSuccessors() aus der Klasse Stabilizer heraus aufgerufen.

PeerConnectionClient PeerConnectionClient(in Location) lookupResponse(in LookupMessage) lookup(in LookupMessage)

PeerConnectionServer mediator: Mediator

findSuccessor(in Location) getExponent()

processCommand(in RemoteMessage)

getSuccessors()

run()

leaveChordRing(in Object) stabilizeNode() notifyNode(in Location)

Abbildung 4.4: UML-Klassendiagramm: PeerConnectionClient und -Server

Ferner baut ein Peer aktiv Verbindungen zu anderen Peers auf, wenn er in den ChordRing eintritt oder diesen absichtlich verl¨asst. Wenn ein Peer den Chord-Ring verl¨asst, so benachrichtigt er seine Nachbarn durch Aufruf der Methode leaveChordRing(). In dem Fall, dass eine Peer jedoch in den Chord-Ring eintreten m¨ochte, muss er zun¨achst den Exponenten des Chord-Rings sowie seinen Nachfolger kennen. Diese werden durch getExponent() und findSuccessor() vom verbundenen Peer abgefragt. Eine weiterer Grund, eine Verbindung zu einem anderen Peer zu ¨offnen, ist die Beantwortung von Lookups. Hier wird dem suchenden Peer durch Aufruf der Methode lookupResponse() eine Antwort auf seinen Lookup gesendet. 5

Eine Tabelle der m¨ oglichen Nachrichten befindet sich in Anhang C.

39

4.1 Klassendesign

4.1.7 Die Klasse RemoteMessage In der Klasse RemoteMessage werden an andere Peers zu versendende Daten bzw. Java-Objekte gekapselt. Hierzu besitzt RemoteMessage die Felder messagecommand und messagebody sowie die zum Zugriff auf die Felder ben¨otigten get- und setMethoden. Das Feld messagecommand ist vom Typ byte. Anhand dieses Feldes werden die Art der Nachricht sowie die im Feld messagebody transportierten Objekte klassifiziert. Da je nach Nachricht in messagebody unterschiedliche Objekte transportiert werden, ist Feld messagebody vom Typ Object. Die Gr¨oße einer RemoteMessage ist damit abh¨angig von den zu u ¨bertragenden Objekten. Tabelle 4.1 gibt Beispiele f¨ ur die konkreten Werte von messagecommand und messagebody. Nachricht

messagecommand

messagebody

GET EXPONENT

30

NULL

EXPONENT IS

31

Byte

NOTIFY

2

Location

KEY LOOKUP

70

LookupMessage

Tabelle 4.1: Beispiele f¨ ur RemoteMessages

4.1.8 Die Klasse Mediator Die Klasse Mediator dient der Entkopplung der einzelnen Klassen, entsprechend dem gleichnamigen Mediator-Entwurfsmuster [14]. Mediator bildet die Schnittstelle zwischen den einzelnen Komponenten eines Chord-Peers. Weiterhin verwaltet Mediator sowohl die Nachfolgerliste vom Typ SuccessorList wie auch den Vorg¨anger und die Fingertabelle vom Typ FingerTable und stellt Methoden zum synchronisierten Zugriff auf diese bereit. Der synchronisierte Zugriff ist deshalb wichtig, da es durch die Verwendung von Threads vorkommen kann, dass zwei Threads gleichzeitig auf das gleiche Objekt zugreifen m¨ochten. So kann es z. B. dazu kommen, dass bei der Ausf¨ uhrung des Stabilisierungsprotokolls der Nachfolger gerade abge¨andert wird, jedoch zur gleichen Zeit ein Lookup ausgef¨ uhrt wird, weshalb der aktuelle Nachfolger abgefragt wird. Zur Abfrage und Ver¨anderung des Nachfolgers, des Vorg¨angers und der Finger stellt Mediator die get- und set-Methoden get-/setSuccessor(), get-/setPredecessor() und get-/setFinger() bereit. Die Methode setSuccessor() wird z. B. dann aufgerufen, wenn

40

4.1 Klassendesign Mediator successors: SuccessorList fingertable: FingerTable Mediator() keyIsBetween(in long, in long, in long) closestNode(in long) localLookup(in long) lookup(in LookupMessage) storeLookupResponse(in LookupMessage) getLookupResponse(in long) deregisterLookup(in LookupKeyThread, in LookupMessage) registerLookup(in LookupKeyThread, in LookupMessage) leave() getPredecessor() checkPredecessor() setPredecessor(in Location) setSuccessors(in LinkedList) getSuccessors() setSuccessor(in Location) getSuccessor() setFinger(in int, in Location) getFinger(in int)

Abbildung 4.5: UML-Klassendiagramm: Mediator ein Peer das Stabilisierungsprotkoll ausf¨ uhrt und dabei durch den Aufruf der Methode PeerConnectionClient.stabilizeNode() einen neuen Nachfolger erh¨alt und den entsprechenden Eintrag in der Nachfolgerliste somit ab¨andert. Die Methode getPredecessor() wird z. B. dann benutzt, wenn Stabilizer den Nachfolger auf Erreichbarkeit pr¨ uft, oder wenn PeerConnectionServer eine Anfrage nach dem Vorg¨anger beantwortet. Die Methoden zum Zugriff auf die Finger werden bei der Aktualisierung der Fingertabelle sowie beim Weiterleiten eines Lookups an einen Finger benutzt. Der Zugriff auf die Nachfolgerliste erfolgt mit den Methoden get-/setSuccessors(). Die Methode getSuccessors() wird dabei z. B. aus einer Instanz der Klasse PeerConnectionServer aufgerufen, wenn ein Peer die Nachfolgerliste des Peers abfragt. Dies ist dann der Fall, wenn von einem anderen Peer durch den Aufruf von PeerConnectionClient.getSuccessors() eine entsprechende Anfrage an den Peer gestellt wird. ¨ Zur Uberpr¨ ufung des Nachfolgers auf Erreichbarkeit wird die Methode checkPredecessor() eingesetzt. Durch Aufruf der Methode leave() wird den Nachbarn mitgeteilt, dass der Peer den Chord-Ring verl¨asst.

41

4.2 Kommunikation und Interaktion Neben den Methoden zum Zugriff auf die Nachfolger, die Finger und den Vorg¨anger unterst¨ utzt Mediator die Durchf¨ uhrung von Lookups. Hier ist die Funktion keyIsBetween() von zentraler Bedeutung. Mit ihrer Hilfe wird f¨ ur Peer x und seinen Vorg¨anger y, sowie einen Schl¨ ussel key u uft, ob Peer x f¨ ur den Schl¨ ussel key zust¨andig ist, ¨berpr¨ d. h. ob y < key ≤ x. Die weiteren Funktionen zur Durchf¨ uhrung von Lookups werden in Abschnitt 4.2.2 genauer erl¨autert.

4.2 Kommunikation und Interaktion Dieser Abschnitt erl¨autert die Interaktion zwischen den Klassen sowie die unter den Peers stattfindende Kommunikation.

4.2.1 Betreten und Verlassen des Chord-Rings Betreten des Chord-Rings Dieser Abschnitt erl¨autert die praktische Umsetzung von Abschnitt 3.3.2: die Integration von neuen Peers in den Chord-Ring. M¨ochte ein Peer x einen bestehenden Chord-Ring betreten, so muss er zun¨achst einen beliebigen Peer z des Chord-Rings kennen. Diesen muss er dann kontaktieren und ihn zuerst nach dem Exponenten des Chord-Rings fragen. Dies geschieht, indem Peer x die Nachricht GET EXPONENT an z sendet. Peer z gibt darauf hin die Antwort EXPONENT IS. In dieser Nachricht ist der Exponent des Chord-Ring enthalten. Nachdem x nun den Exponenten des Chord-Rings kennt, muss der Nachfolger von x im Chord-Ring ermittelt werden. Diesen l¨asst x von z durch Suche des f¨ ur x.ID zust¨andigen Peers feststellen. Da z, wie bereits in Abschnitt 3.3.2 erkl¨art, den speziellen Fall der Ermittlung des Nachfolgers von der konventionellen Suche nach einem Schl¨ ussel unterscheiden k¨onnen muss, verwendet x die spezielle Nachricht FIND SUCCESSOR.6 Erh¨alt z diese Nachricht, so wird bei ihm der konventionelle Lookup-Mechanismus in Gang gesetzt, mit dem dann der f¨ ur x.ID zust¨andige Peer, also der Nachfolger y von x, gesucht wird. Sobald Peer y gefunden wurde, der Lookup-Prozess also abgeschlossen ist, u ¨bermittelt z das Ergebnis an x. Hierzu sendet z die Nachricht FOUND SUCCESSOR an x zur¨ uck. Peer x setzt nun seinen Nachfolger auf den u ¨bermittelten Wert y. Nachdem x nun seinen Nachfolger kennt, ist der eigentliche Beitritt in den Chord-Ring abgeschlossen. Die weiteren Schritte 6

vgl.: Abschnitt 4.2.2

42

4.2 Kommunikation und Interaktion zur vollst¨andigen Integration von x in den Chord-Ring werden durch das Stabilisierungsprotokoll ausgef¨ uhrt. Hierbei wird y u ¨ber die Existenz von x informiert, so dass x zum Vorg¨anger von y wird. Peer x bezieht seinen Vorg¨anger, indem er von y’, dem alten Vorg¨anger von y, benachrichtigt wird.7 Verlassen des Chord-Rings Wie schon in Abschnitt 3.3.4 erw¨ahnt, ist Chord darauf ausgelegt, dass Peers ohne Vorank¨ undigung ausfallen. Verl¨asst ein Peer jedoch den Chord-Ring absichtlich, so ist es sinnvoll, dass der entsprechende Peer seinen Nachfolger und seinen Vorg¨anger vorab dar¨ uber informiert.8 F¨ ur diesen Fall ist die Nachricht LEAVE vorgesehen. Diese wird von Peer x an seine Nachbarn gesendet bevor er den Chord-Ring absichtlich verl¨asst. Mit Hilfe dieser Nachricht wird es dem Vorg¨anger y und dem Nachfolger z von x erm¨oglicht, ihren Nachfolger bzw. Vorg¨anger direkt und ohne Ausf¨ uhrung des Stabilisierungsprotolls, auf z bzw. y abzu¨andern. Die Nachricht LEAVE enth¨alt dabei eine Liste mit zwei Elementen von Typ Location. Das erste Element bildet x selbst ab. Je nach Empf¨anger, bildet das zweite Element, entweder den Vorg¨anger y oder den Nachfolger z ab. Anhand des ersten Elements k¨onnen y und z unterscheiden, ob sie die LEAVE-Nachricht von ihrem Vorg¨anger oder von ihrem Nachfolger erhalten. Dementsprechend ersetzt sowohl Peer y als auch Peer z seinen Vorg¨anger bzw. Nachfolger durch den Peer, der durch das zweite Element der Liste repr¨asentiert wird. Hierdurch wird also y zum Vorg¨anger von z, w¨ahrend z zum Nachfolger von y wird. Wenn also x den Chord-Ring verl¨asst, so sendet er an seinen Vorg¨anger y die Nachricht LEAVE mit der Liste (x, z) und an seinen Nachfolger z die Nachricht LEAVE mit der Liste (x, y). Erh¨alt Peer y die Nachricht, so ¨andert y seinen Nachfolger auf den u ¨bermittelten Peer z ab, w¨ahrend z seinen Vorg¨anger auf y ab¨andert.

4.2.2 Durchf¨ uhrung von Lookups Routingm¨ oglichkeiten F¨ ur die Implementierung des Lookup-Prozesses ist das f¨ ur die Weiterleitung von Lookups gew¨ahlte Routingkonzept von entscheidender Bedeutung. Dabei werden zwei 7 8

vgl.: Abschnitt 3.3.2 vgl.: Abschnitt 3.3.4

43

4.2 Kommunikation und Interaktion Vorgehensweisen unterschieden: • iterativ : Bei der iterativen Suche werden alle Anfragen vom suchenden Peer gestellt. Er befragt dabei eine Folge von n Peers, wobei ihm Peer i-1 mitteilt, dass Peer i der n¨achste zu befragende Peer auf dem Suchpfad ist. Dies geschieht solange bis der richtige Peer gefunden wird. • rekursiv : Bei der rekursiven Suche wird der Lookup vom suchenden Peer initiiert indem dieser eine Anfrage an einen anderen Peer stellt. Im Anschluss daran wird der Lookup aber von Peer zu Peer weitergeleitet. Hat die Suche ihr Ziel erreicht, so wird die Antwort u uckgeroutet. ¨ber den gleichen Weg zur¨ Der Vorteil der iterativen Suche besteht darin, dass sich der suchende Peer dem gesuchten Peer mit jeder Iteration weiter ann¨ahert. Somit erh¨alt er implizit Informationen zum Fortschritt des Suchprozesses. Da jegliche Kommunikation vom suchenden Peer ausgeht, besitzt dieser st¨andigen Einfluss auf den weiteren Verlauf der Suche und kann diese auch jederzeit abbrechen. Werden w¨ahrend einer iterativen Suche n Peers befragt, so betr¨agt die Anzahl der ben¨otigten Nachrichten 2n. Der Vorteil der rekursiven Suche wiederum besteht darin, dass der suchende Peer unabh¨angig davon, dass der Lookup u ¨ber n Peers weitergeleitet wird, nur eine Nachricht senden und deshalb auch nur eine TCP-Verbindung aufbauen muss, w¨ahrend er bei der iterativen Suche n Nachrichten sendet und damit auch n TCP-Verbindungen aufbauen muss. Der Nachteil an rekursiven Aufrufen ist, dass dem suchenden Peer w¨ahrend der Suche keine Informationen u ugung ¨ber den Fortschritt der Suche zur Verf¨ stehen. Sobald der Lookup gesendet wurde, hat der suchende Peer keinen Einfluss mehr auf den weiteren Verlauf der Suche. Die Antwort erh¨alt er von dem Peer, dem er den Lookup gesendet hat. Bei der rekursiven Suche wird die Antwort u ¨ber die gleichen n Peers, u ur einen Schl¨ ussel verant¨ber die sie vom suchenden Peer zum f¨ wortlichen Peer gelangt ist, zur¨ uckgesendet. In diesem Fall betr¨agt die Anzahl der Nachrichten ebenfalls 2n. Die Anzahl der f¨ ur eine Suche ben¨otigten Nachrichten, sowie die Anzahl der vom suchenden Peer ben¨otigten TCP-Verbindungen l¨asst sich durch einen semi-rekursiven Ansatz verringern. Der Lookup wird dabei wie bei der rekursiven Suche jeweils an den dem gesuchten Peer am n¨achsten gelegenen bekannten Peer weitergeleitet. Wird der gesuchte Peer erreicht, so antwortet dieser jedoch dem Initiator der Suche direkt. Bei diesem Ansatz muss der suchende Peer wie beim rekursiven Ansatz nur eine TCP-

44

4.2 Kommunikation und Interaktion Verbindung aufbauen, w¨ahrend die Anzahl der ben¨otigten Nachrichten n+1 betr¨agt. Wichtig bei diesem Vorgehen ist, dass im Lookup immer dessen Ursprung angegeben wird. F¨ ur die Implementierung wurde der semi-rekursive Ansatz gew¨ahlt. Initiierung von Lookups Vom Benutzer durchgef¨ uhrte Lookups werden durch den Aufruf der Methode lookup(key) der Klasse DHTNode eingeleitet. Das UML-Sequenzdiagramm f¨ ur die Durchf¨ uhrung eines Lookups wird von Abbildung 4.6 gezeigt. Der suchende Peer ist dabei nicht der f¨ ur den Schl¨ ussel verantwortliche Peer. Die Darstellung bezieht sich auf die wesentlichen Schritte, weshalb z. B. die Bestimmung des Peers, an den die Suche weitergeleitet wird, oder die Erzeugung der Instanz von PeerConnectionServer durch die Klasse DHTServer nicht mit eingeflossen sind. Mit dem Aufruf DHTNode.lookup(key) der Peers x wird eine neue Instanz l der Klasse LookupKeyThread generiert, welche mit l.run() gestartet wird. Ist dies geschehen, so wird der Suchvorgang durch Aufruf der Methode l.lookup(key) des erzeugten LookupKeyThreads l fortgef¨ uhrt. Zun¨ achst testet l, ob Peer x nicht selbst f¨ ur den gesuchten ¨ Schl¨ ussel zust¨andig ist. Diese Uberpr¨ ufung erfolgt durch den Aufruf der Methode Mediator.localLookup(). Ist Peer x selbst zust¨andig, so wird direkt eine Instanz von Location zur¨ uckgeliefert, welche Peer x beschreibt. Ist x jedoch nicht f¨ ur den Schl¨ ussel verantwortlich, so muss der Lookup weitergeleitet werden. Hierzu meldet sich die Instanz l von LookupKeyThread bei der Klasse Mediator an. Diese Anmeldung erfolgt durch den Methodenaufruf Mediator.registerLookup(key,l). Nach erfolgter Anmeldung des Lookups f¨allt LookupKeyThread in einen Zustand, in dem er auf das Ergebnis des Lookups wartet. Hierbei wartet l solange, bis der Schl¨ ussel gefunden wurde oder die maximale Suchzeit erreicht ist.9 Die weitere Bearbeitung des Lookups wird unterdessen von Mediator durchgef¨ uhrt. Mediator w¨ahlt nun aus der Fingertabelle den Peer y aus, an den der Lookup weitergeleitet wird. Diese Auswahl erfolgt durch die Methode Mediator.closestNode(key). Nachdem Peer y ermittelt wurde, wird eine Netzwerkverbindung zu diesem aufgebaut. Diese wird mittels einer Instanz der Klasse PeerConnectionClient hergestellt. Ist die Verbindung zwischen den Peers x und y hergestellt, so wird der Lookup versendet. Dies erfolgt durch den Methodenaufruf PeerConnectionClient.lookup(key). Hier9

Die maximale Suchzeit ist in der Konfigurationsdatei einstellbar. Vgl.: Anhang D

45

4.2 Kommunikation und Interaktion

DHTNode

Mediator

LookupKeyThread

PeerConnectionClient

PeerConnectionServer

lookup(key)

localLookup(key) lookup(key)

registerLookup(key,this)

lookup(key)

KEY_LOOKUP

KEY_FOUND

wait storeLookupResponse(key,Location)

setResult

getLookupResponse(key)

Location

Location

deregisterLookup(key,this)

Location

Abbildung 4.6: UML-Sequenzdiagramm: Durchf¨ uhrung von Lookups bei wird die Nachricht KEY LOOKUP versendet. Sie enth¨alt den gesuchten Schl¨ ussel 10 sowie die IP-Adresse und den Chord-Port des suchenden Peers x. Nachdem der Lookup weitergeleitet wurde, ist der aktive Teil des Lookups beendet. Es verbleibt die Instanz l von LookupKeyThread, welche auf das Ergebnis des Lookups wartet. Diese wird wieder aktiviert, wenn sich der f¨ ur den gesuchten Schl¨ ussel verantwortliche Peer meldet, oder die maximale Suchzeit erreicht ist. Wird die maximale Suchzeit erreicht, so meldet l den Lookup bei der Instanz von Mediator wieder ab. Die Methode LookupKeyThread.lookup(key) wird in diesem Fall mit dem R¨ uckgabewert NULL beendet, so dass in der Folge auch die Methode DHTNode.lookup(key) mit dem Ergebnis NULL beendet wird. Wird im Laufe des Suchprozesses der verantwortliche Peer p erreicht, so meldet dieser sich beim suchenden Peer x. Hierzu kontaktiert er x unter der IP-Adresse und Chord-Port, die von x in der Nachricht LOOKUP KEY vermerkt wurde. Von Peer x wird nun eine neue Instanz s der Klasse PeerConnectionServer f¨ ur die von p aus eingehende Verbindung generiert. Diese verarbeitet die von p gesendete Nachricht KEY FOUND. Mit dieser Nachricht u ¨bermittelt p eine Beschreibung loc von sich, und dass er f¨ ur den gesuchten Schl¨ ussel zust¨andig ist. PeerConnectionServer s meldet nun an Mediator, dass Schl¨ ussel key gefunden wurde und dass p, welcher durch loc 10

Details zu Aufbau und Verwendung der versendeten Nachrichten erl¨ autert Anhang C.

46

4.2 Kommunikation und Interaktion beschrieben wird, der zust¨andige Peer ist. Hierzu ruft PeerConnectionServer die Methode Mediator.storeLookupResponse(key,loc) auf. F¨ ur den Fall, dass die maximale Suchdauer u ¨berschritten wurde und LookupKeyThread den Lookup schon wieder abgemeldet hat, verwirft Mediator das Ergebnis. Wurde die maximale Suchdauer jedoch noch nicht u ¨berschritten, informiert Mediator die Instanz l von LookupKeyThread, welche auf das Ergebnis der Suche wartet dar¨ uber, dass die Suche nach Schl¨ ussel key 11 erfolgreich verlaufen ist. Die Benachrichtigung erfolgt durch den Aufruf LookupKeyThread.setResult(). Nachdem LookupKeyThread l benachrichtigt wurde, fragt dieser das Ergebnis der Suche vom Mediator ab. Dies erfolgt mittels Aufruf der Methode Mediator.getLookupResponse(key), deren R¨ uckgabewert die Beschreibung loc des verantwortlichen Peers ist. Nachdem LookupKeyThread l das Ergebnis vom Mediator abgefragt hat, meldet l den Lookup beim diesem ab. Hierzu ruft LookupKeyThread l die Methode Mediator.deregisterLookup(key,l) auf. Ist die Abmeldung erfolgt, wird die Methode LookupKeyThread.lookup(key) mit dem R¨ uckgabewert loc beendet. Danach wird LookupKeyThread selbst beendet. Nachdem LookupKeyThread.lookup(key) beendet wurde, kann nun auch DHTNode.lookup(key) beendet werden. Wenn der gesuchte Schl¨ ussel gefunden wurde, liefert DHTNode.lookup(key) den R¨ uckgabewert loc, wurde der Schl¨ ussel nicht gefunden, so ist der R¨ uckgabewert NULL. Weiterleitung und Beantwortung von Lookups Die Weiterleitung und Beantwortung von Lookups ist neben der aktiven Suche nach einem Schl¨ ussel ein weiterer Aspekt des Suchmechanismus. In diesem Fall erh¨alt der Peer zun¨achst die Nachricht KEY LOOKUP von einem anderen Peer. Diese wird u ¨ber die Klasse PeerConnectionServer empfangen. Erh¨alt eine Instanz von PeerConnectionServer eine KEY LOOKUP Nachricht, so ruft sie die Funktion Mediator.lookup() auf und u ussel sowie die ¨bergibt den in der Nachricht enthaltenen gesuchten Schl¨ ebenfalls in der Nachricht enthaltene Information u ungliche Herkunft ¨ber die urspr¨ des Lookups. Mediator pr¨ uft nun, ob der eigene Chord-Peer f¨ ur den Schl¨ ussel verantwortlich ist. Ist dieser f¨ ur den Schl¨ ussel verantwortlich, so wird dem suchenden Peer eine entsprechende Antwort gesendet. Hierzu wird eine Verbindung zum suchenden Peer aufgebaut. Dies geschieht mit Hilfe der Informationen u ¨ber die Herkunft des Lookups und einer Instanz c der Klasse PeerConnectionClient. Ist die Verbindung 11

Da die Durchf¨ uhrung von Lookups durch Threads realisiert wurde, kann es vorkommen, dass mehrere LookupKeyThreads gleichzeitig den gleichen Schl¨ ussel key suchen. In diesem Fall werden alle wartenden LookupKeyThreads benachrichtigt.

47

4.2 Kommunikation und Interaktion aufgebaut, so wird die Antwort auf den Lookup an den suchenden Peer gesendet. Dies erfolgt durch den Aufruf der Methode c.lookupResponse(). Ist der Peer nicht selbst verantwortlich, so muss er den Lookup weiterleiten. Hierzu w¨ahlt er aus seiner Fingertabelle denjenigen Peer aus, der dem gesuchten Schl¨ ussel am n¨achsten liegt. Anschließend baut er mit Hilfe einer Instanz c von PeerConnectionClient eine Verbindung zu diesem Peer auf. Ist die Verbindung zustande gekommen, so wird der Lookup weitergeleitet. Dies erfolgt durch den Aufruf der Methode c.lookup(key). Abbildung 4.7 zeigt das UML-Sequenzdiagramm f¨ ur den Fall, dass der Peer f¨ ur den gesuchten Schl¨ ussel selbst verantwortlich ist. Falls der Peer den Lookup nur weiterleitet, w¨ urde die Methode lookup(key) der Klasse PeerConnectionClient aufgerufen werden. Die versendete Nachricht w¨are in diesem Fall KEY LOOKUP. PeerConnectionServer

Mediator

PeerConnectionClient

KEY_LOOKUP lookup(key,origin)

localLookup(key)

lookupResponse(key)

KEY_FOUND

Abbildung 4.7: UML-Sequenzdiagramm: Antwort auf Lookups

4.2.3 Aktualisierung der Fingertabelle Die Aktualisierung der Fingertabelle erfolgt in regelm¨aßigen Zeitabst¨anden (Runden). Es wird dabei in jeder Runde genau ein Finger aktualisiert. Hierzu generiert die Klasse FingerTableStabilizer f¨ ur jede Aktualisierung eine neue Instanz l der Klasse LookupFingerThread und startet den Thread mit l.run(). Bevor jedoch der Finger gesucht werden kann, werden der Schl¨ ussel key, f¨ ur den der Finger verantwortlich sein soll, sowie der Platz i des Fingers in der Fingertabelle an LookupFingerThread l u ¨bergeben. Dabei gilt, dass key = 2i−1 ist. Jetzt wird die Suche mit l.updateFinger() gestartet. Die aufgerufene Methode updateFinger() sucht zun¨achst den f¨ ur key zust¨andigen Peer. Dies geschieht mittels der

48

4.2 Kommunikation und Interaktion Funktion lookup(key), welche LookupFingerThread von der Superklasse LookupKeyThread vererbt wurde. Ist die Suche nach Finger i erfolgreich, so ist das Ergebnis loc = lookup(key) eine Instanz von Location, die den entsprechenden Finger beschreibt. Nun aktualisiert LookupFingerThread Eintrag i der Fingertabelle mit dem gerade ermittelten Eintrag loc. Dies erfolgt durch den Aufruf der Methode Mediator.setFinger(i,loc). Nach Beendigung dieses Methodenaufrufs ist die Aktualisierung des Fingers abgeschlossen und l wird beendet. Das UML-Sequenzdiagramm in Abbildung 4.8 zeigt die erl¨auterten Methodenaufrufe zur Aktualisierung eines Fingers. FingerTableStabilizer

LookupFingerThread

Mediator

setFingerkey(key) setFingerindex(i) updateFinger()

lookup(key) setFinger(i,loc)

Abbildung 4.8: UML-Sequenzdiagramm: Aktualisierung eines Fingers

4.2.4 Ausf¨ uhrung des Stabilisierungsprotokolls Die Ausf¨ uhrung des Stabilisierungsprotokolls erfolgt wie in Abschnitt 3.3.1 beschrieben. Die Peers fragen dabei zun¨achst den Vorg¨anger ihres Nachfolgers ab. Dies erfolgt durch Versenden der Nachricht GET PREDECESSOR, welche vom Nachfolger mit PREDECESSOR IS beantwortet wird.12 Nun wird u uft, ob der Vorg¨anger des ¨berpr¨ Nachfolgers als neuer Nachfolger in Betracht kommt. Ist dies der Fall, so wird der Nachfolger entsprechend abge¨andert. Nachdem dieser Teil des Stabilisierungsprotokolls abgeschlossen ist, informieren die Peers ihren Nachfolger u ¨ber die eigene Existenz. Dies geschieht durch Versenden der Nachricht NOTIFY an den Nachfolger. 12

Details zu Aufbau und Verwendung der versendeten Nachrichten erl¨ autert Anhang C.

49

4.2 Kommunikation und Interaktion Zum Abschluss der Stabilisierung wird die Nachfolgerliste vom Nachfolger mit Hilfe der Nachricht GET SUCCESSORS abgefragt. Der Nachfolger antwortet mit der Nachricht SUCCESSORS ARE, welche seine Nachfolgerliste enth¨alt. ¨ Das in Abschnitt 3.3.3 beschriebene Verfahren zur Ubernahme der Nachfolgerliste, d. h. den letzten Peer in der Nachfolgerliste zu l¨oschen und an erster Stelle den eigenen Nachfolger einzuf¨ ugen, erweist sich in der Praxis als nicht ausreichend. Dies gilt insbesondere f¨ ur Chord-Ringe mit wenigen Peers, wenn die maximale L¨ange der ¨ Nachfolgerliste die Anzahl der Peers im Chord-Ring u die L¨ange ¨bersteigt. Ubersteigt der Nachfolgerliste die Anzahl der Peers im Chord-Ring, so f¨ uhrt das beschriebene Verfahren dazu, dass sich Teile der Liste wiederholen und somit mehr Daten u ¨bertragen werden als n¨otig. Aus diesem Grund werden sich wiederholende Eintr¨age bei ¨ der Ubernahme der Nachfolgerliste entfernt. P1 P53

P14, P22, P35 P14 P1, P14, P22 P22,P35,P53

P22 P35

P35, P53, P1 P53, P1, P14

P1 P53

P1 P53

P14, P22, P35

P14, P22, P35

P14

1

2

P22,P35,P53

P35, P53, P1 P1, P14

P14, P22, P35

P14

P22 P35

P1 P53

P14

3

P22,P35,P53

P22 P35

P35, P14, P1 P1, P14, P22

P22, P35, P1

P22 P35

P35, P1, P14 P1, P14, P22

Abbildung 4.9: Vererbung der Nachfolgerliste Ein weiteres Problem der Nachfolgerliste ist, dass ausgefallene Peers nicht direkt aus den Nachfolgerlisten aller Peers gel¨oscht werden. Sei y ein beliebiger Peer mit dem Vorg¨anger x, dem Nachfolger z und einer Nachfolgerliste der L¨ange j. F¨allt Peer y aus, so wird z der neue Nachfolger von x. F¨ uhrt x nun das Stabilisierungsprotokoll aus, so bezieht er eine neue Nachfolgerliste von z. Somit wird y aus der Nachfolgerliste von x gel¨oscht, jedoch existiert der Eintrag immer noch in den Nachfolgerlisten der ersten j-1 Vorg¨anger von x. Bei der folgenden Stabilisierung vererbt nun x wiederum

50

4.3 Datenvolumen seine Nachfolgerliste an seinen Vorg¨anger. Nun existiert der Eintrag y nur noch in den ersten j-2 Vorg¨angern von x. Dieser Vorgang setzt sich fort, bis aus allen Nachfolgerlisten der Eintrag y gel¨oscht wurde. Es dauert also mindestens j Stabilisierungen, bis ein ausgefallener Peer aus allen Nachfolgerlisten gel¨oscht wurde. Abbildung 4.9 veranschaulicht den beschriebenen Sachverhalt an einem Chord-Ring mit 5 Peers und einer Nachfolgerliste der L¨ange j = 3. F¨allt P53 aus, so dauert es j = 3 Stabilisierungen, bis P53 aus allen Nachfolgerlisten verschwunden ist.

4.3 Datenvolumen Dieser Abschnitt analysiert die Gr¨oße der versendeten Nachrichten. Diese lassen sich in zwei Kategorien einordnen: • einmal versendete Nachrichten: Diese Nachrichten werden beim Eintritt und Verlassen des Chord-Rings gesendet. Sie werden zur Abfrage des Exponenten, zum erstmaligen Auffinden des Nachfolgers bei Eintritt in den Chord-Ring, ¨ sowie zur Ubermittlung des Vorg¨angers bzw. Nachfolgers beim Verlassen des Chord-Rings versendet. Hierzu z¨ahlen die Nachrichten GET EXPONENT, EXPONENT IS, FIND SUCCESSOR, FOUND SUCCESSOR und LEAVE. • mehrmals versendete Nachrichten: Diese Nachrichten werden zur Suche nach Schl¨ usseln und zur Stabilisierung des Chord-Rings eingesetzt. Dazu z¨ahlen die Nachrichten GET PREDECESSOR, PREDECESSOR IS, GET SUCCESSORS, SUCCESSORS ARE, NOTIFY sowie KEY LOOKUP und KEY FOUND. Das durch einmalig versendete Nachrichten verursachte Datenvolumen ist konstant, so dass der Anteil, den diese Nachrichten am gesamten Datenvolumen haben, mit der Zeit sinkt. Aus diesem Grund beschr¨ankt sich dieses Kapitel auf die Nachrichten, die mehrmals verwendet werden. Diese sind f¨ ur den gr¨oßten Teil des verursachten Datenvolumens verantwortlich. Wie in Abschnitt 4.1.7 bereits beschrieben, bestehen die von den Peers versendeten Nachrichten immer aus einem Kommando messagecommand und einem Feld messagebody, in dem je nach Kommando unterschiedliche Objekte gespeichert werden. Nachfolgend wird beschrieben, welche Informationen diese Nachrichten im Einzelnen transportieren und wie sich daraus die Nachrichtengr¨oße errechnet. Die Betrachtung der Nachrichtengr¨oße orientiert sich dabei an der Gr¨oße der in der jeweiligen Instanz

51

4.3 Datenvolumen von RemoteMessage u ¨bertragenen Informationen. Die Gr¨oße der u ¨bertragenen Informationen berechnet sich aus der Gr¨oße der Objekte im Feld messagebody plus 1 Byte im Feld command, da Kommandos durch ein Byte repr¨asentiert werden. Insbesondere findet die Betrachtung dabei anhand der Gr¨oße der von Chord verwendeten Datentypen, also unabh¨angig von ihrer konkreten Java-Repr¨asentation, statt. Eine Zeichenkette von 15 Zeichen wird z. B. mit 15 Bytes gez¨ahlt, unabh¨angig davon, dass diese durch ein Objekt des Typs java.lang.String repr¨asentiert wird, welches potenziell mehr als 15 Bytes beansprucht.

4.3.1 Datenvolumen je Lookup Zur Durchf¨ uhrung von Lookups werden die beiden Nachrichten KEY LOOKUP und KEY FOUND verwendet. Diese beiden Nachrichten transportieren im Feld messagebody jeweils ein Objekt der Klasse LookupMessage, in der die zum Lookup ben¨otigten Daten, also der gesuchte Schl¨ ussel, der suchende Peer und die bisherige Anzahl an Weiterleitungen, gekapselt werden.13 Zur Repr¨asentation des gesuchten Schl¨ ussels wird der Java-Typ long verwendet, der 64-Bit Werte darstellt, also 8 Bytes ben¨otigt. Die Anzahl der Weiterleitungen wird der Java-Typ short eingesetzt, welcher 2 Bytes ben¨otigt.14 Der suchende Peer wird durch eine Instanz von Location repr¨asentiert, welche insgesamt 31 Bytes umfasst.15 Insgesamt betr¨agt das Datenvolumen der Nachrichten KEY LOOKUP und KEY FOUND: Kommando gesuchter Schl¨ ussel suchender Peer Weiterleitungen bisher Summe

byte long Location short

1 8 31 2

Byte Bytes Bytes Bytes

42

Bytes

Wird nun in einem Chord-Ring mit n Peers ein Lookup durchgef¨ uhrt, so wird der verantwortliche Peer mit hoher Wahrscheinlichkeit innerhalb von O(log n) Schritten gefunden. Somit werden O(log n) Nachrichten des Typs KEY LOOKUP ben¨otigt. Wird schließlich der verantwortliche Peer gefunden, so sendet dieser die Nachricht KEY FOUND an den suchenden Peer zur¨ uck. Durch die Suche nach einem Schl¨ ussel 13

Das UML-Klassendiagramm der Klasse LookupMessage befindet sich in Anhang A. Die bereitgestellten Methoden dienen dem Zugriff auf die gleichnamigen Felder. 14 Da die maximale Anzahl der Weiterleitungen durch 2m begrenzt ist und f¨ ur m der Java-Typ byte benutzt wurde, muss f¨ ur die Anzahl der Weiterleitungen mindestens der Java-Typ short benutzt ¨ werden, da es sonst zu einem Uberlauf kommen kann. 15 Eine detaillierte Aufschl¨ usselung von Location befindet sich in Anhang C.

52

4.3 Datenvolumen wird also insgesamt die folgende Menge an Daten versandt: KEY LOOKUP KEY FOUND Summe

42*log(n) 42

Bytes Bytes

42*(1+log(n))

Bytes

4.3.2 Datenvolumen je Stabilisierung Jeder Peer im Chord-Ring f¨ uhrt in regelm¨aßigen Zeitabst¨anden t das in Abschnitt 3.3.1 beschriebene Stabilisierungsprotokoll aus. Hierbei kontaktieren die Peers ihre Nachbarn und tauschen Informationen mit diesen aus. Peer x fragt dabei den Vorg¨anger seines Nachfolgers y ab, worauf y die entsprechenur de Information zur¨ ucksendet. Hierf¨ ur werden Nachrichten GET PREDECESSOR f¨ die Anfrage von x an y und PREDECESSOR IS f¨ ur die Antwort von y an x, benutzt. M¨ochte x seinen Nachfolger y u ¨ber seine Existenz informieren, so sendet x die Nach¨ richt NOTIFY an y. Zur Abfrage und Ubermittlung der Nachfolgerliste werden die Nachrichten GET SUCCESSORS und SUCCESSORS ARE benutzt. Die Gr¨oße der Nachrichten berechnet sich analog zum in Abschnitt 4.3.1 beschriebenen Verfahren.16 Eine Sonderstellung nimmt die Nachricht SUCCESSORS ARE ein. Ihre Gr¨oße ist von der L¨ange j der Nachfolgerliste abh¨angig. Je gr¨oßer j wird, desto mehr Objekte vom Typ Location werden mit SUCCESSORS ARE transportiert. Die Gr¨oßen der bei der Stabilisierung versendeten Nachrichten sind im Einzelnen: GET PREDECRESSOR PREDECRESSOR IS NOTIFY GET SUCCESSORS SUCCESSORS ARE

byte byte+Location byte+Location byte byte+Location*j

1 32 32 1 1+32*j

Byte Bytes Bytes Byte Bytes

In der folgenden Analyse wird nun angenommen, dass alle Peers auf der gleichen Implementierung beruhen, insbesondere wird angenommen, dass die Zeit t zwischen zwei Ausf¨ uhrungen des Stabilisierungsprotokolls bei allen Peers gleich ist. Ferner wird angenommen, dass keine neuen Peers hinzukommen oder den Chord-Ring verlassen, d. h. es sich um einen statischen Chord-Ring handelt. Wenn die Dauer t einer Stabilisierungsperiode bei allen Peers gleich ist, f¨ uhrt jeder Peer im Chord-Ring im Zeitintervall [t0 , t1 ) : t0 +t = t1 eine Stabilisierung aus. Dabei 16

Aufbau und Gr¨ oße der Nachrichten sind in Tabelle C.1 in Anhang C dargestellt.

53

4.3 Datenvolumen versendet jeder Peer x im Intervall [t0 , t1 ) bei der Durchf¨ uhrung der Stabilisierung einmal die Nachricht NOTIFY, GET PREDECESSOR und GET SUCCESSORS. Wenn im Intervall [t0 , t1 ) jeder Peer x im Chord-Ring eine Stabilisierung durchf¨ uhrt, so f¨ uhrt auch jeweils der Vorg¨anger y des Peers x eine Stabilisierung durch. Das bedeutet wiederum, dass Peer x im Intervall [t0 , t1 ) nicht nur die Nachrichten NOTIFY, GET PREDECESSOR und GET SUCCESSORS an seinen Nachfolger sendet, sondern zus¨atzlich seinem Vorg¨anger y die Anfrage GET PREDECESSOR und GET SUCCESSORS beantworten muss. Hierzu sendet er die Nachrichten PREDECESSOR IS und SUCCESSORS ARE.17 Eine Besonderheit der vorliegenden Implementierung besteht darin, dass die Nachfolgerliste nicht bei jeder Stabilisierung aktualisiert werden muss. Die H¨aufigkeit der Aktualisierung ist durch einen Parameter u der Konfigurationsdatei ver¨anderbar.18 Dieser gibt an, wie viele Stabilisierungen durchgef¨ uhrt werden, bis eine Aktualisierung der Nachfolgerliste stattfindet. Ein Peer versendet somit insgesamt je Stabilisierungsintervall die Nachrichten: GET PREDECRESSOR PREDECRESSOR IS NOTIFY GET SUCCESSORS SUCCESSORS ARE Summe

1 Bytes 32 Bytes 32 Bytes 1 u Bytes 1+32∗j Bytes u 65 +

2+32∗j u

Bytes

17

W¨ are der Chord-Ring nicht statisch, so k¨ onnten mehrere Peers den gleichen Nachfolger x besitzen, weshalb x im Intervall [ti , ti+1 ) mehr als eine Nachricht PREDECESSOR IS bzw. SUCCESSORS ARE senden m¨ usste. 18 Eine Aufstellung der Parameter der Kondigurationsdatei befindet sich in Anhang D.

54

5 Experimentelle Analyse In den bisherigen Kapiteln wurde der Chord-Algorithmus aus theoretischer Perspektive betrachtet. Die dabei getroffenen Aussagen bezogen sich haupts¨achlich auf generelle Eigenschaften von Chord, wie der Durchf¨ uhrung von Lookups mit Pfadl¨ange O(log n), oder der Robustheit von Chord-Ringen gegen¨ uber Ausf¨allen von Peers. Zu den rein implementierungsspezifischen Eigenschaften geh¨orten der Bandbreitenverbrauch der versendeten Nachrichten. Dieses Kapitel besch¨aftigt sich nun mit der ¨ experimentellen Uberpr¨ ufung dieser grundlegenden Eigenschaften. Hierzu wurden, auf der Grundlage der in Kapitel 4 beschriebenen Implementierung, verschiedene Experimente durchgef¨ uhrt. Da mit diesen Experimenten die grundlegende Eigenschaften von Chord, wie die Suche mit logarithmischer Pfadl¨ange, best¨atigt werden sollten, reichte es aus, die Experimente auf einem System durchzuf¨ uhren, bei dem die Netzwerkkommunikation der Peers u ¨ber die Loopback-Adresse localhost erfolgt. Hierzu wurde ein PC mit 3GHz Intel Pentium IV CPU, sowie Java Version 1.4.2 verwendet. Neben den in dieser Arbeit durchgef¨ uhrten Experimenten wurden weitere Experimente durchgef¨ uhrt, bei denen Chord in einem realen Netzwerk eingesetzt wurde [8, 9].

5.1 Der statische Chord-Ring Ziel dieses Abschnitts ist die Analyse der Durchf¨ uhrung eines Lookups im statischen Chord-Ring. Das Augenmerk liegt dabei auf der L¨ange des Suchpfades, sowie der f¨ ur den Lookup ben¨otigten Zeit.

5.1.1 Lookups im statischen Chord-Ring Zur Untersuchung der Lookups im statischen Chord-Ring wurden Chord-Ringe mit unterschiedlicher Peeranzahl N ={5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 32, 48, 64} instantiiert. Die ChordID der Peers wurde zuf¨allig gew¨ahlt. F¨ ur jede Peeranzahl n ∈ N wurden von jedem der n Peers aus, 5001 zuf¨allig gew¨ahlte Schl¨ ussel gesucht. Die Suche erfolgte dabei in Runden, wobei in jeder Runde nacheinander von jedem der

55

5.1 Der statische Chord-Ring n Peers ein Schl¨ ussel gesucht wurde. Insgesamt wurden also in den 5001 Runden k = n ∗ 5001 Schl¨ ussel gesucht. F¨ ur jeden Schl¨ ussel wurde dabei die L¨ange des Suchpfades und die Suchdauer ermittelt. Dauer der Suche Zur Betrachtung der Suchdauer wurden f¨ ur jede Peeranzahl n ∈ N eine Messreihe erstellt. Anschließend wurde die Suchdauer von allen k = n ∗ 5001 gesuchten Schl¨ usseln ausgewertet und das 25%-Quartil, der Median, das 75%-Quartil, sowie das arithmetische Mittel von allen k Suchdauern gebildet. Abbildung 5.1 stellt die Ergebnisse grafisch dar. Je gr¨oßer die Pfadl¨ange bei der Durchf¨ uhrung eines Lookups ist, je mehr Peer haben den Lookup weitergeleitet. Da jede Weiterleitung eine gewisse Zeit beansprucht, ist die mit der Anzahl der Peers steigende Dauer zur Durchf¨ uhrung eines Lookups ein erstes Indiz daf¨ ur, dass mit steigender Peeranzahl auch die die Pfadl¨ange einer Suche tats¨achlich ansteigt.

180 160

Lookupzeit [ms]

140 120 100 80 60 40 20 0 0

10

20

30

40

50

60

70

Peeranzahl 25%-Quartil

Median

75%-Quartil

Mittel

Abbildung 5.1: Durchschnittlich Suchdauer im statischen Chord-Ring Da die Peers alle auf einem System ausgef¨ uhrt wurden, und kein echtes Netzwerk ver-

56

5.1 Der statische Chord-Ring wendet wurde, sagen die gemessenen Zeiten jedoch nichts u ¨ber die Zeiten aus, wenn Chord in einem echten Netzwerk eingesetzt wird. In einem echten Netzwerk kann es so z. B. vorkommen, dass nicht alle Verbindungen zwischen den Peers die Daten mit der gleichen Geschwindigkeit u ¨bertragen, so dass es hier zu Zeitverz¨ogerungen und damit zu l¨angeren Lookup-Zeiten kommen kann. L¨ ange des Suchpfades

Anzahl der Suchen

Zur Messung der L¨ange des Suchpfades wurden f¨ ur jedes n ∈ N jeweils 10 Messreihen erstellt. Insgesamt wurden also f¨ ur jede Peeranzahl k = 10 ∗ n ∗ 5001 zuf¨allige Schl¨ ussel gesucht. Bei der Auswertung wurden dann f¨ ur jedes n ∈ N die aufgetretenen Pfadl¨angen L aus allen 10 Messreihen bestimmt. Im Anschluss daran wurden f¨ ur jedes l ∈ L alle Suchen mit der entsprechenden Pfadl¨ange gez¨ahlt. Abbildung 5.2 die Ergebnisse f¨ ur n={8, 16, 32, 48, 64} Peers.

8

16

32

48

64

Peers Pfadlänge

0

1

2

3

4

5

6

7

Abbildung 5.2: Pfadl¨ange: Suche im statischen Chord-Ring (absolut) In dieser Abbildung best¨atigt sich, dass die Pfadl¨ange mit wachsender Peeranzahl ansteigt. Dabei steigt die Pfadl¨ange wie erwartet logarithmisch zur Anzahl der Peers. So betr¨agt z. B. die ermittelte maximale Pfadl¨ange f¨ ur Chord-Ringe mit 8 Peers 4 Schritte, mit 16 Peers 5 Schritte und f¨ ur Chord-Ringe mit 32 Peers 6 Schritte.

57

5.1 Der statische Chord-Ring Die Verteilung der auftretenden Pfadl¨angen entspricht dabei ungef¨ahr einer GaußVerteilung. Die absolute Anzahl der Suchen der Pfadl¨ange l w¨achst mit steigender Peeranzahl n, da f¨ ur jede Messreihe 10 ∗ n ∗ 5001 Schl¨ ussel gesucht wurden. Die Pfadl¨ange L = 0 entsteht, da ein Peer auch selbst f¨ ur den von ihm gesuchten Schl¨ ussel zust¨andig sein kann und deshalb keinen anderen Peer befragen muss. Chord verspricht, dass die Pfadl¨ange f¨ ur Suchen in einem Chord-Ring mit n Peers mit hoher Wahrscheinlichkeit O(log n) betr¨agt. Um dies zu u ufen wurde f¨ ur ¨berpr¨ jedes n der Anteil aller innerhalb der Pfadl¨ange l erfolgreichen Suchen berechnet. Abbildung 5.3 stellt die Ergebnisse f¨ ur Chord-Ringe mit n={8, 16, 32, 48, 64} Peers 1 dar. 110%

Anteil der beendeten Suchen

100% 90% 80% 70% 60% 50% 40% 30% 20% 10% 0% 0

1

2

3

4

5

6

7

8

Pfadlänge 8

16

32

48

64

Abbildung 5.3: Pfadl¨ange: Suche im statischen Chord-Ring (prozentual)

Hierbei stellte sich heraus, dass der Anteil der erfolgreichen Suchen mit Erreichen der Pfadl¨ange bl = log nc in fast allen F¨allen mehr als 99% betr¨agt. Es wird also nur f¨ ur einen sehr geringen Teil der Suchen eine gr¨oßere Pfadl¨ange ben¨otigt. Die Pfadl¨ange f¨ ur Suchen liegt also mit hoher Wahrscheinlichkeit in O(log n).

1

Eine Auswertung des Experiments in tabellarischer Form bietet Tabelle B.1 in Anhang B.

58

5.1 Der statische Chord-Ring

5.1.2 Nachrichtenaufkommen durch Lookups Nachdem im Abschnitt 5.1.1 gezeigt wurde, dass ein Lookup mit hoher Wahrscheinlichkeit nach O(log n) Schritten beendet ist, befasst sich dieser Abschnitt nun damit, wie viele Nachrichten insgesamt f¨ ur eine Suche ben¨otigt werden. Zur Z¨ahlung der Lookup-Nachrichten, die insgesamt im Chord-Ring versendet werden, wurde ein Experiment durchgef¨ uhrt. Da die Pfadl¨ange und somit die Anzahl der f¨ ur einen Lookup ben¨otigten Nachrichten von der Anzahl der Peers abh¨angt, wurden Messreihen f¨ ur die Menge der Peers N ={5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 32, 48, 64} durchgef¨ uhrt. Die ChordIDs der Peers waren dabei zuf¨allig gew¨ahlt. Bei der Durchf¨ uhrung des Experiments wurden in jedem Chord-Ring der Gr¨oße n ∈ N ¨ von jedem Peer je 5001 zuf¨allig gew¨ahlte Schl¨ ussel gesucht. Uber die Dauer des Experiments wurden f¨ ur jeden Peer die Anzahl der von ihm weitergeleiteten Lookups sowie die Anzahl der von ihm gesuchten Schl¨ ussel gez¨ahlt. Wie in Abschnitt 5.1.1 bereits erw¨ahnt, kann ein Peer auch selbst f¨ ur den von ihm gesuchten Schl¨ ussel verantwortlich sein. Deshalb muss er nicht f¨ ur alle der 5001 von ihm gesuchten Schl¨ ussel einen Lookup durchf¨ uhren. Aus diesem Grund wurde außerdem f¨ ur jeden Peer die Anzahl der Schl¨ ussel gez¨ahlt, f¨ ur die der Peer tats¨achlich einen Lookup durchf¨ uhren musste. Ein Problem bei diesem Experiment stellte das Aktualisieren der Fingertabelle dar, da hierbei ebenfalls nach Schl¨ usseln gesucht wird.2 Die Anzahl der Aktualisierungen der Finger, und die damit einhergehenden Lookup-Nachrichten, nehmen mit der Dauer des Experiments zu. Um die Ergebnisse aus den Einzelexperimenten miteinander vergleichen zu k¨onnen, musste jedoch in jedem Experiment von jedem Peer die gleiche Anzahl Schl¨ ussel gesucht werden. Da mit steigender Peeranzahl im Chord-Ring jedoch insgesamt mehr Schl¨ ussel gesucht wurden, nahm die Dauer der Experimente und damit die Anzahl der durch die Aktualisierung der Fingertabelle verursachten Lookups zu. Aus diesem Grund wurden f¨ ur dieses Experiment statische Chord-Ringe verwendet. Da sich diese nicht ver¨andern, war es m¨oglich f¨ ur jeden Peer die Fingertabelle einmalig zu berechnen und anschließend die Aktualisierung der Finger abzuschalten.3

2 3

vgl.: Abschnitte 2, 3.3.5 und 4.1.3 Ein Abschalten der Stabilisierung wurde trotz der Verwendung statischer Chord-Ringe nicht durchgef¨ uhrt, da sie die Ergebnisse des Experiments nicht beeinflusst.

59

5.1 Der statische Chord-Ring Da eine Nachricht mit hoher Wahrscheinlichkeit maximal O(log n) mal weitergeleitet wird, betr¨agt die Anzahl der Nachrichten, die f¨ ur einen Lookup ben¨otigt werden O(log n). Sucht eine Peer nun nach k Schl¨ usseln, so werden daf¨ ur k ∗ O(log n) Lookup-Nachrichten ben¨otigt. Suchen alle n Peers nach k Schl¨ usseln, so werden daf¨ ur insgesamt n ∗ k ∗ O(log n) Lookup-Nachrichten gebraucht. Sind die Peers gleichm¨aßig u ur ¨ber den Chord-Ring verteilt, so ist mit hoher Wahrscheinlichkeit jeder der Peers f¨ k∗n k = n der gesuchten Schl¨ ussel verantwortlich. Ferner wird jeder Peer die gleiche Anzahl an Nachrichten weiterleiten. Bei der Auswertung des Experiments wurde deshalb das arithmetische Mittel aus den von den einzelnen Peers ermittelten Werten gebildet. Dies erfolgte f¨ ur die insgesamt von einem Peer gesendeten Nachrichten (gesamt), die von einem Peer gestellten Lookups (erzeugt) und die von einem Peer weitergeleiteten Nachrichten (weitergeleitet). Dabei gilt: gesamt = erzeugt + weitergeleitet 16000

14000

Lookup-Nachrichten pro Peer

12000

10000

8000

6000

4000

2000

0 0

10

20

30

40

50

60

70

Peeranzahl gesamt

erzeugt

weitergeleitet

O(log n)

Abbildung 5.4: Nachrichtenanzahl (KEY LOOKUP) Abbildung 5.4 zeigt, dass die Anzahl der Lookup-Nachrichten pro Peer (gesamt) logarithmisch mit der Anzahl n der im Chord-Ring vorhandenen Peers ansteigt. Sind n Peers gleichm¨aßig im Chord-Ring verteilt, und werden in diesem k zuf¨allig gew¨ ahlte Schl¨ ussel gesucht, so ist jeder der n Peer mit hoher Wahrscheinlichkeit f¨ ur

60

5.2 Der dynamische Chord-Ring genau einen Schl¨ ussel verantwortlich. Werden in einem Chord-Ring mit n Peers von einem einzigen Peer k zuf¨allig gew¨ahlte Schl¨ ussel gesucht, so muss dieser Peer mit hoher Wahrscheinlichkeit f¨ ur nur k-1 Schl¨ ussel einen Lookup durchf¨ uhren. Bei einem der k Schl¨ ussel wird er jedoch direkt entscheiden k¨onnen, dass sein Nachfolger der zust¨andige Peer ist. In der vorliegenden Implementierung pr¨ uft ein Peer jedoch zus¨atzlich, ob er nicht selbst der verantwortliche Peer ist. Dies ist ohne weiteres m¨oglich, da ein Peer nicht nur seinen Nachfolger, sondern auch seinen Vorg¨anger kennt. Durch dieses Vorgehen muss der Peer dann nur noch f¨ ur k-2 Schl¨ ussel einen Lookup durchf¨ uhren. Insgesamt nimmt die Anzahl der tats¨achlich durchzuf¨ uhrenden Lookups mit der Anzahl der Peers im Chord-Ring zu, wie die Kurve erzeugt in Abbildung 5.4 zeigt. Die Kurve zeigt ebenfalls, dass sich die Anzahl der tats¨achlich durchzuf¨ uhrenden Lookups mit steigender Peeranzahl n an k = 5001 ann¨ahert, da ein Peer f¨ ur die k n−2 zuf¨ allig gew¨ahlten Schl¨ ussel in n ∗ k F¨allen einen Lookup durchf¨ uhren muss. Hier ist auch zu erkennen, dass in Chord-Ringen mit vielen Peers, kein großer Vorteil entsteht, wenn ein Peer zus¨atzlich entscheidet, ob er selbst f¨ ur einen Schl¨ ussel verantwortlich ist. W¨ urde er dies nicht tun und nur entscheiden, ob sein Nachfolger f¨ ur einen gesuchten Schl¨ ussel verantwortlich ist, so m¨ usste der Peer in n−1 allen n ∗ k F¨ einen Lookup durchf¨ uhren. n−1 In diesem Fall w¨ urden n−2 mal mehr Lookup-Nachrichten erzeugt werden. Da aber f¨ ur Chord-Ringe mit vielen Peers n−1 =1 n→∞ n − 2 lim

gilt, ist der Vorteil praktisch nur f¨ ur Chord-Ringe mit wenigen Peers vorhanden.

5.2 Der dynamische Chord-Ring In n¨achsten Schritt wurden dynamische Chord-Ringe untersucht. Hierbei wurden sowohl die Durchf¨ uhrung von Lookups, als auch die Korrektheit des Stabilisierungsprotokolls untersucht.

5.2.1 Lookups im dynamischen Chord-Ring Wie bei den Experimenten zum statischen Chord-Ring wurden bei diesem Experiment Chord-Ringe mit unterschiedlicher Peeranzahl N ={8, 16, 32, 48, 64} untersucht. Die ChordID der Peers wurde wieder zuf¨allig gew¨ahlt. Im Gegensatz zum sta-

61

5.2 Der dynamische Chord-Ring tischen Chord-Ring wurden jedoch w¨ahrend der gesamten Laufzeit des Experiments neue Peers hinzugef¨ ugt bzw. es verließen Peers den Chord-Ring. Um die Peeranzahl w¨ahrend der Dauer der Experimente konstant zu halten wurde ein Peeraustausch ausgef¨ uhrt, d. h. es wurde immer dann ein neuer Peer hinzugef¨ ugt, wenn ein anderer den Chord-Ring verließ. Der Peer, der den Chord-Ring verließ, wurde aus den n ∈ N Peers des Chord-Rings zuf¨allig ausgew¨ahlt, d. h. jeder Peer verließ mit der Wahrscheinlichkeit p = N1 den Chord-Ring. Im Folgenden wird die Zeitdauer, die zwischen dem Austauschen zweier Peers liegt, als Join-Leave-Zeit bezeichnet. Die sich daraus ergebende Frequenz, mit der Peers ausfallen und hinzukommen, wird mit Join-Leave-Frequenz bezeichnet. Die Join-LeaveFrequenz gibt die Ver¨anderungsrate des Chord-Rings an. Dabei gilt: 1 . Join − Leave − F requenz = Join−Leave−Zeit Um untersuchen zu k¨onnen, wie sich unterschiedliche Join-Leave-Zeiten auf die Lookups auswirken, wurden f¨ ur jede Peeranzahl n ∈ N Messreihen mit den Join-LeaveZeiten T ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35} Sekunden durchgef¨ uhrt. F¨ ur jedes Tupel (N,T) wurden dann jeweils 5 Chord-Ringe instantiiert. In jedem ChordRing wurden dann nacheinander 5001 Schl¨ ussel gesucht. F¨ ur jeden neuen gesuchten Schl¨ ussel wurde dabei ein Peer als suchender Peer zuf¨allig aus den vorhandenen Peers bestimmt. W¨ahrend der Experimente wurden von jedem Peer alle 1.5 Sekunden eine Stabilisierung durchgef¨ uhrt, sowie ein Finger aktualisiert. Der Exponent der Chord-Rings betrug m = 16, d. h. jeder Peer hatte 16 Finger. Fehlgeschlagene Versuche Abbildung 5.5 zeigt den Anteil der Schl¨ ussel, f¨ ur die der verantwortliche Peer innerhalb der maximalen Suchdauer von 35 Sekunden oder der maximalen Pfadl¨ange 2m nicht gefunden werden konnte. Sie zeigt, dass die Anzahl der fehlgeschlagenen Lookups f¨ ur gleich bleibende Join-Leave-Zeiten bei steigender Peeranzahl abnimmt. Ebenso sinkt die Anzahl fehlgeschlagener Lookups, wenn die Peeranzahl konstant bleibt, die Join-Leave-Frequenz jedoch abnimmt, d. h. die Join-Leave-Zeit vergr¨oßert wird. Ein Teil der fehlgeschlagenen Versuche l¨asst sich auf die Begrenzung der Pfadl¨ange auf 2m zur¨ uckf¨ uhren.4 Der Anteil den diese aber an den insgesamt fehlgeschlagenen 4

vgl.: Abschnitt 4.1.3

62

5.2 Der dynamische Chord-Ring 0.6

nicht gefundene Schlüssel [%]

0.5

0.4

0.3

0.2

0.1

0 0

5

10

15

20

25

30

35

40

Join-Leave-Zeit [s] 8 Peers

16 Peers

32 Peers

48 Peers

64 Peers

Abbildung 5.5: Anteil fehlgeschlagener Suchen im dynamischen Chord-Ring Versuche haben ist jedoch sehr gering. Diese Vermutung legt zumindest die Verteilung der Pfadl¨angen f¨ ur Lookups in dynamischen Chord-Ringen, wie sie in den Abbildungen 5.7 und 5.8 dargestellt sind, nahe. Der Großteil der fehlgeschlagenen Versuche l¨asst sich jedoch auf die Korrektheit der Fingertabellen zur¨ uckf¨ uhren. Je mehr Eintr¨age der Fingertabelle nicht korrekt sind und/oder auf ausgefallene Peers verweisen, je gr¨oßer wird die Wahrscheinlichkeit, dass es im Laufe eines Lookups zu Zyklen im Suchpfad kommt. Hierdurch kommt ¨ es zur Uberschreitung der maximalen Suchdauer, so dass timeouts auftreten. Zudem birgt eine nicht korrekten Fingertabelle einen gewissen R¨ uckkopplungseffekt, da zur Aktualisierung der Fingertabelle Lookups durchgef¨ uhrt werden, die ebenfalls mit h¨oherer Wahrscheinlichkeit fehlschlagen. Wenn z. B. alle tf ix = 1.5 Sekunden ein Finger aktualisiert wird, dauert es bei 16 Fingern mindestens 24 Sekunden bis alle Finger aktualisiert wurden.5 Wenn jeder Peer mit der Wahrscheinlichkeit p = N1 ausf¨allt und pro Sekunde ein Peer ausgetauscht wird (tjl = 1), dann werden in diesen 24 Sekunden insgesamt 24 Peers ausgetauscht. 5

Wird auf Grund der Dynamik, der f¨ ur einen Schl¨ ussel zust¨ andige Peer nicht gefunden, kann die komplette Aktualisierung der Finger l¨ anger dauern.

63

5.2 Der dynamische Chord-Ring In einem Chord-Ring mit n = 8 Peers wird so in 24 Sekunden mit hoher Wahrscheinlichkeit jeder Peer mindestens einmal ausgetauscht, so dass es sehr wahrscheinlich ist, dass die Fingertabelle nicht korrekt ist. Ein Maß f¨ ur die Korrektheit der Fingertabelle ist die Anzahl der nicht korrekten Finger Λ. Sei: n = Anzahl der P eers m = Anzahl der F inger tf ix = F inger Aktualisierungsintervall tjl = Join − Leave − Zeit Dann berechnet sich die Anzahl der nicht korrekten Finger: (

Λ = min

m ∗ tf ix ,n tjl

)

Im obigen Beispiel sind somit Λ = 8 Finger nicht korrekt gesetzt. Wie in [43] gezeigt wird, sind in einem Chord-Ring mit n Peers jedoch nur O(log n) Eintr¨age der Fingertabelle tats¨ achlich verschieden. Es ist also m¨oglich, dass sich zwei nicht korrekte Eintr¨age der Fingertabelle auf den gleichen Peer beziehen. Das Maß Λ muss somit verfeinert werden. Sei: n = Anzahl der P eers im Chord − Ring Dann ist das Maß f¨ ur die Korrektheit der Fingertabelle: λ=

log n ∗ tjl log n = Λ m ∗ tf ix

Die Korrektheit der Fingertabelle λ steigt also je mehr Peers im Chord-Ring vorhanden sind, da mit steigender Peeranzahl mehr Eintr¨age der Fingertabelle tats¨achlich unterschiedlich sind. Hierdurch wirkt sich der Ausfall eines Peers im besten Fall dann nur noch auf einen Eintrag der Fingertabelle aus. So betr¨agt das Maß f¨ ur die Korrektheit der Fingertabelle in einem Chord-Ring mit n = 16 Peers, bei tjl = 1 Sekunde und tf ix = 1.5 Sekunden λ = 61 , w¨ahrend im obigen Beispiel mit n = 8 Peers λ = 81 betr¨agt. Außer mit einer steigenden Peeranzahl erh¨oht sich λ, je gr¨oßer die Join-Leave-Zeiten im Vergleich zum Aktualisierungsintervall der Finger werden. Je gr¨oßer der Quotient tjl tf ix wird, desto mehr Finger werden zwischen dem Austausch zweier Peers aktualisiert, wodurch sich wiederum die Korrektheit der Fingertabelle verbessert. So betr¨agt

64

5.2 Der dynamische Chord-Ring im Chord-Ring aus dem obigen Beispiel das Maß f¨ ur die Korrektheit der Fingerta1 belle λ = 8 . Werden die Peers nun nicht mehr so h¨aufig ausgetauscht, sondern z. B. nur alle tjl = 2 Sekunden so steigt das Maß f¨ ur die Korrektheit der Fingertabelle auf 1 λ = 4 . Allgemein gilt: Je gr¨oßer λ desto korrekter die Fingertabelle.

Dauer der Suche Bei der Auswertung der Experimente wurden f¨ ur jedes Tupel (N,T) das arithmetische Mittel u ussel ¨ber alle Suchdauern der in den 5 Einzelexperimenten gesuchten Schl¨ gebildet. Abbildung 5.6 zeigt, dass die Suchdauer abnimmt, je gr¨oßer die Join-LeaveZeit wird, d. h. je mehr Zeit zwischen dem Austausch zweier Peers vergeht. Umgekehrt nimmt die durchschnittliche Suchdauer mit k¨ urzeren Join-Leave-Zeiten zu, da bei hoher Ver¨anderungsrate die Eintr¨age der Fingertabelle mit h¨oherer Wahrscheinlichkeit nicht korrekt sind als bei niedrigen Ver¨anderungsraten. Dadurch dass die Eintr¨age der Fingertabelle bei kurzen Join-Leave-Zeiten weniger korrekt sind, verschiebt sich die Verteilung der Pfadl¨angen so, dass der Anteil der Suchen mit gr¨oßerer Pfadl¨ange h¨oher ist als bei einer großen Join-Leave-Zeit. Auch treten die Ausreißer bei den Pfadl¨angen, d. h. Pfadl¨angen die deutlich gr¨oßer als log n sind, nur bei kleinen JoinLeave-Zeiten auf. Neben der Abh¨angigkeit der durchschnittlichen Suchdauer von der 400

350

Lookup-Dauer [ms]

300

250

200

150

100

50

0 0

5

10

15

20

25

30

35

40

Join-Leave-Zeit [s] 8 Peers

16 Peers

32 Peers

48 Peers

64 Peers

Abbildung 5.6: Durchschnittliche Suchzeit f¨ ur dynamische Chord-Ringe

65

5.2 Der dynamische Chord-Ring Join-Leave-Zeit, ist in Abbildung 5.6 eine Abh¨angigkeit von der Anzahl der im ChordRing vorhandenen Peers zu erkennen. So nimmt die durchschnittliche Suchdauer mit steigender Peeranzahl zu. Dies h¨angt wiederum damit zusammen, dass die Pfadl¨ange mit der Anzahl der Peers im Chord-Ring w¨achst. L¨ ange des Suchpfades Im Vergleich zu den Lookups im statischen Chord-Ring ¨andert sich die L¨ange der Suchpfade in dynamischen Chord-Ringen nicht wesentlich. Bei Suchen in ChordRingen mit kurzen Join-Leave-Zeiten treten vereinzelt gr¨oßere Pfadl¨angen auf. Diese lassen sich auf nicht mehr aktuelle Eintr¨age in den Fingertabellen zur¨ uckf¨ uhren. Wie bei Lookups im statischen Chord-Ring entspricht auch hier die Verteilung der Pfadl¨angen wieder ungef¨ahr einer Gauß-Verteilung.

10000 16 Peers

Gesamtanzahl

1000

100

10

1 0

5

10

15

20

25

30

Pfadlänge Join/Leave [s]

1

2

3

4

5

6

7

8

9

10

15

20

25

30

35

Abbildung 5.7: Pfadl¨ange f¨ ur 16 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten An dieser Stelle werden exemplarisch die Pfadl¨angen f¨ ur Chord-Ringe mit 16 bzw. 6 64 Peers in den Abbildungen 5.7 und 5.8 dargestellt. Die Abbildungen zeigen, dass die Pfadl¨angen f¨ ur Lookups auch f¨ ur dynamische Chord-Ringe immer noch mit hoher 6

Die Pfadl¨ angen f¨ ur Chord-Ringe mit 8, 32 und 48 Peers befinden sich im Anhang B.

66

5.2 Der dynamische Chord-Ring

10000 64 Peers

Gesamtanzahl

1000

100

10

1 0

5

10

15

20

25

30

Pfadlänge Join/Leave [s]

1

2

3

4

5

6

7

8

9

10

15

20

25

30

35

Abbildung 5.8: Pfadl¨ange f¨ ur 64 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten 5 Durchschnittliche Pfadlängen

durchschnittliche Pfadlänge

4

3

2

1

0 0

10

20

30

40

50

60

70

Peers t_jl = 10 Sekunden

t_jl = 35 Sekunden

log n

Abbildung 5.9: Durchschnittliche Pfadl¨ange in dynamischen Chord-Ringen

67

5.2 Der dynamische Chord-Ring Wahrscheinlichkeit in O(log n) liegen, wenngleich die Pfadl¨angen im Schnitt ein wenig l¨anger sind. So sind im statischen Chord-Ring mit 16 Peer die meisten Suchen nach einer Pfadl¨ange von 5 Schritten erfolgreich, w¨ahrend in dynamischen Chord-Ringen mit 16 Peers die meisten Suchen erst mit der Pfadl¨ange 6 abgeschlossen sind. Dass die Pfadl¨angen wie im Fall von statischen Chord-Ringen logarithmisch zur Peeranzahl ansteigen, zeigt Abbildung 5.9. Diese bildet die durchschnittliche Pfadl¨ange f¨ ur die Join-Leave-Zeiten tjl = 10 und tjl = 35 ab.

5.2.2 Systemstabilit¨ at Dieser Teil untersucht die Korrektheit des Stabilisierungsprotokolls. Hierzu wird untersucht, ob es unter bestimmten Voraussetzungen dazu kommen kann, dass das Stabilisierungsprotokoll die Korrektheit der Nachfolger nicht mehr gew¨ahrleisten kann. So besitzt Chord u. a. die Eigenschaft, dass die H¨alfte aller Peers gleichzeitig ausfallen kann, der Chord-Ring jedoch verbunden bleibt.7 Neben der experimentellen ¨ Uberpr¨ ufung dieser Eigenschaft untersucht dieser Abschnitt die Korrektheit des Stabilisierungsprotokoll auf Abh¨angigkeit von folgenden Einfl¨ ussen: Anzahl der Peers im Chord-Ring, Zeit zwischen zwei Ausf¨ uhrungen des Stabilisierungsprotokolls und Ver¨anderungsrate des Chord-Rings. Ein recht intuitives Maß, welches von den Faktoren Peeranzahl, Zeit zwischen zwei Stabilisierungen und Ver¨anderungsrate eines Chord-Rings abh¨angt, ist die Halbwertzeit (half-life) eines P2P-Systems [24]. Diese ist wie folgt definiert: Gegeben sei zur Zeit t ein P2P-System mit N aktiven Peers. Die doubling time von ” t ist die Zeit, die von t aus vergeht, bis N zus¨ atzliche Peers hinzugekommen sind. Die halving time von t ist die Zeit, die von t aus vergeht, bis sich die Anzahl der Peers halbiert hat. Die half-life von t ist die kleinere der beiden Zeiten doubling time und halving time. Die half-life eines P2P-Systems ist das Minimum aller half-life Zeiten t.“ ¨ Uber die Halbwertzeit l¨asst sich folgende Aussage treffen: Ein beliebiges P2P-System mit N Peers bleibt dann verbunden, wenn f¨ ur eine beliebige Sequenz aus Joins und Leaves jeder Peer innerhalb der half-life Zeit τ mindestens Ω(log N ) mal benachrichtigt wird [24].

7

vgl.: Abschnitt 3.3.3

68

5.2 Der dynamische Chord-Ring Bei Chord erfolgt diese Benachrichtigung der Peers durch das Stabilisierungsproto¨ koll. Zur Uberpr¨ ufung des Stabilisierungsprotokolls auf die Abh¨angigkeit von Peeranzahl, der Ver¨anderungsrate sowie der Zeit zwischen zwei Stabilisierungen, wurden verschiedene Experimente durchgef¨ uhrt. In allen durchgef¨ uhrten Experimenten wurde dabei der gleiche grundlegende Versuchsaufbau V1 verwendet:

Zu Beginn des Experiments wurden zun¨achst stabile Chord-Ringe der Gr¨oßen N ={8, 16, 32, 64, 128} erzeugt. Die ChordID’s der Peers wurden zuf¨allig gew¨ahlt. Im Verlauf des Experiments wurde bei jeder Stabilisierung die Liste der ersten j = 16 Nachfolger vom Nachfolger bezogen und der Vorg¨anger auf Erreichbarkeit gepr¨ uft. Aus den Chord-Ringen wurden dann im Abstand von tjl ∈ T ={0.25, 0.5, 0.75, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35} Sekunden ein Peer entfernt. Damit sich die Gr¨oße des Chord-Rings nicht ¨anderte, wurde jeweils nach der Entfernung eines Peers ein neuer Peer hinzugef¨ ugt. Der Peer, der entfernt wurde, wurde mit der 1 Wahrscheinlichkeit p = N aus allen Peers des Chord-Rings ausgew¨ahlt. Der Peer, welcher den Nachfolger des neu hinzugekommenen Peers bestimmte, wurde ebenfalls mit der Wahrscheinlichkeit p aus den verbleibenden Peers ausgew¨ahlt. F¨ ur jedes Tupel (N,T) wurden jeweils 20 Experimente durchgef¨ uhrt, wobei die Dauer der Phase in der die Peers ausgetauscht wurden auf 10 Minuten beschr¨ankt war. Nach Beendigung der Austauschphase wurden zun¨achst N Stabilisierungen abgewartet, so dass die Vorg¨anger- und Nachfolgerbeziehungen vom Stabilisierungsprotokoll korrigiert werden konnten. Danach wurde die Topologie des resultierenden Chord-Rings in einer XML-Datei im GraphXML-Format [17] gespeichert. Hierzu wurden von jedem Peer dessen ChordID, sowie sein Vorg¨anger und Nachfolger bestimmt. Bei der Auswertung wurden f¨ ur jedes Tupel (N,T) die resultierenden XML Dateien analysiert. Hierbei wurde ermittelt, wie viele Peers im Chord-Ring verblieben waren und ob alle Peers die korrekten Vorg¨anger und Nachfolger besaßen. Ein Chord-Ring, bei dem alle Peers den korrekten Vorg¨anger bzw. Nachfolger besitzen, wird im Folgenden intakter Chord-Ring genannt.

Um zu analysieren inwiefern es sich auf die Korrektheit des Stabilisierungsprotokolls auswirkt, ob die Peers ausfallen oder den Chord-Ring absichtlich verlassen, wurden auf Grundlage des Versuchsaufbaus V1 zun¨achst zwei Experimente mit der gleichen Dauer von tstab = 1.5 Sekunden zwischen den Stabilisierungen durchgef¨ uhrt. Im ersten Experiment, dem Join-Leave-Fall, verließen die Peers den Chord-Ring absichtlich

69

5.2 Der dynamische Chord-Ring und informierten vorher ihre Nachbarn.8 Im zweiten Experiment, dem Join-Fail-Fall, fielen die Peers einfach aus. Im Anschluss daran wurde untersucht, inwiefern sich unterschiedliche Stabilisierungszeiten tstab auswirken. Hierzu wurde auf Grundlage von V1 ein weiteres Experiment durchgef¨ uhrt, wobei die Peers ohne Ank¨ undigung ausfielen und tstab = 3 Sekunden betrug. Im vierten und letzten Experiment wurde dann noch das Funktionieren des Stabilisierungsprotokolls im Extremfall untersucht. Dazu wurde untersucht, ob der Chord-Ring intakt bleibt, wenn die H¨alfte aller Peers gleichzeitig ausf¨allt.9 Im Folgenden werden die Ergebnisse der einzelnen Experimente genauer beschrieben. Stabilit¨ at im Join-Leave-Fall (Stabilisierungsintervall tstab = 1.5s) Wie bereits beschrieben, wurde dieses Experiment auf Grundlage von Versuchsaufbau V1 mit der Zeit tstab = 1.5 Sekunden zwischen den Stabilisierungen durchgef¨ uhrt. Die Peers verließen dabei den Chord-Ring mit Vorank¨ undigung.

1.2

Anteil intakter Chord-Ringe

1

0.8

0.6

0.4

0.2

0 100

Join-Leave-Zeit [ms]

1000 8

16

32

48

10000 64

100000

128

Abbildung 5.10: Stabilit¨at im Join-Leave-Fall, tstab = 1.5s Die Ergebnisse des Experiments in Abbildung 5.10 zeigen, dass die Chord-Ringe mit mehr als 16 Peers auch dann mit hoher Wahrscheinlichkeit intakt bleiben, wenn 8 9

vgl.: Abschnitt 3.3.4 und 4.2.1 vgl.: Abschnitt 3.3.3

70

5.2 Der dynamische Chord-Ring die Zeitdauer zwischen dem Ausfallen zweier Peers mit tjl = 0.25 Sekunden sehr klein wird, d. h. pro Sekunde 4 Peers ausgetauscht werden. Die Ausnahme bilden dabei Chord-Ringe mit 8 Peers. Hier ist der Anteil der intakten Ringe f¨ ur sehr hohe Ver¨anderungsraten sehr gering. Ab einer Join-Leave-Zeit von 5 Sekunden sind die Ergebnisse jedoch denen von Chord-Ringen mit 16 oder mehr Peers vergleichbar.

180

160

vom Chord-Ring getrennte Peers [absolut]

140

120

100

80

60

40

20

0 100

Join-Leave-Zeit [ms]

1000 8

16

32

48

10000 64

100000 128

Abbildung 5.11: Vom Ring getrennte Peers im Join-Leave-Fall, tstab = 1.5s Abbildung 5.11 stellt die absolute Anzahl der vom Chord-Ring getrennten Peers dar. Obwohl, wie Abbildung 5.10 zeigt, die Chord-Ringe auch f¨ ur kleine tjl intakt bleiben, so sinkt die Anzahl der Peers, die im Chord-Ring verblieben sind, je kleiner tjl wird. Die absolute Anzahl der w¨ahrend des Experiments vom Chord-Ring getrennten Peers, also der Peers, die keinen Nachfolger mehr besaßen, wird somit also gr¨oßer je kleiner tjl wird. Umgekehrt wird die Anzahl der vom Chord-Ring getrennten Peers kleiner je gr¨oßer tjl . Ein Peer x wird dann vom Chord-Ring getrennt, wenn er den Chord-Ring gerade erst betreten hat, noch nicht voll in den Chord-Ring integriert ist und vor allem noch keine Nachfolgerliste bezogen hat. In diesem Fall besitzt x nur einen, n¨amlich seinen direkten Nachfolger x.successor. F¨allt dieser aus, so besitzt x keine weiteren

71

5.2 Der dynamische Chord-Ring Nachfolger mehr und wird folglich vom Chord-Ring getrennt. Im Gegensatz zum negativen Zusammenhang zwischen der Anzahl der vom ChordRing getrennten Peers und der Join-Leave-Zeit tjl , l¨asst sich aus den Ergebnissen des Experiments jedoch keine direkte Abh¨angigkeit zwischen der Anzahl der vom Chord-Ring getrennten Peers, und der Peeranzahl selbst herleiten. So werden von Chord-Ringen mit vielen Peers ungef¨ahr genau so viele Peers getrennt wie von ChordRingen mit wenigen Peers. Die Ausnahme bilden hier Chord-Ringe mit 8 Peers. Da diese nicht intakt sind, werden alle ihre Peers als vom Chord-Ring getrennte Peers gez¨ ahlt. Da in Chord-Ringen mit vielen Peers ¨ahnlich viele Peers vom Chord-Ring getrennt werden wie in Chord-Ringen mit wenigen Peers, bedeutet das, dass von Chord-Ringen mit wenigen Peers bei gleicher Join-Leave-Zeit tjl im Verh¨altnis zur Gr¨oße des Rings mehr Peers getrennt werden als bei Chord-Ringen mit vielen Peers. Als Besonderheit ist noch zu erw¨ahnen, dass in Chord-Ringen mit 8 bzw. 16 Peers u urften, da in einer 16 Peers ¨berhaupt keine Peers vom Chord-Ring getrennt werden d¨ langen Nachfolgerliste alle anderen Peers erfasst sein m¨ ussten. Hier kommt zum Tragen, dass ausgefallene Peers nicht direkt aus allen Nachfolgerlisten entfernt werden.10 Gerade bei hohen Ver¨anderungsraten sind dann viele Eintr¨age der Nachfolgerliste nicht mehr aktuell, so dass die Wahrscheinlichkeit, dass ein Peer keinen Nachfolger mehr ermitteln kann, steigt. Stabilit¨ at im Join-Fail-Fall (Stabilisierungsintervall tstab = 1.5s) Wie bereits beschrieben, wurde auch in diesem Experiment vom Versuchsaufbau V1 ausgegangen, wobei die Zeit zwischen zwei Stabilisierungen erneut tstab = 1.5 Sekunden betrug. Erneut wurde eine vollst¨andige Messreihe durchgef¨ uhrt, wobei die Peers den Chord-Ring diesmal ohne Vorank¨ undigung verließen. Abbildung 5.12 stellt die Auswertung dieses Experiments dar. Auch hier sind ChordRinge mit mehr als 16 Peers mit hoher Wahrscheinlichkeit intakt, wobei Chord-Ringe mit 8 Peers erneut die Ausnahme bilden. Ab einer Join-Leave-Zeit von 15 Sekunden sind jedoch auch hier die Ergebnisse mit Chord-Ringen mit 16 oder mehr Peers vergleichbar. Der negative Zusammenhang zwischen der Anzahl der vom Chord-Ring getrennten Peers und der Join-Leave-Zeit tjl liegt auch in diesem Experiment vor. Auch in die10

vgl.: Abschnitt 4.2.4

72

5.2 Der dynamische Chord-Ring

1.2

Anteil intakter Chord-Ringe

1

0.8

0.6

0.4

0.2

0 100

Join-Fail-Zeit [ms]

1000 8

16

32

48

10000 64

100000

128

Abbildung 5.12: Stabilit¨at im Join-Fail-Fall, tstab = 1.5s

180

160

vom Chord-Ring getrennte Peers [absolut]

140

120

100

80

60

40

20

0 100

Join-Fail-Zeit [ms]

1000 8

16

32

48

10000 64

100000 128

Abbildung 5.13: Vom Ring getrennte Peers im Join-Fail-Fall, tstab = 1.5s

73

5.2 Der dynamische Chord-Ring sem Fall ist jedoch kein eindeutiger Zusammenhang zwischen der absoluten Anzahl der vom Chord-Ring getrennten Peers und der Anzahl der Peers im Chord-Ring zu erkennen. Auff¨allig ist, wie Abbildung 5.13 zeigt, dass sich die Anzahl der vom Chord-Ring getrennten Peers gegen¨ uber dem Join-Leave-Fall im Join-Fail-Fall nur geringf¨ ugig erh¨ oht. Insgesamt kommt es gegen¨ uber dem Join-Leave-Fall zu einer geringen Verlagerung der gesamten Kurve nach rechts. Besonders gut ist das an der Kurve f¨ ur 8 Peers zu erkennen. Diese n¨ahert sich im Join-Fail-Fall erst sp¨ater und auch nicht so schnell an die Kurven f¨ ur Chord-Ringe ab 16 Peers an. Die Ank¨ undigung, den Chord-Ring zu verlassen, verbessert das Stabilisierungsprotokoll also nicht wesentlich. Wohl birgt sie aber den Vorteil, dass gespeicherte Schl¨ ussel vor Verlassen des Chord-Rings an andere Peers u ¨bertragen werden k¨onnen. Stabilit¨ at im Join-Fail-Fall (Stabilisierungsintervall tstab = 3s) Bis jetzt wurde untersucht, wie sich unterschiedliche Ver¨anderungsraten auf ChordRinge mit unterschiedlicher Peeranzahl auswirken. Dabei stellte sich heraus, dass die Anzahl der vom Chord-Ring getrennten Peers geringer wird, je geringer die Ver¨anderungsrate wird. Dar¨ uber hinaus war kein eindeutiger Zusammenhang zwischen der Anzahl der vom Chord-Ring getrennten Peers und der Anzahl der aktiven Peers festzustellen. Ferner hat sich gezeigt, dass sich die Ank¨ undigung eines Peers, den Chord-Ring zu verlassen, nicht wesentlich auf das Stabilisierungsprotokoll auswirkt. Dieser Abschnitt untersucht nun wie sich die H¨aufigkeit, mit der das Stabilisierungsprotokoll ausgef¨ uhrt wird, auswirkt. Hierzu wurde erneut ein auf Versuchsaufbau V1 basierendes Experiment durchgef¨ uhrt. Die Peers benachrichtigten die anderen Peers nicht bevor sie ausfielen, die Dauer zwischen zwei Stabilisierungen betrug tstab = 3 Sekunden. Bei der Auswertung zeigte sich erneut das gleiche Ergebnis. So sind Chord-Ringe mit 16 oder mehr Peers mit hoher Wahrscheinlichkeit intakt. Erneut sind die Ergebnisse f¨ ur Chord-Ringe mit 8 Peers erst bei einer Join-Leave-Zeit von 15 Sekunden mit den Ergebnissen in Chord-Ringen mit 16 oder mehr Peers vergleichbar. Im Unterschied zum Fall tstab = 1.5 verl¨auft die Kurve jedoch anfangs flacher und steigt dann steil an, wobei sie im Fall tstab = 1.5 eher gleichm¨aßig ansteigt. Der negative Zusammenhang zwischen der Anzahl der vom Chord-Ring getrennten Peers und der Join-Leave-Zeit tjl wird durch dieses Experiment erneut best¨atigt.

74

5.2 Der dynamische Chord-Ring

1.2

Anteil intakter Chord-Ringe

1

0.8

0.6

0.4

0.2

0 100

Join-Fail-Zeit [ms]

1000 8

16

32

48

10000 64

100000

128

Abbildung 5.14: Stabilit¨at im Join-Fail-Fall, tstab = 3s

180

160

vom Chord-Ring getrennte Peers [absolut]

140

120

100

80

60

40

20

0 100

Join-Fail-Zeit [ms]

1000 8

16

32

48

10000 64

100000 128

Abbildung 5.15: Vom Ring getrennte Peers im Join-Fail-Fall, tstab = 3s

75

5.2 Der dynamische Chord-Ring Wie in den vorangegangenen Experimenten l¨asst sich aber auch hier kein eindeutiger Zusammenhang zwischen der absoluten Anzahl der vom Chord-Ring getrennten Peers und der Anzahl der Peers im Chord-Ring feststellen. Des Weiteren ver¨andert sich die Anzahl der vom Chord-Ring getrennten Peers gegen¨ uber den Experimenten mit tstab = 1.5 nicht wesentlich, wobei auch hier ChordRinge mit 8 Peers wieder die Ausnahme bilden. Hier verl¨auft die Kurve anfangs flacher und f¨allt dann steil ab, wobei die Anzahl der abgetrennten Peers im Fall tstab = 1.5 eher gleichm¨aßig abnimmt. Dabei best¨atigt sich zumindest im Ansatz, dass bei einer half-life τ mehr Peers vom Chord-Ring getrennt werden, wenn die Zeit tstab zwischen zwei Benachrichtigungen gr¨oßer wird.

Stabilit¨ at im Extremfall - Der gleichzeitige Ausfall von 50% der Peers Eine Eigenschaft von Chord ist es, dass die H¨alfte aller Peers gleichzeitig ausfallen kann, ohne dass der Chord-Ring zerf¨allt.11 Diese Eigenschaft wurde f¨ ur Chord-Ringe mit N ={8, 16, 32, 64, 128} Peers in zwei Experimenten u uft. Hierzu wurden ¨berpr¨ jeweils f¨ ur jedes n ∈ N jeweils zwei Experimente durchgef¨ uhrt, die wiederum aus 40 Einzelexperimente bestanden. Die L¨ange der Nachfolgerliste jedes Peers betrug dabei k = 16 Eintr¨age. Nachdem der Chord-Ring instantiiert und alle Vorg¨anger und Nachfolger korrekt gesetzt waren, wurde die H¨alfte aller n Peers wieder aus dem Chord-Ring entfernt. Die entfernten Peers wurden zuf¨allig gew¨ahlt und verließen den Chord-Ring im ersten Experiment mit und im zweiten Experiment ohne Ank¨ undigung. Nachdem die Peers entfernt wurden erfolgte eine Wartezeit, so dass jeder der verbliebenen Peers mindestens n-mal das Stabilisierungsprotokoll ausf¨ uhren konnte. Nach Verstreichen dieser Zeit wurde die Topologie des resultierenden Chord-Rings wie im Versuchsaufbau V1 beschrieben gespeichert. Bei der Auswertung der Experimente zeigte sich, dass sowohl im Experiment, in dem die Peers den Chord-Ring mit Ank¨ undigung verließen, als auch im Experiment, in dem die Peers den Chord-Ring ohne Ank¨ undigung verließen, in allen F¨allen ein n intakter Chord-Ring mit 2 aktiven Peers entstanden war. 11

vgl.: Abschnitt 3.3.3

76

5.3 Bandbreitenverbrauch

5.3 Bandbreitenverbrauch Dieser Abschnitt analysiert, wie viel Netzwerkbandbreite von den Peers f¨ ur das Versenden von Nachrichten ben¨otigt wird. Dabei wird zwischen der durch Lookups und der durch die Ausf¨ uhrung des Stabilisierungsprotokolls verbrauchten Bandbreite unterschieden. Hierbei wurden f¨ ur die Durchf¨ uhrung von Lookups die Nachrichten KEY LOOKUP und KEY FOUND, und im Fall des Stabilisierungsprotokolls die Nachrichten GET PREDECESSOR, PREDECESSOR IS, GET SUCCESSORS, SUCCESSORS ARE und NOTIFY gez¨ahlt.12 Zur Messung der versendeten Daten wurden verschiedene Experimente durchgef¨ uhrt. Dabei wurden jeweils Anzahl und tats¨achliche Gr¨oße, der insgesamt versendeten relevanten Nachrichten bestimmt. Im Gegensatz zu Abschnitt 4.3 bezog sich die Gr¨oße der Nachrichten hier jedoch auf die tats¨ achliche Gr¨oße der versendeten Nachricht, also inklusive des Overheads, der durch die Verwendung von Java-ObjectStreams entsteht.13

5.3.1 Bandbreitenverbrauch durch Lookups Die durch das Versenden von Lookup-Nachrichten genutzte Bandbreite wurde anhand der vorliegenden Implementierung gemessen. eine gesonderte Messung des eingehenden Verkehrs erfolgte nicht, da die Nachrichten KEY LOOKUP und KEY FOUND die gleiche Gr¨oße besitzen und f¨ ur jeden Peer die Summe der bei ihm eingehenden Nachrichten gleich der Summe der von ihm gesendeten Nachrichten ist. Die Peers senden f¨ ur jeden von ihnen gesuchten Schl¨ ussel jeweils eine Nachricht KEY LOOKU Pgen . Ist die Suche erfolgreich, so empfangen sie daf¨ ur die Nachricht KEY F OU N Din . KEY LOOKU Pgen = KEY F OU N Din

(5.1)

Erh¨ alt ein Peer den Lookup eines anderen Peers, so empf¨angt er diesen u ¨ber die Nachricht KEY LOOKU Pin . Nun ist er entweder selbst der verantwortliche Peer, in diesem Fall sendet er KEY F OU N Dout , oder er ist nicht verantwortlich und leitet den Lookup an einen seiner Finger weiter. In diesem Fall sendet er die Nachricht KEY LOOKU Pf wd . KEY LOOKU Pin = KEY F OU N Dout + KEY LOOKU Pf wd

(5.2)

Die insgesamt gesendeten KEY LOOKUP Nachrichten setzen sich dabei aus den 12 13

vgl.: Abschnitt 4.3 vgl.: Abschnitt 4.3

77

5.3 Bandbreitenverbrauch selbst erzeugten und den weitergeleiteten Nachrichten zusammen. KEY LOOKU Pout = KEY LOOKU Pgen + KEY LOOKU Pf wd

(5.3)

Insgesamt gilt also, dass die Anzahl der eingehenden Nachrichten der Anzahl der ausgehenden Nachrichten entspricht. KEY LOOKU Pin + KEY F OU N Din = KEY LOOKU Pout + KEY F OU N Dout

(5.4)

Da die Pfadl¨ange f¨ ur Lookups von der Peeranzahl abh¨angt, ist auch zu erwarten, dass die f¨ ur Lookups ben¨otigte Bandbreite mit der Anzahl der aktiven Peers ansteigt. Um dies zu u ufen, wurde die ben¨otigte Bandbreite in statischen Chord-Ringen mit ¨berpr¨ N= {8, 16, 32, 64} aktiven Peers gemessen. Hierbei wurden f¨ ur jedes n ∈ N jeweils in Einzelexperimenten 15 Minuten lang zuf¨allig gew¨ahlte Schl¨ ussel nacheinander gesucht. F¨ ur jeden Schl¨ ussel wurde der suchende Peer zuf¨allig aus den n Peers bestimmt. Die ChordID’s der Peers wurden zuf¨allig gew¨ahlt, so dass die Peers gleichm¨aßig u ¨ber den Chord-Ring verteilt wurden. Durch die zuf¨allige Verteilung der Peers auf dem Chord-Ring, sowie die zuf¨allige Auswahl des Peers zur Suche eines zuf¨allig gew¨ahlten Schl¨ ussels ist es sehr wahrscheinlich, dass jeder Peer im Experiment gleich stark belastet wird.14 Aus diesem Grund wurden bei der Auswertung des Experiments die jeweiligen Durchschnittswerte von allen Experimenten bzw. Peers gebildet. Zur Durchf¨ uhrung dieses Experiments wurden statische Chord-Ringe verwendet. Die Durchf¨ uhrung eines solchen Experiments in dynamischen Chord-Ringen ist deshalb problematisch, da die Peers st¨ andig wechseln. So sind z. B. Peers, die nur kurz am Chord-Ring teilnehmen, nicht in den Fingertabellen der anderen Peers verzeichnet. Dadurch erhalten sie weniger Lookups und m¨ ussen auch weniger Lookups weiterleiten als andere Peers, was die gemessenen Daten verf¨alscht. Da bei den Experimenten statische Chord-Ringe zum Einsatz kamen, wurde keine Aktualisierung der Finger durchgef¨ uhrt. Aktualisiert ein Peer x in einem statischen Chord-Ring den Finger i, so sendet er einen Lookup nach Schl¨ ussel k = x.ID + 2i−1 . Wenn sich die Topologie des Chord-Rings jedoch nicht ¨andert, so ist der erste Peer an den dieser Lookup gesendet wird, i selbst, da der erste Finger ist, der dem gesuchten Schl¨ ussel am n¨achsten ist und auf dem Chord-Ring nicht hinter dem gesuchten Schl¨ ussel liegt.15 Der Lookup kann somit ohne nochmalige Weiterleitung direkt von i beantwortet werden. F¨ ur die Aktualisierung der Finger werden somit weniger Nachrichten und damit Bandbreite ben¨otigt als f¨ ur andere Lookups. W¨ urde die verwendete 14 15

vgl.: Tabelle B.4 vgl.: Abschnitt 2

78

5.3 Bandbreitenverbrauch Bandbreite unter diesen Bedingungen gemessen, so w¨ urden die Ergebnisse auch hierdurch verf¨alscht. Um zun¨achst die von einem Lookup verursachte Datenmenge zu ermitteln, wurde die Summe der von allen Chord-Peers gesendeten Datenmenge durch die Gesamtanzahl der gesuchten Schl¨ ussel geteilt. Abbildung 5.16 zeigt die so ermittelte Datenmenge und stellt sie der in Abschnitt 4.3 theoretisch berechneten Datenmenge gegen¨ uber. Sie zeigt, dass die experimentell ermittelte Datenmenge je Lookup logarithmisch mit der Peeranzahl ansteigt. Dabei betr¨agt das Gesamtvolumen der Nachrichten pro Lookup in einem Chord-Ring mit 8 Peers ca. 0.9 KB, wobei es in einem Chord-Ring mit 64 Peers auf ca. 1.7 KB pro Lookup ansteigt. 2 Datenvolumen je Lookup [KB]

KB

1.5

1

0.5

0 8

16

gemessenes Datenvolumen

Peers

32

64

vorhergesagtes Datenvolumen

Abbildung 5.16: Bandbreite pro Lookup Anhand der Datenmenge pro Lookup ist es nun m¨oglich die ben¨otigte Bandbreite in Kilobyte pro Sekunde in Abh¨angigkeit von den pro Sekunde durchgef¨ uhrten Lookups zu errechnen. Abbildung 5.17 stellt die anhand von experimentell ermittelten Werten berechnete Bandbreite, der auf Grundlage der Werte aus Abschnitt 4.3 berechneten Bandbreite gegen¨ uber. So werden in einem Chord-Ring mit 8 Peers z. B. von jedem Peer pro Sekunde ca. 4.5 KB versandt, wenn jeder Peer im Chord-Ring pro Sekunde 5 Schl¨ ussel sucht. Ohne den durch Java-ObjectStreams verursachten Overhead w¨aren

79

5.3 Bandbreitenverbrauch es dagegen nur ca. 0.8 KB/s. Ferner zeigt die Abbildung, dass die verwendete Bandbreite in KB/s linear mit der Anzahl der pro Sekunde gesuchten Schl¨ ussel ansteigt. Die anhand der vorliegenden Daten errechneten Werte liegen dabei um ca. das 6fache h¨oher als die theoretisch vorhergesagten Werte. Das bedeutet, dass durch die Verwendung der Java-ObjectStreams ungef¨ahr 6-mal mehr Daten versendet werden als eigentlich n¨otig. 20

3.5 gemessen

vorhergesagt 3

15

2.5

KB/s

KB/s

2 10

1.5 1

5

0.5 0

0 0

2

8 Peers

4

6 Lookups/s

16 Peers

32 Peers

8

10

64 Peers

12

0

2

8 Peers

4

16 Peers

6 Lookups/s 32 Peers

8

10

12

64 Peers

Abbildung 5.17: Bandbreite in KB/s f¨ ur Lookups pro Sekunde

5.3.2 Bandbreitenverbrauch durch Stabilisierung Um die f¨ ur die Stabilisierung notwendige Netzwerkbandbreite zu bestimmen, wurde die Anzahl und Gr¨oße der Nachrichten GET PREDECESSOR, PREDECESSOR IS, NOTIFY, GET SUCCESSORS und SUCCESSORS ARE gemessen. Die Messung erfolgte, wie bereits in Abschnitt 5.3.1 beschrieben, inklusive des Overheads, der durch die Verwendung von Java-ObjectStreams entsteht. Unterstellt man, wie schon in Abschnitt 4.3.2 angenommen, dass die Zeit zwischen zwei Ausf¨ uhrungen des Stabilisierungsprotokolls bei allen Peers gleich ist, so ist die Anzahl der Nachrichten, die ein Peer erh¨alt, gleich der Anzahl an Nachrichten, die der Peer versendet. Die eingehende Datenmenge entspricht also der ausgehenden Datenmenge. Aus diesem Grund wurde auch hier nur die versendete Datenmenge gemessen. W¨ahrend Stabilisierung sendet ein Peer Nachrichten an seinen Vorg¨anger und seinen Nachfolger. Im Gegensatz zu Lookups, bei denen die Pfadl¨ange mit der Anzahl der Peers steigt, ist die bei der Durchf¨ uhrung des Stabilisierungsprotokolls anfallende

80

5.3 Bandbreitenverbrauch 10000 Datenvolumen je Stabilisierung 1000

100

10

1 1.5

3

6

12

0.1

0.01 Stabilisierungsintervall [s]

KB/s

gesamt [KB]

Stabilisierungen

KB/Stabilisierung

vorhergesagt [KB/s]

Abbildung 5.18: Bandbreite Stabilisierung Datenmenge unabh¨angig von der Peeranzahl. Somit ist die durch die Stabilisierung verbrauchte Netzwerkbandbreite tats¨achlich nur von der Gr¨oße der zu versendenden Nachrichten sowie der H¨aufigkeit mit der diese versendet werden abh¨angig. Die Gr¨oße der zu versendenden Nachrichten kann jedoch noch durch die L¨ange der zu u ¨bertragenden Nachfolgerliste variieren. Letztendlich ist aber die H¨aufigkeit mit der das Stabilisierungsprotokoll durchgef¨ uhrt wird der entscheidende Faktor f¨ ur die anfallende Datenmenge. Zur Messung der belegten Bandbreite wurden deshalb mehrere Experimente mit unterschiedlichen Zeiten tstab = {1.5, 3, 6, 12} Sekunden zwischen zwei Stabilisierungen durchgef¨ uhrt. Hierbei wurde die Anzahl der versendeten Nachrichten sowie deren Gr¨oße gemessen. Die maximale L¨ange der bei einer Stabilisierung zu u ¨bertragenden Nachfolgerliste betrug hierbei 16 Nachfolger. Die Nachfolgerliste wurde bei jeder Stabilisierung u ¨bertragen. Die Anzahl der Peers im Chord-Ring betrug 32, so dass stets die maximale L¨ange f¨ ur die Nachfolgerliste erreicht wurde.16 Abbildung 5.18 zeigt f¨ ur die unterschiedlichen Zeiten tstab das insgesamt im Experiment gemessene Datenvolumen (gesamt [KB] ), den insgesamt gemessenen Bandbrei16

vgl.: Abschnitt 4.2.4

81

5.3 Bandbreitenverbrauch tenverbrauch (KB/s) sowie die Anzahl der durchgef¨ uhrten Stabilisierungen. Dar¨ uber hinaus stellt sie dem gemessenen Bandbreitenverbrauch pro Stabilisierung den in Abschnitt 4.3.2 theoretisch ermittelten Bandbreitenverbrauch pro Stabilisierung gegen¨ uber. Dies erfolgt anhand der Geraden vorhergesagt [KB/s] und KB/s. So werden pro Stabilisierung ca. 2 KB Daten versendet, so dass die belegte Bandbreite bei einem Stabilisierungsintervall von tstab = 1.5s ca. 1.2 KB/s betr¨agt. Diese nimmt linear zur Vergr¨oßerung von tstab ab. So werden f¨ ur tstab = 3s noch 0.6 KB/s und bei 0.3 KB/s ¨ f¨ ur tstab = 6s versendet. Ahnlich wie im Lookup-Fall sind auch wieder die gemessenen Werte um ca. das 3-fache h¨oher als die theoretisch berechneten. So betr¨agt z. B. das theoretisch ermittelte Datenvolumen f¨ ur tstab = 1.5s nur 0.3 KB/s und im Fall von tstab = 3s nur 0.2 KB/s.

5.3.3 Mindestbandbreitenverbrauch Bisher wurde die Bandbreite gemessen, die durch Lookups und die Ausf¨ uhrung des Stabilisierungsprotokolls verwendet wird. Die Stabilisierung ist dabei ein Faktor, der einen konstanten Bandbreitenverbrauch hervor ruft. Die von den Lookups belegte Bandbreite variiert jedoch mit der H¨aufigkeit, mit der diese durchgef¨ uhrt werden und h¨angt somit auch vom Benutzer ab. Neben der Stabilisierung ruft jedoch noch ein weiterer periodisch ausgef¨ uhrter Vorgang einen konstanten Bandbreitenverbrauch hervor: das Aktualisieren der Finger. Da das Aktualisieren der Finger durch Lookups realisiert wird, kann die daf¨ ur ben¨otigte Bandbreite mit Hilfe der Ergebnisse aus Abschnitt 5.3.1 angegeben werden. So betr¨agt z. B. in einem Chord-Ring mit 16 Peers, das durch das Aktualisieren der Fingertabelle verursachte Datenvolumen ca. 0.4 KB/s, wenn alle tf ix = 3 Sekunden ein Finger aktualisiert wird. Die Mindestbandbreite, die ein Peer belegt, ergibt sich aus der durch Stabilisierung und Aktualisieren der Fingertabelle belegten Bandbreite. Bei einem Stabilisierungsintervall von tstab = 3 Sekunden und einem Aktualisierungsintervall f¨ ur die Finger von tf ix = 3 Sekunden, betr¨agt z. B. die Mindestbandbreite in einem Chord-Ring mit 16 Peers 0.2KB/s + 0.4KB/s = 0.6KB/s. Ein Peer versendet also in diesem Fall 0.6 KB Daten in der Sekunde. Da die durch das Aktualisieren der Fingertabelle belegte Bandbreite jedoch mit der Anzahl der Peers steigt, steigt auch die Mindestbandbreite mit der Anzahl der Peers im Chord-Ring.

82

6 Zusammenfassung und Ausblick Die vorliegende Arbeit besch¨aftigt sich mit dem effizienten Routing von Suchen in P2P-Netzwerken am Beispiel des auf verteilten Hashtabellen basierenden Routingalgorithmus Chord. Chord organisiert seine Peers in einer Ringstruktur in der jeder Peer zwei Nachbarn besitzt: einen Vorg¨anger und einen Nachfolger. Mit Hilfe der Fingertabellen, mit denen ein Lookup immer mindestens die H¨alfte der Distanz zum gesuchten Peer u ¨berspringen kann, erreicht Chord, dass der f¨ ur einen gesuchten Schl¨ ussel verantwortliche Peer innerhalb von O(log n) Schritten gefunden wird. Auf Grund der Dynamik, der P2P-Systeme unterliegen, aktualisieren die Chord-Peers in regelm¨aßigen Abst¨anden sowohl ihre Nachbarn als auch ihre Finger. Wie erwartet zeigten die anhand der im Rahmen dieser Arbeit durchgef¨ uhrten Implementierung von Chord durchgef¨ uhrten Experimente, dass Suchen in O(log n) Schritten abgeschlossen sind. Die Verteilung der auftretenden Pfadl¨angen entspricht dabei ungef¨ahr einer Gauß-Verteilung, so dass die durchschnittliche Pfadl¨ange bei 21 log n Schritten liegt. Weitere Experimente haben gezeigt, dass die Korrektheit der Fingertabellen zum einen die Pfadl¨ange und somit die Performanz aber auch den Ausgang von Lookups maßgeblich beeinflussen. So hat sich einerseits gezeigt, dass sich die bei den Lookups auftretenden Pfadl¨angen vergr¨ oßern, je weniger aktuell die Fingertabelle ist. Andererseits hat sich gezeigt, dass bei weniger korrekten Fingertabellen weniger gesuchte Schl¨ ussel gefunden werden, wobei der Anteil der nicht gefundenen Schl¨ ussel in den Experimenten deutlich unter 1% lag. F¨ ur die Korrektheit der Fingertabelle gilt wiederum, dass diese einerseits steigt, je mehr Peers im Chord-Ring vorhanden sind, und sie andererseits f¨allt je ¨ofter Peers dem Chord-Ring beitreten oder diesen verlassen. Neben den Experimenten in Bezug auf die Durchf¨ uhrung von Lookups, wurden Experimente durchgef¨ uhrt, in denen Chord-Ringe einem Stresstest“ unterzogen wurden. ”

83

6 Zusammenfassung und Ausblick Hierbei hat sich gezeigt, dass die Vorg¨anger- und Nachfolgerbeziehungen zwischen den Peers auch dann noch zuverl¨assig durch das Stabilisierungsprotokoll aufrecht erhalten werden, wenn Peers in sehr kurzem Abstand den Chord-Ring betreten oder verlassen. Die Experimente zum Bandbreitenverbrauch eines Chord-Peers ergaben, dass sich die durch die Chord-Peers belegte Mindestbandbreite im moderaten Bereich bewegt. So betr¨agt diese f¨ ur in einem Chord-Ring mit 16 Peers bei ca. 0.6 KB/s wenn alle tstab = tf ix = 3 Sekunden eine Stabilisierung ausgef¨ uhrt und ein Finger aktualisiert wird. Ferner haben die Experimenten zum Bandbreitenverbrauch best¨atigt, dass der Großteil der belegten Bandbreite erst dann entsteht, wenn viele Schl¨ ussel in kurzer Zeit gesucht werden. F¨ ur die Zukunft ergeben sich f¨ ur den Chord-Algorithmus weitere Arbeitsfelder wie die gegenseitigen Authentifizierung der Peers untereinander [3] sowie die Verbesserung der Robustheit von Chord gegen¨ uber Angreifern [41], so dass St¨orungen des P2PSystems durch einzelne b¨oswillig agierende Peers verringert oder ausgeschlossen werden k¨onnen. Ein weiteres Arbeitsfeld er¨offnet die Erweiterung des DHT-Ansatzes auf Suchen, die auch die Peers finden, die f¨ ur dem gesuchten Schl¨ ussel ¨ahnliche Schl¨ ussel verantwortlich sind (Range-Queries). Bisher ist der DHT-Ansatz lediglich in der Lage, f¨ ur eine Suche entweder einen exakten Treffer oder u ¨berhaupt kein Ergebnis zu liefern. Hier bietet [48] einen m¨oglichen Ansatz.

84

FingerTable NeighbourList

FingerTable()

NeighbourList

neighbours: LinkedList neighbours: LinkedList

FingerTable()

setFinger()

setFinger()

getFinger()

NeighbourList() getNeighbour()

FingerTable

A UML-Darstellungen getFinger()

NeighbourList() getNeighbour()

Stabilizer mediator: Mediator

ist

PredecessorList PredecessorList SuccessorList

PredecessorList() SuccessorList() setPredecessor() setSuccessor() getPredecessor() setSuccessors()

Stabilizer()

mediator: Mediator mediator: Mediator

mediator: Mediator

FingerTableStabilizer() FingerTableStabilizer() setMediator()run() run() run() Stabilizer()

setMediator() run()

PredecessorList()

FingerTableStabilizer Stabilizer FingerTableStabilizer

setPredecessor() getPredecessor()

getSuccessor() getSuccessors()

er

diator

LookupMessage LookupMessage location: Location searchkey: long

DHTServer ClientFactory mediator: Mediator

hops: short LookupMessage() setSearchKey()

setMediator() run()

searchkey: long

RemoteMessage RemoteMessage

messagecommand: byte messagecommand: byte messagebody: Object messagebody: Object LookupMessage()

hops: short

ClientFactory

DHTServer()ClientFactory() DHTServer()getClient()

location: Location

ClientFactory() getClient()

getSearchKey() setLocation() getLocation() getHops() incHops() setHops()

setSearchKey() RemoteMessage() getSearchKey() getCommand() setLocation()

setCommand()

getLocation()

getBody()

getHops()

setBody()

incHops()

RemoteMessage() getCommand() setCommand() getBody() setBody()

setHops()

Abbildung A.1: UML-Klassendiagramme (1)

vii

A UML-Darstellungen

FingerTable NeighbourList

FingerTable()

neighbours: LinkedList

setFinger() getFinger()

NeighbourList() getNeighbour()

Stabilizer mediator: Mediator

PredecessorList

SuccessorList

Stabilizer() setMediator()

SuccessorList()

PredecessorList()

setSuccessor()

setPredecessor()

FingerTable

getPredecessor() NeighbourList

setSuccessors() getSuccessor()

run()

FingerTable()

neighbours: LinkedList

setFinger()

getSuccessors()

getFinger()

NeighbourList() getNeighbour()

LookupMessage Stabilizer

location: Location searchkey: long

DHTServer SuccessorList mediator: Mediator NeighbourList

DHTServer() SuccessorList() DHTServer() setSuccessor()

neighbours: LinkedList

setMediator() setSuccessors()

NeighbourList()

run() getSuccessor()

getNeighbour()

getSuccessors()

PredecessorList ClientFactory FingerTable PredecessorList() ClientFactory() FingerTable()setPredecessor() getClient() setFinger() getPredecessor() getFinger()

RemoteMes mediator: Mediator

hops: short Stabilizer()

setMediator() messagebody: O

setSearchKey()

run()

getSearchKey() setLocation()

setBody()

setHops()

FingerTableStabilizer LookupMessage

mediator: Mediator

SuccessorList()

PredecessorList()

setSuccessor()

setPredecessor()

setSuccessors()

getPredecessor()

run() mediator: Mediator

run()

ClientFactory

location: Location searchkey: long hops: short

ClientFactory()

getSearchKey()

getClient()

setLocation()

searchkey: long

setHops()

RemoteMessage

Abbildung A.2: UML-Klassendiagramme (2) hops: short

DHTServer

messagecommand: byte

mediator: Mediator

ClientFactory

DHTServer() setMediator() run()

LookupMessage() setSearchKey()

DHTServer() ClientFactory()

getSearchKey()

getClient()

setLocation() getLocation() getHops() incHops()

getCommand

setBody()

incHops()

location: Location

RemoteMessa

getBody()

getHops()

LookupMessage

messagebody:

setCommand(

getLocation()

run()

RemoteMe

messagecomm

LookupMessage() setSearchKey()

DHTServer() setMediator()

getSuccessors()

FingerTableStabilizer()

setMediator()

DHTServer()

getSuccessor()

mediator: Mediator

Stabilizer()

DHTServer

getCommand() getBody()

getHops()

Stabilizer

PredecessorList

RemoteMessag setCommand()

getLocation() incHops()

SuccessorList

messagecomma

LookupMessage()

messagebody: Object RemoteMessage() getCommand() setCommand() getBody() setBody()

setHops()

viii

B Auswertung der Experimente Peers 5 6 8 10 12 14 16 18 20 22 24 26 28 32 48 64

gesuchte Schl¨ ussel 250050 300060 400080 500100 600120 700140 800160 900180 1000200 1100220 1200240 1300260 1400280 1600320 2400480 3200640

0 99896 99956 100051 100156 100209 100395 100366 100437 99986 99903 99294 100059 99954 100330 100336 99842

1 104054 140018 158354 166015 201651 208364 193424 213280 237223 231440 251772 248411 258090 286741 288029 319537

2 42780 44963 119382 187353 232359 281123 314564 345965 387063 424168 473386 474219 495082 547564 678976 828853

Pfadl¨ ange 3 4 3320 15123 18367 3925 44141 2434 63097 2801 101356 8900 166934 20822 207312 32094 224656 47536 284100 58179 312296 58669 367946 100455 426645 110096 499502 151377 821197 426477 1066717 694405

5

6

4047 1090 3730 2426 4820 7819 10162 14784 81528 178061

1349 251 16 3901 12637

7

31

Tabelle B.1: Pfadl¨ange: Suche im statischen Chord-Ring (absolut)

Peers

Summe der bis Pfadl¨ ange i abgeschlossenen Suchen 0 1 2 3 4 5 98.6723% 5 39.9504% 81.5637% 100% 6 33.3120% 79.9753% 94.9600% 100% 8 25.0078% 64.5885% 94.4281% 99.0189% 100% 99.5133% 10 20.0272% 53.2237% 90.6868% 100% 99.5333% 12 16.6982% 50.3002% 89.0191% 100% 14 14.3393% 44.0997% 84.2522% 98.7288% 100% 16 12.5433% 36.7165% 76.0293% 96.8920% 99.4942% 100% 99.8789% 18 11.1575% 34.8506% 73.2835% 96.3136% 100% 20 9.9967% 33.7144% 72.4132% 94.8744% 99.6271% 100% 22 9.0803% 30.1162% 68.6693% 94.4915% 99.7795% 100% 99.5984% 100% 24 8.2729% 29.2497% 68.6908% 94.7103% 99.2949% 26 7.6953% 26.8001% 63.2712% 91.5691% 99.8963% 28 7.1381% 25.5695% 60.9254% 91.3939% 99.2564% 99.9821% 32 6.2694% 24.1872% 58.4032% 89.6160% 99.0752% 99.9990% 99.8362% 48 4.1798% 16.1787% 44.4637% 78.6735% 96.4399% 64 3.1200% 13.1054% 39.0066% 72.3410% 94.0408% 99.6051% rot geschriebene Zahlen markieren blog(P eeranzahl)c

6

100% 100% 100% 99.9987% 100%

7

100%

Tabelle B.2: Pfadl¨ange: Suche im statischen Chord-Ring (prozentual)

ix

B Auswertung der Experimente

10000 8 Peers

Gesamtanzahl

1000

100

10

1 0

5

10

15 Pfadlänge

Join/Leave [s]

5

6

7

8

9

20 10

15

25 20

25

30

30

35

Abbildung B.1: Pfadl¨ange f¨ ur 8 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten 10000 32 Peers

Gesamtanzahl

1000

100

10

1 0

5

10

15

20

25

30

Pfadlänge Join/Leave [s]

1

2

3

4

5

6

7

8

9

10

15

20

25

30

35

Abbildung B.2: Pfadl¨ange f¨ ur 32 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten

x

B Auswertung der Experimente

10000 48 Peers

Gesamtanzahl

1000

100

10

1 0

5

10

15

20

25

30

Pfadlänge Join/Leave [s]

1

2

3

4

5

6

7

8

9

10

15

20

25

30

35

Abbildung B.3: Pfadl¨ange f¨ ur 48 Peers in dynamischen Chord-Ringen mit verschiedenen Join-Leave-Zeiten

xi

B Auswertung der Experimente Peers Datenmenge gesamt [KB] Lookups/Peer* Median 0.25-Quartil 0.75-Quartil Standardabweichung Bandbreite pro Peer [KB/s]* Median 0.25-Quartil 0.75-Quartil Standardabweichung Datenvolumen je Lookup [KB] Lookups pro Peer und Sekunde Dauer des Experiments [s]* * Durchschnittswerte

8 2086.45 2285.07 2379 2052 2647 1032.60 2.29 2.39 1.90 2.75 0.77 0.91 2.51 908

16 953.25 872.26 918 794 999.75 233.92 1.03 1.00 0.67 1.28 0.41 1.09 0.94 924

32 458.22 353.74 355 329 378 71.07 0.48 0.44 0.34 0.62 0.20 1.29 0.37 935

64 228.90 132.17 132 124 141 21.13 0.23 0.22 0.16 0.29 0.10 1.73 0.13 975

Tabelle B.3: Durch Lookups belegte Bandbreite

Stabilisierungsintervall [ms] Datenmenge gesamt [KB] Stabilisierungen* Datenvolumen pro Stabilisierung [KB] Bandbreite [KB/s] Dauer des Experiments [s]* * Durchschnittswerte

1.5 1134.51 615 1.84 1.21 932

3 596.81 309.73 1.92 0.63 932

6 317.34 155.43 2.04 0.34 931.61

12 179.99 77.76 2.31 0.19 933.40

Tabelle B.4: Durch Stabilisierung belegte Bandbreite

xii

C Nachrichten und Nachrichtengr¨ oßen Eine Nachricht besteht aus einem Kommando und den zu dem Kommando geh¨orenden Daten. Das Kommando klassifiziert dabei die ihm folgenden Daten. Im Folgenden werden die in der vorliegenden Implementierung verwendeten Nachrichten kurz erl¨autert. Tabelle C.1 fasst den Aufbau der Nachrichten und die Gr¨oße der transportierten Informationen zusammen. • EXIT - Verbindungsabbau • GET EXPONENT - Dient zur Abfrage des Exponenten beim Eintritt (join) in den Ring. • EXPONENT IS - Beinhaltet den Exponenten des Rings. Diese Nachricht ist die Antwort auf GET EXPONENT. • FIND SUCCESSOR - Dient zu Bestimmung des Nachfolgers beim Eintritt in einen Chord-Ring. • FOUND SUCCESSOR - Antwort auf FIND SUCCESSOR. Die u ¨bermittelten Daten beschreiben den gesuchten Nachfolger. • LEAVE - Wird beim Verlassen des Rings an den Vorg¨anger und den Nachfolger geschickt. Verl¨asst Peer x den Chord-Ring, so wird diese Nachricht an den Vorg¨anger geschickt. In diesem Fall enth¨alt sie Informationen u ¨ber den Peer x, der den Ring verl¨asst, sowie den Nachfolger von x. Wird die Nachricht an den Nachfolger von x geschickt, so beinhaltet sie statt dessen Informationen u ¨ber den Vorg¨anger von x. Mit Hilfe dieser Information k¨onnen die benachrichtigten Peers unterscheiden, ob sie die Nachricht von ihrem Vorg¨anger oder ihrem Nachfolger erhalten haben. Wurde die Nachricht vom Nachfolger gesendet, so aktualisiert der Peer seinen Nachfolger, wurde sie vom Vorg¨anger gesendet, so wird der Vorg¨anger aktualisiert. • NOTIFY - Wird von Peer x an seinen Nachfolger y geschickt, um y u ¨ber die Existenz von x zu informieren. Hierbei u ¨bermittelt x seine ChordID. Wenn x

xiii

C Nachrichten und Nachrichtengr¨oßen zwischen y und dem Vorg¨anger p von y liegt, so ¨andert y seinen Vorg¨anger von p auf x. • GET PREDECESSOR - Wird beim Stabilisieren des Rings vom Peer x an dessen Nachfolger y gesendet. Liegt der Vorg¨anger p des Nachfolgers y zwischen Peer x und dessen Nachfolger y, so wird p zum neuen Nachfolger von x. • PREDECESSOR IS - Antwort auf GET PREDECESSOR. Diese Nachricht enth¨alt Informationen u ¨ber den Vorg¨anger des Peers der diese Nachricht verschickt. • GET SUCCESSORS - Wird an den Nachfolger geschickt, um von diesem eine Liste seiner Nachfolger zu erhalten. • SUCCESSORS ARE - Antwort auf GET SUCCESSORS. Die Nachricht enth¨alt eine Liste mit Informationen u ¨ber die Nachfolger des Peers, der diese Nachricht verschickt. • KEY LOOKUP - Suche nach einem Schl¨ ussel. Die Nachricht enth¨alt den gesuchten Schl¨ ussel, die Anzahl der Weiterleitungen der Nachricht und die Informationen dar¨ uber, an welchen Peer die Antwort gesendet werden soll. Erh¨alt ein Peer diese Nachricht, so pr¨ uft er zun¨achst, ob er selbst f¨ ur den gesuchten Schl¨ ussel verantwortlich ist. Falls ja, so antwortet er dem fragenden Peer, falls nicht, leitet er die Anfrage an den Peer aus seiner Fingertabelle weiter, der dem gesuchten Schl¨ ussel am n¨achsten liegt. Die Nachricht wird nicht weitergeleitet, wenn die Anzahl der Spr¨ unge, die sie bisher gemacht hat den Wert 2 ∗ exponent u ¨bersteigt. Dies verhindert, dass ein Lookup im Fall eines Zyklus immer wieder weitergeleitet wird, obwohl der suchende Peer nicht mehr auf die Antwort wartet. • KEY FOUND - Positive Antwort auf die Suche nach einem Schl¨ ussel. Die Nachricht enth¨alt Informationen u ¨ber den zust¨andigen Peer.

xiv

Nachricht ERROR EXIT GET EXPONENT EXPONENT IS FIND SUCCESSOR FOUND SUCCESSOR LEAVE NOTIFY GET PREDECESSOR PREDECESSOR IS GET SUCCESSORS SUCCESSORS ARE KEY LOOKUP KEY FOUND Java Objekt LookupMessage Location Command Wert chordID ip chordPort applicationPort searchkey lastAlive hops

Bytes 1 1 1 1+1 = 2 1+31 = 32 1+31 = 32 1+31*2 = 63 1+31 = 32 1 1+31 = 32 1 1+(31*MAX SUCCESSORS) 1+41 = 42 1+41 = 42 Bytes 8+2+31 = 41 8+15+4+4 = 31 1 Bytes 8 15 4 4 8 8 2

Tabelle C.1: Nachrichtenaufbau und -gr¨oße

Aufbau Command Command Command (Command, Byte) (Command, Location) (Command, Location) (Command, Location*2) (Command, Location) Command (Command, Location) Command (Command, Location*MAX SUCCESSORS) (Command, LookupMessage) (Command, LookupMessage) Aufbau (searchkey, hops, Location) (chordID, ip, chordPort, applicationPort) Byte Aufbau Long String(15) Integer Integer Long Long Short

C Nachrichten und Nachrichtengr¨oßen

xv

D Die Konfigurationsdatei DEFAULT RINGEXPONENT = 16

Exponent m des Chord-Rings Da ChordID als long (−263 ..263 − 1) implementiert wurde und ChordID = ID mod 2m ∈ (0..263 − 1) betr¨agt das Maximum f¨ ur m = 63

DEFAULT PORT = 22280

der von Port benutzte Netzwerkport

LOOKUP TIMEOUT = 35000

maximale Suchzeit in Millisekunden

MAX SUCCESSORS = 16

maximale L¨ange der Nachfolgerliste

FIND SUCCS INTERVAL = 1

Anzahl Stabilisierungen bis die Nachfolgerliste erneut bezogen wird

CHECK PRED INTERVAL = 1

Anzahl Stabilisierungen bis der Vorg¨anger u uft wird ¨berpr¨

STABILIZATION INTERVALL = 3000

Intervall in [ms] zwischen zwei Stabilisierungen

FIX FINGERS INTERVAL = 3000

Intervall in [ms] zwischen der Aktualisierung zweier Finger

Tabelle D.1: Parameter der Konfigurationsdatei

xvi

Literaturverzeichnis

[1] FIPS 180-1. Secure hash standard, April 1995. http://www.itl.nist.gov/fipspubs/fip180-1.htm. letzter Abruf: 21.03.2005. [2] Karl Aberer. P-Grid: A self-organizing access structure for P2P information systems. volume 2172, pages 179–194. Springer-Verlag Berlin et al., 2001. [3] Karl Aberer and Zoran Despotovic. Managing trust in a peer-2-peer information system. In Proceedings of the tenth international conference on Information and knowledge management, pages 310–317. ACM Press, 2001. [4] Karl Aberer and Manfred Hauswirth. An Overview of Peer-to-Peer Information Systems. In Distributed Data & Structures 4: Records of the 4th International Meeting (WDAS 2002), volume 14, pages 171–188. Carleton Scientific, March 2002. [5] James Aspnes and Gauri Shah. Skip graphs. In SODA ’03: Proceedings of the fourteenth annual ACM-SIAM symposium on Discrete algorithms, pages 384– 393. Society for Industrial and Applied Mathematics, 2003. [6] Baruch Awerbuch and Christian Scheideler. Peer-to-peer systems for prefix search. In PODC ’03: Proceedings of the twenty-second annual symposium on Principles of distributed computing, pages 123–132. ACM Press, 2003. [7] Hari Balakrishnan, M. Frans Kaashoek, David Karger, Robert Morris, and Ion Stoica. Looking up data in P2P systems. Commun. ACM, 46(2):43–48, 2003. [8] Matthias Bender, Sebastian Michel, Gerhard Weikum, and Christian Zimmer. The MINERVA project: Database selection in the context of P2P search. In Datenbanksysteme in Business, Technologie und Web (BTW2005; 11. Fachtagung des GI-Fachbereichs Datenbanken und Informationssysteme (DBIS)), volume P65 of Lecture Notes in Informatics, pages 125–144, Karlsruhe, Germany, March 2005. Gesellschaft f¨ ur Informatik.

xvii

Literaturverzeichnis [9] Matthias Bender, Sebastian Michel, Christian Zimmer, and Gerhard Weikum. Bookmark-driven Query Routing in Peer-to-Peer Web Search. In Jamie Callan, Norbert Fuhr, and Wolfgang Nejdl, editors, Proceedings of the SIGIR Workshop on Peer-to-Peer Information Retrieval : 27th Annual International ACM SIGIR Conference ; SIGIR 2004 P2PIR Workshop, pages SessionII,1–12, Sheffield, England, 2004. Universit¨at Duisburg-Essen. [10] Ian Clarke, Oskar Sandberg, Brandon Wiley, and Theodore W. Hong. Freenet: a distributed anonymous information storage and retrieval system. In International workshop on Designing privacy enhancing technologies, pages 46–66. Springer-Verlag New York et al., 2001. [11] Frank Dabek, Emma Brunskill, M. Frans Kaashoek, David Karger, Robert Morris, Ion Stoica, and Hari Balakrishnan. Building peer-to-peer systems with Chord, a distributed lookup service. In HOTOS ’01: Proceedings of the Eighth Workshop on Hot Topics in Operating Systems, pages 81–86. IEEE Computer Society, 2001. [12] Frank Dabek, M. Frans Kaashoek, David Karger, Robert Morris, and Ion Stoica. Wide-area cooperative storage with cfs. In SOSP ’01: Proceedings of the eighteenth ACM symposium on Operating systems principles, pages 202–215. ACM Press, 2001. [13] N. de Bruijn. A combinatorial problem. In Proceedings Nederlandse Akademie van Wetenschappen, volume 49, pages 758–764, 1946. [14] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design patterns: elements of reusable object-oriented software. Addison-Wesley, 1999. [15] The gnutella protocol specification v0.4, June 2001. http://www9.limewire.com/developer/gnutella protocol 0.4.pdf. letzter Abruf: 21.03.2005. [16] Nicolas Harvey, Michael Jones, Stefan Saroiu, Marvin Theimer, and Alec Wolman. Skipnet: A scalable overlay network with practical locality properties. In Proceedings of USITS, March 2003. [17] Ivan Herman and M. Scott Marshall. GraphXML - An XML-Based Graph Description Format. In GD ’00: Proceedings of the 8th International Symposium on Graph Drawing, pages 52–62. Springer-Verlag Berlin et al., 2001.

xviii

Literaturverzeichnis [18] Kirsten Hildrum, John D. Kubiatowicz, Satish Rao, and Ben Y. Zhao. Distributed object location in a dynamic network. In SPAA ’02: Proceedings of the fourteenth annual ACM symposium on Parallel algorithms and architectures, pages 41–52. ACM Press, 2002. [19] M. Frans Kaashoek and David Karger. Koorde: A simple degree-optimal distributed hash table. Lecture Notes in Computer Science, 2735:98–107, 2003. [20] Thomas Karagiannis, Andre Broido, Michalis Faloutsos, and Kc Claffy. Transport layer identification of P2P traffic. In IMC ’04: Proceedings of the 4th ACM SIGCOMM conference on Internet measurement, pages 121–134. ACM Press, 2004. [21] David Karger, Eric Lehman, Tom Leighton, Rina Panigrahy, Matthew Levine, and Daniel Lewin. Consistent hashing and random trees: distributed caching protocols for relieving hot spots on the world wide web. In STOC ’97: Proceedings of the twenty-ninth annual ACM symposium on Theory of computing, pages 654–663. ACM Press, 1997. [22] Jon Kleinberg. Small-world phenomena and the dynamics of information, 2001. [23] John Kubiatowicz, David Bindel, Yan Chen, Steven Czerwinski, Patrick Eaton, Dennis Geels, Ramakrishna Gummadi, Sean Rhea, Hakim Weatherspoon, Chris Wells, and Ben Zhao. Oceanstore: an architecture for global-scale persistent storage. In ASPLOS-IX: Proceedings of the ninth international conference on Architectural support for programming languages and operating systems, pages 190–201. ACM Press, 2000. [24] David Liben-Nowell, Hari Balakrishnan, and David Karger. Analysis of the evolution of peer-to-peer systems. In Proceedings of the twenty-first annual symposium on Principles of distributed computing, pages 233–242. ACM Press, 2002. [25] Bruce M. Maggs and Ramesh K. Sitaraman. Simple algorithms for routing on butterfly networks with bounded queues. In STOC ’92: Proceedings of the twenty-fourth annual ACM symposium on Theory of computing, pages 150–161. ACM Press, 1992. [26] Dahlia Malkhi, Moni Naor, and David Ratajczak. Viceroy: a scalable and dynamic emulation of the butterfly. In PODC ’02: Proceedings of the twenty-first annual symposium on Principles of distributed computing, pages 183–192. ACM Press, 2002.

xix

Literaturverzeichnis [27] Petar Maymounkov and David Mazieres. Kademlia: A peer-to-peer information system based on the xor metric. In IPTPS ’01: Revised Papers from the First International Workshop on Peer-to-Peer Systems, pages 53–65. Springer-Verlag Berlin et al., 2002. [28] Valentin Mesaros, Bruno Carton, and Peter Van Roy. S-Chord: Using symmetry to improve lookup efficiency in chord. Report UCL/INFO-2002-08, December 2002. [29] Stanley Milgram. The small world problem. Psychology Today, (1):60–67, 1967. [30] Paul V. Mockapetris. RFC 1034: Domain Names - Concepts and Facilities. Network Working Group, November 1987. [31] Paul V. Mockapetris and Kevin J. Dunlap. Development of the domain name system. SIGCOMM Comput. Commun. Rev., 25(1):112–122, 1995. [32] Sharman Networks. KaZaA Website. http://www.kazaa.com. letzter Abruf: 21.03.2005. [33] Jon Postel. User datagram protocol. 1980. RFC768. [34] The Chord Project. http://pdos.lcs.mit.edu/chord. letzter Abruf: 21.03.2005. [35] The Freenet Network Project. http://freenet.sourceforge.net. letzter Abruf: 21.03.2005. [36] Sylvia Ratnasamy, Paul Francis, Mark Handley, Richard Karp, and Scott Schenker. A scalable content-addressable network. In Proceedings of the 2001 conference on Applications, technologies, architectures, and protocols for computer communications, pages 161–172. ACM Press, 2001. [37] RFC793. Transmission Control Protocol. September 1981. DARPA Internet Program Protocol Specification. [38] Antony Rowstron and Peter Druschel. Storage management and caching in past, a large-scale, persistent peer-to-peer storage utility. In SOSP ’01: Proceedings of the eighteenth ACM symposium on Operating systems principles, pages 188–201. ACM Press, 2001. [39] Antony I. T. Rowstron and Peter Druschel. Pastry: Scalable, decentralized object location, and routing for large-scale peer-to-peer systems. Lecture Notes in Computer Science, 2218:329–350, 2001.

xx

Literaturverzeichnis [40] Stefan Saroiu, P. Krishna Gummadi, and Steven Gribble. A measurement study of peer-to-peer file sharing systems. 2002. [41] Emil Sit and Robert Morris. Security considerations for peer-to-peer distributed hash tables. In P. Druschel, F. Kaashoek, and A. Rowstron, editors, Peer-toPeer Systems: First InternationalWorkshop, IPTPS 2002 Cambridge, MA, USA, March 7-8, 2002. Revised Papers, Lecture Notes in Computer Science. SpringerVerlag Berlin et al., 2002. [42] UML 2.0 Superstructure specification. http://www.omg.org/cgi-bin/doc?ptc/2004-10-02. letzter Abruf: 28.03.2005. [43] Ion Stoica, Robert Morris, David Liben-Nowell, David R. Karger, M. Frans Kaashoek, Frank Dabek, and Hari Balakrishnan. Chord: a scalable peer-to-peer lookup protocol for internet applications. IEEE/ACM Trans. Netw., 11(1):17–32, 2003. [44] The World Wide Web Consortium (W3C). Extensible Markup Language (XML). http://www.w3c.org/XML. letzter Abruf: 21.03.2005. [45] Gnutella Website. http://www.gnutella.com. letzter Abruf: 21.03.2005. [46] Napster Website. http://www.napster.com. letzter Abruf: 21.03.2005. [47] Beverly Yang and Hector Garcia-Molina. Designing a super-peer network. In Proceedings of the 19th International Conference on Data Engineering (ICDE’03), pages 49–60, March 2003. [48] Ming Zhang and Kian-Lee Tan. Supporting rich queries in dht-based peer-topeer systems. In WETICE ’03: Proceedings of the Twelfth International Workshop on Enabling Technologies, page 95. IEEE Computer Society, 2003. [49] Shelley Q. Zhuang, Ben Y. Zhao, Anthony D. Joseph, Randy H. Katz, and John D. Kubiatowicz. Bayeux: an architecture for scalable and fault-tolerant wide-area data dissemination. In NOSSDAV ’01: Proceedings of the 11th international workshop on Network and operating systems support for digital audio and video, pages 11–20. ACM Press, 2001.

xxi