Таратылған бұғаттау
1) Таратылған блоктау не үшін (және қашан) қажет
Таратылған бұғаттау - кластердің бірнеше тораптары арасындағы сындарлы секция үшін өзара ерекшелікке кепілдік беретін механизм. Типтік тапсырмалар:- Өңдік тапсырма/шедулер үшін көшбасшылық (leader election).
- Жалғыз орындаушыны ортақ ресурстан шектеу (файлдарды жылжыту, схеманы көшіру, эксклюзивті төлем қадамы).
- Агрегатты дәйекті өңдеу (wallet/order) егер демпотенттікке/реттеуге басқаша қол жеткізу мүмкін болмаса.
- Егер демпотенттік upsert, CAS (compare-and-set) немесе кілт бойынша кезек (per-key ordering) жасауға болады.
- Егер ресурс коммутативті әрекеттерге (CRDT, есептегіштер) рұқсат берсе.
- Егер мәселе бір қоймада транзакциямен шешілсе.
2) Қатерлер моделі және қасиеттері
Істен шығулар мен қиындықтар:- Желі: кідірістер, бөлу (partition), пакеттерді жоғалту.
- Процестер: GC үзілісі, stop-the-world, құлыпты алғаннан кейін қисаю.
- Уақыт: сағат дрейфі және ауысу TTL-тәсілдерді бұзады.
- Қайта иелену: «зомби» - желіден кейін үдеріс құлыпқа ие деп ойлауы мүмкін.
- Қауіпсіздік: бір нақты иесінен (safety) артық емес.
- Өміршеңдік: құлып иесі істен шыққан кезде босатылады (liveness).
- Әділеттілік: аштық жоқ.
- Сағатқа тәуелділік: дұрыстығы wall-clock-қа байланысты емес (немесе fencing tokens өтеледі).
3) Негізгі модельдері
3. 1 Lease (жалдау құлпы)
Құлып TTL-мен беріледі. Иесі оны аяқталғанға дейін ұзартуға міндетті (heartbeat/keepalive).
Артықшылықтары: крэш кезінде өзін-өзі жабдықтау.
Тәуекелдер: егер иесі «құлдырап», жұмысын жалғастырса, бірақ ұзартуды жоғалтса, қос иелену пайда болуы мүмкін.
3. 2 Fencing token (қоршау белгісі)
Әрбір сәтті басып алу кезінде монотонды өсетін нөмір беріледі. Ресурсты тұтынушылар (ДҚ, кезек, файлдық сақтау орны) токенді тексереді және ескі нөмірмен операцияларды қабылдамайды.
Бұл TTL/lease және желілік бөлулер кезінде өте маңызды - «ескі» иесінен қорғайды.
3. 3 Quorum-құлыптары (CP-жүйелері)
Бөлінген консенсус қолданылады (Raft/Paxos; etcd/ZooKeeper/Consul), жазба консенсус логымен байланысты → көптеген тораптарда сплит-брейн жоқ.
Плюс: күшті қауіпсіздік кепілдіктері.
Минус: кворумға сезімталдық (оны жоғалтқан кезде өміршеңдік хромдайды).
3. 4 AP құлыптары (in-memory/кэш + репликалау)
Мысалы, Redis-кластер. Жоғары қолжетімділік және жылдамдық, бірақ желілік бөлулер кезінде қатаң қауіпсіздік кепілдіктерсіз. Көк жағында fencing талап етеді.
4) Платформалар мен паттерндер
4. 1 etcd/ZooKeeper/Consul (strong locks үшін ұсынылады)
Эфемерлік тораптар (ZK) немесе сессиялар/leases (etcd): сессия тірі болғанша кілт бар.
Сессиялық keepalive; кворумды жоғалту → сессия аяқталады → құлып босатылады.
Кезек күтуге арналған реттік тораптар (ZK 'EPHEMERAL _ SEQUENTIAL') → әділдік.
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 (мұқият)
Классика - 'SET key value NX PX ttl'.
Проблемалар:- Репликалау/фейловер бір мезгілде иеленушілерге рұқсат етуі мүмкін.
- Бірнеше инстанцияның Redlock тәуекелді азайтады, бірақ жоймайды; сенімді желісі жоқ орталарда даулы.
Redis-ті тез үйлестіру қабаты ретінде қолдану қауіпсіз, бірақ әрқашан мақсатты ресурста fencing token-ті толықтыру.
Мысал (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 ДБ құлыптары
PostgreSQL advisory locks: Postgres кластері шеңберіндегі лок (процесс/сессия).
Барлық сыни секциялар бір ДБ-да болғаны жақсы.
sql
SELECT pg_try_advisory_lock(42); -- take
SELECT pg_advisory_unlock(42); -- let go
4. 4 Файлдық/бұлтты құлыптар
S3/GCS + «If-Match» (ETag) шарттары бар объектілік метадеректік лок → шын мәнінде CAS.
Бэкап/көші-қон үшін жарамды.
5) Қауіпсіз құлып дизайны
5. 1 Иесінің сәйкестігі
'owner _ id' (торап #процесс #pid #start_time) + unlock кезінде салыстыру үшін кездейсоқ токенді сақтаңыз.
Қайталанған unlock басқаның құлпын шешпеуі керек.
5. 2 TTL және ұзарту
TTL <T_fail_detect (ақаулықты анықтау уақыты) және сыни секция жұмысының p99 ≥ × қор.
Ұзарту - мерзімдік (мысалы, әрбір 'TTL/3'), с deadline.
5. 3 Синкада Fencing token
Сыртқы ресурсты өзгертетін бөлім 'fencing _ token' дегенді беруі тиіс.
Синк (ДБ/кэш/сақтау орны) 'last _ token' сақтайды және төмендегілерді қабылдамайды:sql
UPDATE wallet
SET balance = balance +:delta, last_token =:token
WHERE id =:id AND:token > last_token;
5. 4 Күту кезегі және әділдік
ZK - 'EPHEMERAL _ SEQUENTIAL' және бақылаушылар: клиент ең жақын алдыңғысының босатылуын күтеді.
В etcd - ревизиясы/нұсқасы бар кілттер; 'mod _ revision' бойынша кезектілік.
5. 5 Split-brain кезінде мінез-құлық
CP-тәсіл: кворумсыз құлып алуға болмайды - safety сындырғаннан гөрі тұру жақсы.
AP-тәсіл: бөлінген аралдарда прогреске жол беріледі → fencing қажет.
6) Көшбасшылық (leader election)
etcd/ZK - «көшбасшы» - бұл эксклюзивті эпемерлік кілт; қалғандары өзгерістерге қол қойылды.
Көшбасшы heartbeats жазады; жоғалту - қайта сайлау.
Көшбасшының барлық операцияларын fencing token (дәуір/ревизия нөмірі) сүйемелдеңіз.
7) Қателер және оларды өңдеу
Клиент құлыпты алды, бірақ жұмыс алдында крэш → нормалар, ешкім зардап шекпейді; TTL/сессиясы босатылады.
Құлып жұмыс ортасынан өтіп кетті:- Міндетті watchdog: егер ұзарту сәтсіз болса - сындарлы секцияны үзіп, сырғып/орнын толтырыңыз.
- Ешқандай «кейін аяқтау»: құлыпсыз сыни секцияны жалғастыруға болмайды.
Ұзақ үзіліс (GC/stop-the-world) → ұзарту болмады, екіншісі құлыпты алды. Жұмыс процесі иелену жоғалғанын (keepalive арнасы) анықтап, тоқтатуы тиіс.
8) Дедлоктар, басымдықтар және инверсия
Таратылған әлемде дедлоктар сирек кездеседі (құлып әдетте бір), бірақ бірнеше құлыптар болса - алудың бірыңғай тәртібін ұстаныңыз (lock ordering).
Басымдықтардың инверсиясы: төмен басымдықты иеленуші ресурсты жоғары басымдылықтар күтіп тұрғанда ұстап тұрады. Шешімдер: TTL-лимиттер, preemption (егер бизнес рұқсат берсе), sharding ресурсы.
Ашаршылық: әділ болу үшін күту кезектерін (ZK-ретсіз тораптар) пайдаланыңыз.
9) Бақылау
Өлшемдері:- `lock_acquire_total{status=ok|timeout|error}`
- `lock_hold_seconds{p50,p95,p99}`
- 'fencing _ token _ value' (біркелкілік)
- `lease_renew_fail_total`
- 'split _ brain _ prevented _ total' (кворум болмағандықтан қанша әрекет жасалмады)
- `preemptions_total`, `wait_queue_len`
- `lock_name`, `owner_id`, `token`, `ttl`, `attempt`, `wait_time_ms`, `path` (для ZK), `mod_revision` (etcd).
- Нәтижесі бар «acquire → critical section → release» спандары.
- 'lease _ renew _ fail _ total' өсуі.
- `lock_hold_seconds{p99}` > SLO.
- «Орфандық» құлыптар (heartbeatсіз).
- Күту кезектері.
10) Практикалық мысалдар
10. 1 Қауіпсіз Redis-fencing құлпы (псевдо)
1. Токендер есептеуішін сенімді күйде сақтаймыз (мысалы, Postgres/etcd).
2. Сәтті «SET NX PX» кезінде токенді оқимыз/инкременттейміз және ресурстың барлық өзгерістерін ДБ/сервистегі токенді тексерумен жасаймыз.
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 көшбасшылығы (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) Тест-плейбуктер (Game Days)
Кворумды жоғалту: 1-2 etcd тораптарын өшіру → құлыпты алу әрекеті өтпеуі тиіс.
GC-үзіліс/stop-the-world: иесінің ағынын жасанды түрде кідірту → watchdog жұмысын тоқтататынын тексеру.
Split-brain: иесі мен құлыптың жағы арасындағы желілік бөлуді эмуляциялау → жаңа иесі жоғары fencing token алады, ескісі синк арқылы қабылданбайды.
Clock skew/drift: сағатты иесінен алу (Redis/lease үшін) → дұрыстығы белгілермен/тексерулермен қамтамасыз етілетініне көз жеткізу.
Crash before release: процестің құлауы → құлып TTL/сессиясы бойынша босатылады.
12) Қарсы үлгілер
Сыртқы ресурсқа қатынасқанда fencing жоқ таза TTL құлпы.
Түзету үшін жергілікті уақытқа сүйену (HLC/fencing).
Құлыптарды бір Redis шебері арқылы фейловермен ортада және репликаларды растаусыз тарату.
Шексіз сыни секция (TTL «ғасырларға»).
'owner _ id '/token салыстыруынсыз «бөтен» құлыпты алып тастау.
backoff + jitter → «дауыл» әрекеттерінің болмауы.
«Барлығына» бірыңғай жаһандық құлып - жанжалдар қаптамасы; кілт бойынша шардинг жақсы.
13) Енгізу чек-парағы
- Ресурстың түрі анықталды және CAS/кезекпен/іспеттілікпен айналысуға бола ма.
- Механизм таңдалды: CP үшін etcd/ZK/Consul; Redis/кэш - тек fencing.
- Іске асырылды: 'owner _ id', TTL + ұзарту, watchdog, дұрыс unlock.
- Сыртқы ресурс fencing token (монотонды) тексереді.
- Көшбасшылық және failover стратегиясы бар.
- Өлшемдер, алерттар, белгілер мен тексерулерді логикалау теңшелген.
- backoff + jitter және acquire таймауттары қарастырылған.
- Өткізілген game days: кворум, split-brain, GC-үзілістер, clock skew.
- Бірнеше құлыптарды алу тәртібінің құжаттамасы (егер талап етілсе).
- Деградация жоспары (brownout): құлып қол жетімсіз болғанда не істеу керек.
14) FAQ
Q: «SET NX PX» Redis-құлпы жеткілікті ме?
A: Егер ресурс fencing token тексерсе ғана. Әйтпесе желілік бөлу кезінде екі иеленуші болуы мүмкін.
Q: «әдепкі» қандай таңдау керек?
A: Қатаң кепілдіктер үшін - etcd/ZooKeeper/Consul (CP). Бір БД ішіндегі жеңіл тапсырмалар үшін - advisory locks Postgres. Redis - тек fencing.
Q: Қандай TTL қою?
A: 'TTL ≥ p99 сыни секция ұзақтығы × 2' және «зомби» тез тазалау үшін жеткілікті қысқа. Ұзарту - әрбір 'TTL/3'.
Q: аштық болдырмау үшін қалай?
А: Күту кезегі (ZK sequential) немесе fairness-алгоритм; әрекеттер лимиті және әділ жоспарлау.
Q: уақытты синхрондау қажет пе?
А: Дұрыстығы үшін - жоқ (fencing пайдаланыңыз). Пайдалану болжамдылығы үшін - иә (NTP/PTP), бірақ құлыптың логикасында wall-clock-қа сүйенбеңіз.
15) Қорытынды
Сенімді бөлінген бұғаттаулар lease + keepalive бар кворумды тұстарда (etcd/ZK/Consul) құрылады және өзгеретін ресурс деңгейінде fencing token міндетті түрде толықтырылады. Қоршаусыз кез келген TTL/Redis-тәсілдері - сплит-брейн тәуекелі. Алдымен каузальдық пен іспеттілік туралы ойланыңыз, оларсыз мүмкін емес жерлерде бұғаттауды пайдаланыңыз, өлшеңіз, істен шығу режимдерін тестілеңіз - және сіздің «сыни секцияларыңыз» инциденттердің саны бойынша емес, мағынасы бойынша ғана сыни болып қалады.