GH GambleHub

Blokady rozproszone

1) Dlaczego (i kiedy) rozproszone zamki są potrzebne

Blokowanie rozproszone jest mechanizmem gwarantującym wzajemne wykluczenie dla odcinka krytycznego między kilkoma węzłami klastrowymi. Typowe zadania:
  • Wybory przywódców do zadania tła/cień.
  • Ograniczenie pojedynczego wykonawcy nad udostępnionym zasobem (ruch plików, migracja schematów, ekskluzywny krok płatniczy).
  • Sekwencyjne przetwarzanie kruszywa (portfel/zamówienie), jeśli nie jest możliwe osiągnięcie idempotencji/zamawianie w inny sposób.
Kiedy lepiej nie używać blokady:
  • Jeśli możesz zrobić idempotent upsert, CAS (porównaj-i-zestaw) lub zamówienie per-key.
  • Jeśli zasób pozwala na operacje komutacyjne (CRDT, liczniki).
  • Jeśli problem zostanie rozwiązany przez transakcję w jednym sklepie.

2) Model zagrożenia i właściwości

Niepowodzenia i powikłania:
  • Sieć: opóźnienia, partycje, utrata pakietów.
  • Procesy: pauza GC, stop-the-world, crash after lock capture.
  • Czas: Dryfowanie zegara i przesuwanie TTL zbliża się.
  • Repossession: Proces „zombie” po sieci może myśleć, że nadal jest właścicielem zamku.
Żądane właściwości:
  • Bezpieczeństwo: nie więcej niż jeden ważny właściciel (bezpieczeństwo).
  • Możliwość przeżycia: blokada jest uwalniana, gdy właściciel zawiódł (los).
  • Sprawiedliwość: Nie ma postu.
  • Niezależność zegara: prawidłowość nie zależy od zegara ściennego (lub kompensowana przez żetony ogrodzeniowe).

3) Główne modele

3. 1 Dzierżawa (blokada wynajmu)

Zamek jest wydany z TTL. Właściciel jest zobowiązany do odnowienia go przed wygaśnięciem (bicie serca/utrzymanie przy życiu).

Plusy: Rozpadające się wchłanianie siebie.
Ryzyko: jeśli właściciel „utknął” i nadal pracuje, ale stracił przedłużenie, może powstać podwójna własność.

3. 2 Token ogrodzeniowy

Przy każdym udanym przechwyceniu wydaje się monotonnie rosnącą liczbę. Konsumenci zasobów (baza danych, kolejka, przechowywanie plików) sprawdzają token i odrzucają operacje ze starym numerem.
Jest to niezwykle ważne dla TTL/dzierżawy i przegród sieciowych - chroni przed „starym” właścicielem.

3. 3 Zamki kworum (systemy CP)

Używany jest konsensus rozproszony (Raft/Paxos; etcd/ZooKeeper/Consul), rekord jest związany z dziennikiem konsensusu → nie ma rozdzielonego mózgu z większością węzłów.

Plus: mocne gwarancje bezpieczeństwa.
Minus: wrażliwość na kworum (gdy jest utracone, przeżywalność jest kulawa).

3. 4 zamki AP (pamięć/pamięć podręczna + replikacja)

Na przykład klaster Redis. Wysoka dostępność i szybkość, ale bez silnych gwarancji bezpieczeństwa dla przegród sieciowych. Wymagają ogrodzenia po stronie siniaka.

4) Platformy i wzory

4. 1 etcd/ZooKeeper/Consul (zalecany do mocnych zamków)

Węzły efemeryczne (ZK) lub sesje/dzierżawy (etcd): klucz istnieje, gdy sesja jest żywa.
Sesja utrzymuje się przy życiu; quorum loss → sesja wygasa → blokada jest zwolniona.
Węzły sekwencji (ZK 'EFEMERAL _ SEQUENTIAL') dla kolejki oczekiwania → fair.

Szkic na etcd (Go):
go cli, _:= clientv3. New(...)
lease, _:= cli. Grant(ctx, 10)            // 10s lease sess, _:= concurrency. NewSession(cli, concurrency. WithLease(lease. ID))
m:= concurrency. NewMutex(sess, "/locks/orders/42")
if err:= m. Lock(ctx); err!= nil { / handle / }
defer m. Unlock(ctx)

4. 2 Redis (schludny)

Classic - 'SET key value NX PX ttl'.

Problemy:
  • Replikacja/feilover może umożliwić jednoczesnym właścicielom.
  • Redlock z wielu instancji zmniejsza ryzyko, ale nie eliminuje; jest kontrowersyjny w środowiskach o nierzetelnej sieci.

Bezpieczniej jest używać Redis jako szybkiej warstwy koordynacyjnej, ale zawsze uzupełniaj token ogrodzenia w zasobie docelowym.

Przykład (Lua-unlock):
lua
-- release only if value matches if redis. call("GET", KEYS[1]) == ARGV[1] then return redis. call("DEL", KEYS[1])
else return 0 end

4. Zamki 3 DB

Blokady doradcze PostgreSQL: blokada w klastrze Postgres (proces/sesja).
Dobrze, że wszystkie krytyczne sekcje są już w tej samej bazie danych.

SQL:
sql
SELECT pg_try_advisory_lock(42); -- take
SELECT pg_advisory_unlock(42); -- let go

4. 4 blokady pliku/chmury

S3/GCS + obiekt blokada metadanych z warunkami 'If-Match' (ETag) → zasadniczo CAS.
Nadaje się do kopii zapasowych/migracji.

5) Projekt blokady bezpieczeństwa

5. 1 Tożsamość właściciela

Store 'owner _ id' (# proces # pid # start _ time node) + losowy token do weryfikacji odblokowania.
Wielokrotne odblokowanie nie powinno usunąć czyjegoś zamka.

5. 2 TTL i przedłużenie

TTL <T_fail_detect (czas wykrywania usterek) i p99 ≥ operacji odcinka krytycznego × zapasowego.
Odnowienie - okresowo (na przykład każdy 'TTL/3'), z terminem.

5. 3 Ogrodzenie żeton na siniaku

Sekcja modyfikująca zasób zewnętrzny musi przejść przez „ogrodzenie _ token”.

Zlewozmywak (DB/cache/storage) przechowuje „last _ token” i odrzuca mniejsze:
sql
UPDATE wallet
SET balance = balance +:delta, last_token =:token
WHERE id =:id AND:token > last_token;

5. 4 Czekająca kolejka i sprawiedliwość

W ZK - „EFEMERAL _ SEQUENTIAL” i obserwatorzy: klient czeka na uwolnienie najbliższego poprzednika.
W etcd - klucze z wersją/wersją; zamówienie przez 'mod _ revision'.

5. 5 Zachowanie dzielonego mózgu

Podejście CP: bez kworum nie można wziąć zamka - lepiej stać niż złamać bezpieczeństwo.
Podejście AP: postęp jest dozwolony na wyspach podzielonych → ogrodzenie jest wymagane.

6) Wybory do lidera

W etcd/ZK „lider” jest wyłącznym kluczem epemerycznym; reszta jest zapisana do zmian.
Lider pisze bicie serca; strata - reelekcja.
Towarzyszyć wszystkim operacjom lidera z tokenem ogrodzenia (numer ery/wersji).

7) Błędy i ich przetwarzanie

Klient wziął zamek, ale crash do pracy → norma, nikt nie będzie cierpieć; TTL/sesja zostanie wydana.

Zamek wygasł w trakcie pracy:
  • Obowiązkowy watchdog: jeśli rozszerzenie nie powiodło się, przerwać sekcję krytyczną i cofnąć/zrekompensować.
  • Nie „zakończyć później”: bez zamka, sekcja krytyczna nie może być kontynuowana.

Długa przerwa (GC/stop-the-world) → rozszerzenie nie nastąpiło, drugi wziął zamek. Przepływ pracy musi wykryć utratę własności (utrzymujący się kanał) i przerwać.

8) Dedloki, priorytety i inwersja

Dedloki w rozproszonym świecie są rzadkie (zwykle jest jeden zamek), ale jeśli istnieje kilka zamków, trzymać się jednego zamówienia (zamek zamawiania).
Inwersja priorytetowa: właściciel o niskim priorytecie posiada zasoby, podczas gdy te o wysokim priorytecie czekają. Rozwiązania: limity TTL, preempcja (jeśli pozwala na to biznes), odłamywanie zasobów.
Post: Użyj kolejek oczekujących (węzłów ZK-sub-order) dla uczciwości.

9) Obserwowalność

Metryka:
  • 'lock _ acquire _ total {status = ok' timeout 'error}'
  • „lock _ hold _ seconds {p50, p95, p99}”
  • „ogrodzenie _ token _ value” (monotonia)
  • „lease _ renew _ fail _ total”
  • „split _ brain _ prevented _ total” (liczba odmownych prób z powodu braku kworum)
  • „preemptions _ total”, „wait _ queue _ len”
Dzienniki/śledzenie:
  • 'lock _ name', 'owner _ id',' token ',' ttl', 'attempt', 'wait _ time _ ms', 'path' (дла ZK), 'mod _ revision' (etcd).
  • „acquire → critical section → release” przęsła z wynikiem.
Wpisy:
  • Wzrost „leasing _ renew _ fail _ total”.
  • 'lock _ hold _ seconds {p99}'> SLO.
  • Zamki „sierocych” (bez bicia serca).
  • Wzdęte listy oczekujących.

10) Studia przypadku

10. 1 Bezpieczny zamek Redis z ogrodzeniem (pseudo)

1. Licznik tokenów przechowujemy w niezawodnym sklepie (na przykład Postgres/etcd).
2. Jeśli 'SET NX PX' zakończy się sukcesem, odczytujemy/zwiększamy token i wprowadzamy wszystkie zmiany do zasobu za pomocą tokenu zaznaczonego w bazie/usłudze danych.

python acquire token = db. next_token ("locks/orders/42") # monotone ok = redis. set("locks:orders:42", owner, nx=True, px=ttl_ms)
if not ok:
raise Busy()

critical op guarded by token db. exec("UPDATE orders SET... WHERE id=:id AND:token > last_token",...)
release (compare owner)

10. 2 etcd Mutex + watchdog (Go)

go ctx, cancel:= context. WithCancel(context. Background())
sess, _:= concurrency. NewSession(cli, concurrency. WithTTL(10))
m:= concurrency. NewMutex(sess, "/locks/job/cleanup")
if err:= m. Lock(ctx); err!= nil { /... / }

// Watchdog go func() {
<-sess. Done ()//loss of session/quorum cancel ()//stop working
}()

doCritical (ctx )//must respond to ctx. Done()
_ = m. Unlock(context. Background())
_ = sess. Close()

10. 3 Przywództwo w ZK (Java, Kurator)

java
LeaderSelector selector = new LeaderSelector(client, "/leaders/cron", listener);
selector. autoRequeue();
selector. start(); // listener. enterLeadership() с try-finally и heartbeat

10. 4 Postgres blokada doradcza z terminem (SQL + aplikacja)

sql
SELECT pg_try_advisory_lock(128765); -- attempt without blocking
-- if false --> return via backoff + jitter

11) Test playbooks (Dni gry)

Utrata kworum: wyłączyć 1-2 węzły etcd → próba zabrania blokady nie powinna przejść.
GC-pauza/stop-the-world: sztucznie opóźnić przepływ właściciela → sprawdź, czy obserwator przerywa pracę.
Split-brain: emulacja separacji sieci między właścicielem a bokiem zamku → nowy właściciel dostaje wyższy symbol ogrodzenia, stary jest odrzucany przez niebieski.
Zegar skew/drift: zabrać zegar od właściciela (dla Redis/dzierżawy) → upewnij się, że poprawność jest zapewniona przez żetony/kontrole.
Crash przed zwolnieniem: proces awarii → blokada jest uwalniana poprzez TTL/sesję.

12) Anty-wzory

Czyścić blokadę TTL bez ogrodzenia podczas dostępu do zewnętrznego zasobu.
Polegać na czasie lokalnym dla poprawności (bez HLC/ogrodzenia).
Dystrybucja zamków przez jednego mistrza Redis w środowisku z feilover i bez potwierdzenia replik.
Nieskończona część krytyczna (TTL „dla wieków”).
Usuwanie czyjegoś zamka bez sprawdzania 'owner _ id'/token.
Brak backoff + jitter → burza prób.
Pojedynczy globalny zamek „za wszystko” - torba konfliktów; klucz jest lepszy.

13) Lista kontrolna wdrażania

  • Typ zasobów zdefiniowany i można dozować CAS/kolejkę/idempotencję.
  • Wybrany mechanizm: etcd/ZK/Consul for CP; Redis/cache - tylko z ogrodzeniem.
  • Wdrożone: 'owner _ id', rozszerzenie TTL +, watchdog, poprawne odblokowanie.
  • Zewnętrzne zasoby kontrolują token ogrodzenia (monotonia).
  • Istnieje strategia przywództwa i porażka.
  • Skonfigurowane mierniki, wpisy, żetony do rejestrowania i wersje.
  • Zapewniono backoff + jitter i nabycie terminów.
  • Dni gry: kworum, podział mózgu, pauzy GC, skew zegara.
  • Dokumentacja procedury zabrania kilku zamków (jeżeli jest to wymagane).
  • plan brownout - co zrobić, gdy blokada jest niedostępna.

14) FAQ

P: Czy blokada 'SET NX PX' jest wystarczająca?
Odp.: Tylko jeśli zasób sprawdza token ogrodzenia. W przeciwnym razie, z podziału sieci, dwóch właścicieli są możliwe.

P: Co wybrać „domyślnie”?
Odp.: Dla ścisłych gwarancji - etcd/ZooKeeper/Consul (CP). Dla łatwych zadań wewnątrz jednej bazy danych - blokady doradcze Postgres. Redis - tylko z ogrodzeniem.

P: Który TTL umieścić?
Odp.: 'TTL ≥ p99 krytyczny czas trwania odcinka × 2' i wystarczająco krótki, aby szybko oczyścić 'zombie. "Odnowienie - każdy 'TTL/3'.

P: Jak uniknąć postu?
Odp.: Kolejka oczekująca w kolejności (sekwencyjna ZK) lub algorytm uczciwości; limit prób i sprawiedliwego planowania.

P: Czy potrzebuję synchronizacji czasu?
Odp.: Dla poprawności - nie (użyj ogrodzenia). Dla przewidywalności operacyjnej, tak (NTP/PTP), ale nie polegać na zegarze ściennym dla logiki blokady.

15) Kwoty całkowite

Niezawodne blokady rozproszone są zbudowane na poziomach kworum (etcd/ZK/Consul) z dzierżawą + utrzymywane, i są koniecznie uzupełniane przez żeton ogrodzenia na poziomie zasobów ulegających zmianie. Każde podejście TTL/Redis bez ogrodzenia stanowi ryzyko rozszczepienia mózgu. Pomyśl najpierw o przyczynowości i idempotencji, użyj zamków, gdzie jest to niemożliwe bez nich, pomiar, tryby awarii testów - a twoje „krytyczne sekcje” pozostaną krytyczne tylko w znaczeniu, a nie w liczbie incydentów.

Contact

Skontaktuj się z nami

Napisz do nas w każdej sprawie — pytania, wsparcie, konsultacje.Zawsze jesteśmy gotowi pomóc!

Rozpocznij integrację

Email jest wymagany. Telegram lub WhatsApp są opcjonalne.

Twoje imię opcjonalne
Email opcjonalne
Temat opcjonalne
Wiadomość opcjonalne
Telegram opcjonalne
@
Jeśli podasz Telegram — odpowiemy także tam, oprócz emaila.
WhatsApp opcjonalne
Format: kod kraju i numer (np. +48XXXXXXXXX).

Klikając przycisk, wyrażasz zgodę na przetwarzanie swoich danych.