Paylanmış kilidlər
1) Nə üçün (və nə zaman) paylanmış kilidləmə lazımdır
Paylanmış bloklama - bir neçə klaster qovşağı arasındakı kritik bölmə üçün qarşılıqlı istisnaya zəmanət verən mexanizm. Tipik tapşırıqlar:- Arxa plan/şah üçün liderlik (leader election).
- Vahid icraçının ümumi resurs üzərində məhdudlaşdırılması (faylların hərəkəti, sxemin miqrasiyası, eksklüziv ödəniş addımı).
- Aqreqatın ardıcıl emalı (wallet/order) əgər fərqli şəkildə idempotentlik/nizama nail olmaq mümkün deyilsə.
- Əgər siz idempotent upsert, CAS (compare-and-set) və ya açar növbəsi (per-key ordering) edə bilərsiniz.
- Əgər resurs kommutativ əməliyyatlara icazə verirsə (CRDT, sayğaclar).
- Problem bir anbarda bir əməliyyat ilə həll edilərsə.
2) Təhlükə modeli və xassələri
Uğursuzluqlar və çətinliklər:- Şəbəkə: gecikmələr, bölünmə (partition), paket itkisi.
- Proseslər: GC fasilə, stop-the-world, kilidi aldıqdan sonra crash.
- Vaxt: saat sürüklənməsi və yerdəyişmə TTL yanaşmaları pozur.
- Təkrar sahiblik: Şəbəkədən sonra «zombi» prosesi hələ də kilidin sahibi olduğunu düşünə bilər.
- Təhlükəsizlik: ən çox bir həqiqi sahibi (təhlükəsizlik).
- Dözümlülük: Sahibi (liveness) uğursuz olduqda kilid azad edilir.
- Ədalət: oruc yoxdur.
- Saatdan müstəqillik: düzgünlük wall-clock-dan asılı deyil (və ya fencing tokens tərəfindən kompensasiya olunur).
3) Əsas modellər
3. 1 Lease (icarə qəsri)
Kilid TTL ilə verilir. Sahibi sona çatana qədər yeniləməlidir (heartbeat/keepalive).
Üstünlüklər: kreş zamanı özünü düzəltmək.
Risklər: sahibi «asılsa» və işləməyə davam etsə, lakin yeniləməni itirsə, ikili mülkiyyət yarana bilər.
3. 2 Fencing token (çit token)
Hər bir uğurlu tutulma zamanı monoton böyüyən nömrə verilir. Resurs istehlakçıları (DB, növbə, fayl saxlama) tokeni yoxlayır və köhnə nömrə əməliyyatlarını rədd edirlər.
Bu, TTL/lease və şəbəkə bölmələrində son dərəcə vacibdir - «köhnə» sahibindən qoruyur.
3. 3 Quorum kilidləri (CP sistemləri)
Paylanmış konsensusdan istifadə edin (Raft/Paxos; etcd/ZooKeeper/Consul), qeyd konsensus log ilə bağlıdır → heç bir bölünmüş fasilə əksər düyünlər.
Plus: güclü təhlükəsizlik zəmanəti.
Mənfi: Kvoruma həssaslıq (onun itkisi ilə həyat qabiliyyəti zəifləyir).
3. 4 AP kilidləri (in-memory/cache + replikasiya)
Məsələn, Redis-klaster. Yüksək mövcudluq və sürət, lakin şəbəkə bölünmələrində ciddi təhlükəsizlik zəmanəti yoxdur. Sink tərəfində fencing tələb edir.
4) Platformalar və nümunələr
4. 1 etcd/ZooKeeper/Consul (strong locks üçün tövsiyə olunur)
Efemer düyünlər (ZK) və ya sessiyalar/leases (etcd): açar session sağ olarkən mövcuddur.
Sessiya keepalive; kvorum itkisi → seans başa çatır → kilid azad edilir.
Sıra qovşaqları (ZK 'EPHEMERAL _ SEQUENTIAL') gözləmə növbəsi → ədalət.
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 (diqqətlə)
Klassik - 'SET key value NX PX ttl'.
Problemlər:- Replikasiya/faylover eyni vaxtda sahiblərinə icazə verə bilər.
- Bir neçə instansiyadan Redlock riski azaldır, lakin aradan qaldırmır; etibarsız şəbəkə ilə mühitdə mübahisəlidir.
Redis 'i sürətli koordinasiya təbəqəsi kimi tətbiq etmək daha təhlükəsizdir, lakin hədəf resursda həmişə fencing tokenini tamamlayın.
Nümunə (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. 3 DB kilidləri
PostgreSQL advisory locks: Postgres klasterində lok (proses/sessiya).
Bütün kritik bölmələr bir DB-də olduqda yaxşıdır.
sql
SELECT pg_try_advisory_lock(42); -- take
SELECT pg_advisory_unlock(42); -- let go
4. 4 Fayl/bulud «kilidləri»
S3/GCS + «If-Match» (ETag) şərtləri ilə obyektin meta məlumat lok → mahiyyətcə CAS.
Backup/miqrasiya üçün uygundur.
5) Təhlükəsiz kilidin dizaynı
5. 1 Sahibinin kimliyi
'owner _ id' saxlayın (düyün #процесс #pid #start_time) + unlock zamanı yoxlama üçün təsadüfi token.
Təkrar unlock başqasının kilidini çıxarmamalıdır.
5. 2 TTL və yeniləmə
TTL <T_fail_detect (uğursuzluq aşkar vaxt) və ≥ p99 iş kritik bölmə × ehtiyat.
Yeniləmə - dövri olaraq (məsələn, hər 'TTL/3'), deadline ilə.
5. 3 Fencing token
Xarici resursu dəyişdirən bölmə 'fencing _ token' ötürməlidir.
Sink (BD/Cache/Storage) 'last _ token' saxlayır və aşağıdakıları rədd edir:sql
UPDATE wallet
SET balance = balance +:delta, last_token =:token
WHERE id =:id AND:token > last_token;
5. 4 Gözləmə və ədalət növbəsi
ZK-də - 'EPHEMERAL _ SEQUENTIAL' və müşahidəçilər: müştəri ən yaxın sələfinin sərbəst buraxılmasını gözləyir.
etcd - təftiş/versiyası olan açarlar; 'mod _ revision' ardıcıllığı.
5. 5 Split-brain davranışı
CP-yanaşma: Kvorum olmadan kilidi götürə bilməzsiniz - safety sındırmaqdan daha yaxşı dayanmaq.
AP-yanaşma: bölünmüş adalarda irəliləyişə icazə → fencing lazımdır.
6) Liderlik (leader election)
etcd/ZK - «lider» eksklüziv epemer açardır; qalanları dəyişikliklər üçün imzalanmışdır.
Lider heartbeats yazır; itki - yenidən seçilmək.
Liderin bütün əməliyyatları fencing token (epoxa/reviziya nömrəsi) ilə müşayiət olunur.
7) Səhvlər və onların emalı
Müştəri kilidi götürdü, lakin işdən əvvəl krash → normalar, heç kim zərər görməyəcək; TTL/sessiya azad.
Qala işin ortasında başa çatdı:- Watchdog tələb olunur: yeniləmə uğursuzdursa - kritik bölməni kəsin və geri/kompensasiya edin.
- Heç bir «sonra bitirmək»: kilid olmadan kritik bölmə davam edə bilməz.
Uzun fasilə (GC/stop-the-world) → yeniləmə baş vermədi, digəri kilidi aldı. İş prosesi sahiblik itkisini (keepalive kanalı) aşkar etməli və kəsməlidir.
8) Dedlock, prioritetlər və inversiya
Paylanmış dünyada Dedlock nadirdir (adətən bir kilid), lakin bir neçə kilid varsa - götürmək üçün vahid qaydaya riayət edin (lock ordering).
Prioritet inversiyası: aşağı prioritet sahibi yüksək prioritet gözləyərkən resursu saxlayır. Həllər: TTL-limitləri, preemption (əgər biznes icazə verirsə), resursun paylaşılması.
Oruc: Ədalət üçün gözləmə xətlərindən (ZK-sıra qovşaqları) istifadə edin.
9) Müşahidə
Metriklər:- `lock_acquire_total{status=ok|timeout|error}`
- `lock_hold_seconds{p50,p95,p99}`
- 'fencing _ token _ value' (monotonluq)
- `lease_renew_fail_total`
- 'split _ brain _ prevented _ total' (kvorumun olmaması səbəbindən neçə cəhd rədd edildi)
- `preemptions_total`, `wait_queue_len`
- `lock_name`, `owner_id`, `token`, `ttl`, `attempt`, `wait_time_ms`, `path` (для ZK), `mod_revision` (etcd).
- Span «acquire → critical section → release» nəticə ilə.
- 'lease _ renew _ fail _ total'.
- `lock_hold_seconds{p99}` > SLO.
- «Yetim» kilidləri (heartbeat olmadan).
- Şişmiş gözləmə növbələri.
10) Praktik nümunələr
10. 1 Təhlükəsiz Redis kilidi ilə fencing (psevdo)
1. Token sayğacını etibarlı storda saxlayın (məsələn, Postgres/etcd).
2. Uğurlu 'SET NX PX' tokenini oxuyur/yığır və bütün resurs dəyişikliklərini DB/servisdə token yoxlaması ilə edirik.
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 ZK-də liderlik (Java, Curator)
java
LeaderSelector selector = new LeaderSelector(client, "/leaders/cron", listener);
selector. autoRequeue();
selector. start(); // listener. enterLeadership() с try-finally и heartbeat
10. 4 Postgres advisory lock (SQL + app)
sql
SELECT pg_try_advisory_lock(128765); -- attempt without blocking
-- if false --> return via backoff + jitter
11) Test Playbook (Game Days)
Kvorum itkisi: 1-2 etcd düyününü söndürmək → kilidi götürmək cəhdi keçməməlidir.
GC-fasilə/stop-the-world: süni sahibinin axını saxlamaq → watchdog iş kəsir ki, yoxlamaq.
Split-brain: sahibi və qala tərəfi arasında şəbəkə bölünməsinin emulyasiyası → yeni sahibi daha yüksək fencing token alır, köhnə - sink tərəfindən rədd edilir.
Clock skew/drift: saat sahibindən (Redis/lease üçün) → düzgün tokenlər/yoxlamalar ilə təmin olunduğundan əmin olun.
Crash before release: Düşmə prosesi → TTL/seans ilə kilid azad edilir.
12) Anti-nümunələr
Xarici mənbəyə daxil olduqda fencing olmadan təmiz TTL kilidi.
Düzgünlük üçün yerli vaxta güvənin (HLC/fencing olmadan).
Kilidlərin bir Redis master vasitəsilə feylover ilə və replikaların təsdiqi olmadan bir mühitdə paylanması.
Sonsuz kritik bölmə (TTL «əsrlər üçün»).
«Başqasının» kilidini 'owner _ id '/token ilə yoxlamadan çıxarmaq.
backoff + jitter → «fırtına» cəhdlərinin olmaması.
«Hər şeyə» vahid qlobal qala - münaqişə çantası; açar daha yaxşı.
13) Giriş çek siyahısı
- Müəyyən resurs növü və CAS/növbə/idempotentlik edə bilərsiniz.
- mexanizmi seçilir: CP üçün etcd/ZK/Consul; Redis/cache - yalnız fencing ilə.
- Həyata keçirildi: 'owner _ id', TTL + yeniləmə, watchdog, düzgün unlock.
- Xarici resurs fencing token (monotonluq) yoxlayır.
- Liderlik və failover strategiyası var.
- Metriklər, alertlər, tokenlərin loqosu və reviziyalar konfiqurasiya edilmişdir.
- Backoff + jitter və acquire-də vaxtlar var.
- Keçirilən game days: kvorum, split-brain, GC-fasilələr, clock skew.
- Bir neçə kilidin alınması prosedurunun sənədləşdirilməsi (tələb olunarsa).
- Deqradasiya planı (brownout): kilid əlçatmazsa nə etmək lazımdır.
14) FAQ
Q: Redis kilidi 'SET NX PX' kifayətdirmi?
A: Yalnız resurs fencing token yoxlayır. Əks halda, şəbəkə bölünməsində iki sahibi mümkündür.
Q: «Default» seçmək üçün nə?
A: Ciddi zəmanət üçün - etcd/ZooKeeper/Consul (CP). Bir DB daxilində asan vəzifələr üçün - advisory locks Postgres. Redis - yalnız fencing ilə.
Q: Hansı TTL qoymaq?
A: 'TTL ≥ p99 kritik bölmə müddəti × 2' və «zombi» tez təmizləmək üçün kifayət qədər qısa. Yeniləmə - hər 'TTL/3'.
Q: orucdan necə qaçmaq olar?
A: Sıra gözləmə növbəsi (ZK sequential) və ya fairness-alqoritm; cəhd limiti və ədalətli planlaşdırma.
Q: Vaxt sinxronizasiyası lazımdır?
A: Düzgünlük üçün - yox (fencing istifadə edin). Əməliyyat proqnozlaşdırılması üçün - bəli (NTP/PTP), lakin kilidin məntiqində wall-clock-a güvənməyin.
15) Nəticələr
Etibarlı paylanmış kilidlər lease + keepalive ilə kvorum storları (etcd/ZK/Consul) üzərində qurulur və dəyişdirilə bilən resurs səviyyəsində fencing tokenini tamamlamağa əmin olun. Çit olmadan hər hansı bir TTL/Redis yanaşmaları split break riskidir. Əvvəlcə kauzallıq və idempotentlik haqqında düşünün, onsuz mümkün olmayan yerlərdə kilidləri istifadə edin, ölçün, nasaz rejimləri sınayın - və «kritik bölmələriniz» hadisələrin sayına görə deyil, yalnız mənasına görə kritik olaraq qalacaq.