Jeden z mechanismů koordinace v distrbuovaných systémech
Proces musí explicitně požádat ostatní procesy o souhlas před vykonáním kritické akce. Pokračuje až po obdržení potvrzení od všech relevantních procesů.
Klíčová myšlenka:
Žádné centrální řízení, žádný token. Každý se ptá všech ostatních: “Můžu?”
Jak to funguje
Základní průběh
REQUEST(timestamp) všem ostatním procesůmRELEASE, aby uvolnil jejich hlasy
if dostanu REQUEST(Tj) od Pj:
if nechci_do_CS:
pošli GRANT(Pj)
elif chci_do_CS and (Ti < Tj or (Ti == Tj and i < j)):
odlož_odpověď(Pj) # Já mám přednost
else:
pošli GRANT(Pj) # Pj má přednost
Důležité: Porovnává se Lamportův timestamp (logický čas) + process ID jako tiebreaker.
Optimalizace oproti naivnímu přístupu:
Proces Pi chce do CS:
Ti = Lamport_timestamp++
pošli REQUEST(Ti) všem
čekej na (N-1) GRANT
vstup_do_CS()
opusť_CS()
pošli odložené GRANTy
1. Plně distribuovaný
2. Férové uspořádání
3. Žádné ztracené tokeny
4. Dobrá pro malé systémy
1. Vysoký počet zpráv
2. Všichni musí odpovědět
3. Nízká odolnost vůči výpadkům
4. Režie při nízké konkurenci
Ricart-Agrawala Algorithm:
class Process:
def request_CS(self):
self.timestamp = lamport_clock.tick()
self.state = REQUESTING
# Rozešli REQUEST všem
for p in other_processes:
send(p, REQUEST(self.id, self.timestamp))
# Čekej na N-1 odpovědí
wait_for_grants(N - 1)
self.state = IN_CS
enter_critical_section()
def on_receive_request(self, sender, timestamp):
lamport_clock.update(timestamp)
if self.state == IN_CS or \
(self.state == REQUESTING and self.timestamp < timestamp):
# Odlož odpověď
deferred_queue.append(sender)
else:
# Pošli GRANT okamžitě
send(sender, GRANT(self.id))
def release_CS(self):
self.state = RELEASED
# Pošli odložené GRANTy
for p in deferred_queue:
send(p, GRANT(self.id))
deferred_queue.clear()
Two-Phase Commit (2PC):
ISIS Algorithm:
Problém: Pokud proces Pj spadne, všichni čekají navždy na jeho GRANT.
Řešení 1: Timeouts + Failure Detection
if not received_grant(Pj) and timeout_elapsed():
if failure_detector.is_failed(Pj):
# Považuj Pj za mrtvý, ignoruj jeho hlas
continue_without(Pj)
else:
# Pošli znovu
resend_request(Pj)
Řešení 2: Group Membership
Příklad:
Řešení: logický čas + deterministické uspořádání
if T1 < T2: P1 má přednost, P2 pošle GRANT
elif T1 > T2: P2 má přednost, P1 pošle GRANT
elif T1 == T2 and i < j: Pi má přednost (deterministické)
→ Vždy jeden dostane přednost → deadlock nemůže nastat
Problém: Čekání na všech N procesů = latence nejpomalejšího
Řešení: Použij quorum-based místo permission-based
| Vlastnost | Permission | token-based koordinace | quorum-based koordinace |
|---|---|---|---|
| Počet zpráv | O(N) ❌ | O(1) ✅ | O(√N) 🟡 |
| Odolnost vůči výpadkům | 🟡 Nízká-střední | ❌ Nízká | ✅ Vysoká |
| Latence | ❌ N × RTT | 🟡 Závisí | 🟡 √N × RTT |
| Férové uspořádání | ✅ Lamport TS | 🟡 Závisí | ✅ Lamport TS |
| Složitost | 🟡 Střední | ✅ Nízká | ❌ Vysoká |
| Centralizace | ✅ Žádná | ❌ Token je SPOF | ✅ Žádná |
Místo:
REQUEST → GRANT → RELEASE
Použij:
REQUEST → (implicitní souhlas pokud nechci CS) → RELEASE
→ Ušetříš N zpráv
Pokud máš reliable multicast:
# Místo N unicastů
for p in processes:
send(p, REQUEST)
# Použij broadcast
broadcast(REQUEST) # 1 zpráva místo N
Dobré pro:
❌ Nepoužívej pro:
1. Distributed Databases:
3. Distributed File Systems:
Permission-based algoritmy kriticky závisí na Lamportových timestampech:
Bez logického času by permission-based nefungoval!