5.3 Chord

Werbung
5.3 Chord
Arbeit: Stoica u. a. (2001).
Konstruktion:
Zwei unabhängige Hashfunktionen:
• Knoten: hV : {1, . . . , n} → {0, . . . , 2m − 1};
• Schlüssel: hK : {1, . . . , k } → {0, . . . , 2m − 1}.
Hashwerte im Folgenden IDs.
IDs auf Kreis angeordnet, rechne modulo 2m .
506
Beispiel: n = 3, k = 4, m = 3.
Schlüssel: 5, 6
Knoten
0
7
Schlüssel
1
6
2
Schlüssel: 1
3
5
4
Schlüssel: 3
Speichere Schlüssel in im Uhrzeigersinn nächsten Knoten.
507
Im Folgenden der Einfachheit halber Analysen für
vollständig zufällige Hashfunktionen.
Dann:
X1 := hV (1), . . . , Xn := hV (n) und
Y1 := hK (1), . . . , Yk := hK (k ) sind
unabhängige, in {0, . . . , 2m − 1} gleichverteilte ZVs.
Tatsächlich:
• Für Knoten- und Schlüssel-Hashfunktionen jeweils
beschränkte Unabhängigkeit reicht.
• In der Praxis feste Hashfunktion, z. B. SHA-1
(und Daumen drücken).
Annahme: X1 , . . . , Xn paarweise verschieden
(m. h. W. erfüllt, falls m hinreichend groß).
508
Abstand:
Miss Entfernung von Start zu Ziel auf Kreis im Uhrzeigersinn.
Beispiel: Für {0, . . . , 7}:
Von 1 nach 7: Abstand 6.
Von 7 nach 1: Abstand 2.
(Keine Metrik, da nicht symmetrisch.)
Definition 5.1:
Für Knoten u, v sei von Knoten-ID Xu aus im Uhrzeigersinn
auf dem Kreis Xv erste andere Knoten-ID. Dann
v Nachfolger von u und
u Vorgänger von v .
509
Knotenintervalle:
Für Knoten v = 1, . . . , n:
I(v ) := (Xu , Xv ] = {Xu + 1, Xu + 2, . . . , Xv },
u Vorgänger von v . (Rechne dabei modulo 2m .)
Sonderfall: Falls n = 1, dann I(v ) = {0, . . . , 2m − 1}.
Knoten v genau für die Speicherung der in I(v )
ggf. vorkommenden Schlüssel zuständig.
510
Lastverteilung (Balance):
Alle Knoten bekommen ungefähr gleich viele“ Schlüssel ab.
”
Ideal wären k /n pro Knoten, zeige O(log n · k /n).
Lemma 5.2:
Sei c > 0. Mit Wahrscheinlichkeit mindestens 1 − n−c gilt:
Für alle Knoten v = 1, . . . , n ist
4
2m
′
, c′ =
(c + 1).
|I(v )| ≤ c log n
n
log e
511
Beweis: Sei Xv = x fest und ℓ = c ′ log n
2m
.
n
Falls |I(v )| > ℓ, dann enthält insbesondere das Intervall
I := (x − ℓ, x] = {x − ℓ + 1, x − ℓ + 2, . . . , x}
keine anderen Knoten-IDs außer x.
Z := Anzahl Knoten w 6 = v mit Xw ∈ I.
Wegen Gleichverteilung der IDs über {0, . . . , 2m − 1}:
n≥2 n/2
n−1
2m
1
EZ = m · |I| ≥ m · c ′ log n
= c ′ log n.
2
2
n
2
Chernoff:
Pr{Z = 0} ≤ Pr{Z − EZ ≤ −EZ } ≤ e−EZ /2
≤e
− 21 · log4 e (c+1) log n /2
= n−(c+1) .
Die Behauptung folgt nun mit der Vereinigungsschranke. 512
Folgerung 5.3:
Sei c > 0. Mit Wahrscheinlichkeit mindestens 1 − n−c über
die Wahl von Knoten- und Schlüssel-IDs gilt: Jeder Knoten
speichert höchstens O(log n · k /n) Schlüssel.
Beweis wieder mit Chernoff-Argument,
nur jetzt über Schlüssel-IDs (selbst überlegen).
Schärfere Schranke O((1 + γ ) · k /n), γ > 0,
mit 2(log n) IDs für jeden Knoten, Schlüssel
einsammeln für alle IDs. (Feinere Streuung der IDs.)
513
Operationen:
Datenstruktur:
Für jeden aktiven Knoten v :
v .succ = Nachfolger von v ,
v .pred = Vorgänger von v .
L OOKUP(v, x), v irgendein aktiver Knoten, x Schlüssel:
Rufe F IND S UCCESSOR(v , Yx ) auf, Yx Schlüssel-ID von x.
F IND S UCCESSOR(v, y), y ∈ 0, . . . , 2m − 1 :
if y ∈ (Xv .pred , Xv ] then return v ;
while y ∈
/ (Xv , Xv .succ ] do
v := v .succ; / / Xv .succ näher an Yx als Xv
od;
# Botschaften: O(n).
514
J OIN(x), x aktiver Knoten:
• Bestimme ID Xv für neuen Knoten v .
• Bestimme Vorgänger und Nachfolger von v :
v .succ := w := F IND S UCCESSOR (x, Xv );
v .pred := u := w .pred.
• Korrigiere Vorgänger-/Nachfolger-Info für andere Knoten:
u.succ := v ; w .pred := v .
• Verlagere alle Schlüssel in (Xu , Xv ], die w hat, nach v .
u
w
Xu
Xw
515
J OIN(x), x aktiver Knoten:
• Bestimme ID Xv für neuen Knoten v .
• Bestimme Vorgänger und Nachfolger von v :
v .succ := w := F IND S UCCESSOR (x, Xv );
v .pred := u := w .pred.
# Botschaften: O(n).
• Korrigiere Vorgänger-/Nachfolger-Info für andere Knoten:
u.succ := v ; w .pred := v .
• Verlagere alle Schlüssel in (Xu , Xv ], die w hat, nach v .
Verlagerung von O(log n · k /n) Schlüsseln.
u
v
w
Xu
Xv
Xw
515
L EAVE(v), v zu löschender Knoten:
• Verlagere Schlüssel von v zum Nachfolger v .succ.
Wieder Verlagerung von O(log n · k /n) Schlüsseln.
• Aktualisiere Vorgänger- bzw. Nachfolger-Infos
anderer Knoten:
(v .pred).succ := v .succ;
(v .succ).pred := v .pred.
Fazit: Balance okay, aber L OOKUP nicht schnell genug.
Abhilfe:
Knoten brauchen mehr lokale Routing-Info. →
Zwischenknoten in exponentiell wachsenden Abständen.
516
Finger-Informationen:
Für jeden Knoten v und i = 0, . . . , m − 1:
v .finger[i]: Knoten, der zur im Uhrzeigersinn von Xv + 2i
aus nächsten ID gehört.
u
0
7
1
6
2
5
3
4
w
v
Knoten u:
i: Xu + 2i : finger[i]:
0
1
v
1
2
v
2
4
u
Knoten v :
i: Xv + 2i : finger[i]:
0
3
w
1
4
u
2
6
u
Knoten w:
i: Xw +2i : finger[i]:
0
4
u
1
5
u
2
7
u
517
L OOKUP mit Finger-Infos:
Neue Datenstruktur für Knoten v :
Finger-Tabelle, v .succ = v .finger[0], v .pred.
F IND S UCCESSOR(s, y):
Sei s Startknoten und t Vorgängerknoten von y .
Finde Finger von s, der Ziel t am nächsten
(Vereinfachung: Identifiziere IDs ↔ Knoten):
s.finger[i]
s
···
t
s.finger[m−2]
s.finger[m−1]
y
Rekursiv weiter mit s := s.finger[i].
Knoten t wird irgendwann gefunden, da auch direkte
Nachfolger in Finger-Tabelle.
518
Lemma 5.4:
Sei c > 0. Für beliebige s und y gilt mit Wahrscheinlichkeit
mindestens 1 − n−c über die Wahl der Knoten-IDs:
Die Anzahl von Knoten, die F IND S UCCESSOR(s, y )
kontaktieren muss, ist O(log n) (bez. n → ∞).
Beweis: Notation wie auf der letzten Folie.
Sei s 6 = t (sonst fertig).
Ersetzen von s durch f := s.finger[i], zum Ziel t nächster
Finger von s, halbiert mindestens die Entfernung:
f = s.finger[i]
s
s + 2i
t
s + 2i+1
d(s, t) = d(s, f ) + d(f , t), d(s, f ) ≥ 2i , d(f , t) ≤ 2i ⇒
d(s, t)/d(f , t) = d(s, f )/d(f , t) + 1 ≥ 2.
519
Abstands-Halbierung ⇒
Nach log n Schritten ist Abstand höchstens 2m /n.
Z := Anzahl Knoten-IDs in diesem Intervall, dann ist
n 2m
EZ = m ·
= 1.
2
n
Chernoff ⇒ Für geeignete Konstante c ′ = c ′ (c) > 0 gilt:
Pr{Z ≥ c ′ log n} ≤ Pr{Z − EZ ≥ c ′ log n − 1} ≤ n−c .
Also auf dem letzten Wegabschnitt“ noch O(log n) Knoten,
”
diese schlimmstenfalls trivial in Einzelschritten überbrücken.
Damit auch insgesamt O(log n) Schritte und
ebensoviele Anfragen an Knoten.
520
Folgerung 5.5:
Sei c > 0. Für jede L OOKUP-Operation ist mit Wskt.
mindestens 1 − n−c die benötigte Anzahl Botschaften
O(log n).
521
J OIN mit Finger-Infos:
J OIN(x), x bereits aktiver Knoten:
Sei v neuer Knoten mit ID Xv .
• Initialisiere Finger-Tabelle von v .
• Aktualisiere Finger-Tabelle von allen Knoten,
die v als Finger haben könnten.
• Verlagere Schlüssel aus (Xv .pred , Xv ] nach v (wie gehabt).
522
I NIT F INGER TABLE(x, v), x aktiver Knoten, v neu:
for i = 0, . . . , m − 1:
v .finger[i] := F IND S UCCESSOR x, Xv + 2i .
od.
Zusätzlicher Trick:
Berechne und speichere im ersten Schritt
nur verschiedene Finger:
Falls Xv + 2i+1 ≤ v .finger[i], dann
v .finger[i + 1] = v .finger[i].
523
U PDATE F INGER TABLES(v ), v neuer Knoten:
for i = 0, . . . , m − 1:
p := F IND S UCCESSOR v , Xv − 2i .pred;
while Xv ∈ (Xp , Xp.finger[i] ) do
p.finger[i] := v ;
p := p.pred;
od
od.
Korrektheit:
• Alle Knoten u, die v als i-ten Finger haben können,
haben ID vor/inklusive Xv − 2i .
• Knoten p ist letzter mit ID vor/inklusive Xv − 2i .
• Alle weitere Knoten, die selben i-ten Finger wie p haben,
werden in While-Schleife angepasst.
524
Im Folgenden: Nur O log2 n andere Finger-Tabellen
müssen angepasst werden. → # Botschaften O log2 n
(Letzteres ohne Beweis).
Lemma 5.6:
Sei c > 0. Dann hat ein Knoten v mit Wskt. mindestens
1 − n−c höchstens (c + 1) log n verschiedene Finger.
Beweis: Zeige, dass m. h. W. die Finger
j = 0, 1, . . . , i := m − (c + 1) log n alle gleich sind.
Es gilt:
v .finger[0] = · · · = v .finger[i] ⇔
Intervall [Xv + 20 , Xv + 2i enthält keine Knoten-ID.
525
Erinnerung: i = m − (c + 1) log n.
Z := Anzahl Knoten-IDs in Intervall [Xv + 20 , Xv + 2i ,
dann:
EZ ≤
n
· 2i = n−c .
m
2
Markoff:
Pr{Z ≥ 1} ≤ Pr{Z ≥ nc · EZ } ≤ n−c .
Also hat Knoten mit Wskt. mindestens 1 − n−c höchstens
(c + 1) log n Finger.
526
Lemma 5.7:
Sei c > 0. Ein Knoten v ist mit Wskt. mindestens 1 − 2n−c
Finger für höchstens O log2 n andere Knoten.
Beweis:
Sei p der Vorgänger von v (Funktion der ZVs X1 , . . . , Xn ).
Es ist v i-ter Finger für Knoten u genau dann, wenn
Xu + 2i ∈ (Xp , Xv ].
Behauptung 1: Pr Xu + 2i ∈ (Xp , Xv ] ≤ (5 log n)/n.
Behauptung 2: Mit Wskt. mindestens 1 − n−c gibt es nur
O(log n) Knoten, die v als i-ten Finger haben.
Lemma 5.6, c ← c + 1: Mit Wskt. mindestens 1 − n−c hat
jeder Knoten höchstens O(log n) verschiedene Finger.
Damit insgesamt die Behauptung.
527
Beweis von Behauptung 1:
Zeige für festes Xu = x: Pr x ∈ (Xp , Xv ] ≤ (5 log n)/n.
Betrachte die Situation für festes Xv = y :
Es ist x ∈ (Xp , y ] genau dann, wenn es kein w ∈
/ {u, v } gibt,
sodass Xw ∈ [x, y ].
Sei |y − x| ≥ ℓ := 4 log n
2m
(rechne dabei modulo 2m ) und
n
Z := Anzahl alle Xw , w ∈
/ {u, v }, in [x, y ].
Dann ist
2m n≥4
n−2
≥ 2 log n
· 4 log n
EZ =
2m
n
und
Pr{x ∈ (Xp , y ]} = Pr{Z = 0} ≤ e−EZ /2 ≤
1
.
n
528
Es gilt:
Pr{x ∈ (Xp , y ]} =
X
y
=
X
y : y−x≥ℓ
≤
Pr{Xv = y } · Pr{x ∈ (Xp , y ]}
|
{z
}
=1/2m
X
1
·
Pr{x
∈
(X
,
y
]}
+
p
{z
}
2m |
≤1/n
1
1 4 log n
1
+ℓ· m =
+
n
2
n
n
y : y−x<ℓ
n≥2
≤
1
· Pr{x ∈ (Xp , y ]}
{z
}
2m |
≤1
5 log n
.
n
(Behauptung 1) 529
Beweis von Behauptung 2:
Zu zeigen: Mit Wskt. mindestens 1 − n−c gibt es nur
O(log n) Knoten, die v als i-ten Finger haben.
Nach Behauptung 1 gilt:
5 log n
Pr Xu + 2i ∈ (Xp , Xv ] ≤
.
n
Erwartungswert für Anzahl Knoten u, die v als
i-ten Finger haben, ist höchstens 5 log n.
Mit Chernoff-Argument O log n solche
Knoten mit Wahrscheinlichkeit mindestens 1 − n−c .
(Behauptung 2) 530
L EAVE analog zu J OIN (nur keine Initialisierung der
Finger-Tabelle).
Insgesamt:
Anzahl Schlüssel pro Knoten:
Lokaler Platz für Routing-Infos:
J OIN/L EAVE:
L OOKUP:
O(log n · k /n)
O(log n)
O log2 n Botschaften
O(log n) Botschaften
Kritik an der Analyse:
Behandelt Operationen einzeln, will aber kleine
Fehlschlagswskt. für Folgen von Operationen.
Idee für aufgebohrte Version: Benötigte Eigenschaften der
IDs vorab sicherstellen, z. B. kleine Abstände, nur damit
arbeiten. Haarigere Beweise.
531
Was noch fehlt (siehe Originalarbeit):
• Gleichzeitig mehrere J OINs/L EAVEs:
Neue Algorithmen nötigt, während Stabilisierungsphase
evtl. nur direkte Vorgänger und Nachfolger der Knoten.
• Absicherung gegen Datenverlust:
Speichere jeden Schlüssel r -fach, zusätzlich in den
(r − 1)-nächsten Knoten nach ursprünglichem.
Kann bei Ausfall zu Nachfolger weitergehen.
• Absicherung gegen Verlust der Netzstruktur:
Speichere für jeden Knoten zusätzlich die ersten s
Nachfolger.
Für beide letzte Fällen können Ausfälle von benachbarten
Knoten wegen Hashing als unabhängig angesehen werden.
532
Herunterladen