Bu qatlamda nima bor
Core darslik asoslarni berdi. Bu Deep qatlam senior darajadagi chuqur mexanikani ochadi: 2PC bloklash va XA/3PC, saga izolyatsiya anomaliyalari va countermeasure’lar, orkestratorni saqlanadigan state machine sifatida qurish, saga + outbox/event sourcing bilan atomiklik, TCC (Try-Confirm-Cancel) va retriable/non-retriable recovery hamda saga observability. Oxirida — yig‘ma arxitektura va senior cheklist.
2PC bloklash, XA va 3PC
XA · blocking · 3PCCore’da 2PC’dan "qochiladi" dedik. Senior nega ekanini aniq mexanika bilan biladi — va XA/3PC nima ekanini.
2PC ning "bloklovchi" muammosi — aniq stsenariy
Faza 1 tugadi: hamma ishtirokchi "tayyor" (prepared) dedi va qulflarni ushlab turibdi. Aynan shu paytda koordinator o‘ladi. Endi ishtirokchilar noaniq holatda — "commit qilaymi, abort qilaymi?" bilmaydilar. Koordinator qaytmaguncha ular qulflarni ushlab, bloklangan turadi (soatlab). Bu — 2PC’ning tuzalmas kamchiligi.
XA va 3PC
XA — 2PC’ning sanoat standarti (X/Open): Transaction Manager + Resource Managerlar, xa_prepare/xa_commit chaqiruvlari. An’anaviy bazalar (Postgres, MySQL, ba’zi brokerlar) qo‘llab-quvvatlaydi. 3PC esa 2PC’ga "pre-commit" fazasini qo‘shib, bloklashni kamaytirishga urinadi — lekin qo‘shimcha kechikish keltiradi va tarmoq bo‘linishida (11-mavzu) baribir ishonchsiz. Shuning uchun amalda kam ishlatiladi.
XA bitta tashkilot ichida, past masshtabda, ishonchli tarmoqda (masalan, ikkita ichki baza + broker) hali ham mos. Lekin ko‘p xizmatli, yuqori mavjudlikli mikroservis uchun — Saga (yoki TCC) afzal.
Saga izolyatsiya anomaliyalari
dirty read · lost updateSaga ACID’ning I (Isolation)dan mahrum. Har qadam alohida commit bo‘lgani uchun — oralig‘idagi holat ko‘rinadi, bu anomaliyalar keltiradi.
| Anomaliya | Nima bo‘ladi |
|---|---|
| Dirty read | Boshqa tranzaksiya saga’ning tasdiqlanmagan oraliq holatini o‘qiydi (masalan, hali bekor bo‘lishi mumkin bo‘lgan buyurtmani ko‘radi) |
| Lost update | Parallel saga bir yozuvni ustma-ust o‘zgartiradi — biri yo‘qoladi |
| Non-repeatable / fuzzy read | Bir saga davomida bir qiymatni ikki marta o‘qiganda — o‘rtada boshqa saga o‘zgartiradi |
Saga buyurtma yaratdi (balansdan pul "band" qilinishi kutilmoqda), lekin hali to‘lov tasdiqlanmagan. Shu orada foydalanuvchi boshqa xaridni boshladi — tizim o‘sha pulni yana mavjud deb ko‘radi (dirty read) va ikkinchi xaridga ruxsat beradi. Natijada balans manfiyga ketadi.
Izolyatsiya yo‘qligi — saganing ACID’dan voz kechganidagi tabiiy narxi. Uni to‘liq yo‘qotib bo‘lmaydi, lekin countermeasure’lar (keyingi bo‘lim) bilan boshqarish mumkin.
Izolyatsiya qarshi choralari
semantic lock · rereadIzolyatsiya anomaliyalarini yumshatish uchun bir nechta sinovdan o‘tgan countermeasure (qarshi chora) bor (Chris Richardson).
| Countermeasure | G‘oya |
|---|---|
| Semantic lock | Oraliq yozuvni *_PENDING flag bilan belgilash — boshqalar buni ko‘rib, kutadi/e’tiborsiz qoldiradi |
| Commutative updates | Amallarni tartibga bog‘liqmas qilish (set emas, add/subtract) — tartib buzilsa ham natija bir xil |
| Pessimistic view | Qadamlarni xavfni kamaytiradigan tartibda joylashtirish (masalan, kredit limitni oxirida oshirish) |
| Reread value | O‘zgartirishdan oldin qayta o‘qib, o‘zgarmaganini tekshirish (versiya bilan — optimistik) |
| Version file | Amallarni yozib borib, tartibsiz kelganini to‘g‘ri qayta ishlash |
// SEMANTIC LOCK: oraliq holatni "*_PENDING" bilan belgila -> boshqalar biladi
await this.orders.update(id, { status: "PENDING_PAYMENT" }); // qulf-belgisi
// boshqa tranzaksiya PENDING ko'rsa -> kutadi YOKI e'tiborsiz qoldiradi (dirty read yo'q)
// saga tugagach: "CONFIRMED" (muvaffaqiyat) yoki "CANCELLED" (kompensatsiya)
Amalda semantic lock (status flag) + reread (versiya, 9/10-mavzu optimistik concurrency) kombinatsiyasi ko‘p muammoni hal qiladi: oraliq holat aniq belgilanadi va parallel o‘zgarishlar versiya bilan ushlanadi.
State machine + persistence
saga log · recoveryIshonchli orkestrator — bu shunchaki try/catch emas, balki saqlanadigan state machine. Aks holda orkestrator o‘lsa, saga "yarim yo‘lda" qolib ketadi.
Nega state machine + persistence
Har saga nusxasi o‘z holatiga ega (qaysi qadamda, nima bajarilgan). Bu holat har qadamdan keyin saqlanadi — shunda orkestrator qulab tushsa, qayta ishga tushganda tugallanmagan saga’larni yuklab, davom ettiradi (yoki kompensatsiya qiladi):
// ORCHESTRATOR = SAQLANADIGAN state machine. Har qadamdan keyin holat saqlanadi.
enum SagaState { STARTED, INV_RESERVED, PAID, COMPLETED, COMPENSATING, FAILED }
async advance(sagaId: string) {
const saga = await this.repo.load(sagaId); // saqlangan holatni yukla
switch (saga.state) {
case SagaState.STARTED:
await this.inventory.reserve(saga.orderId);
saga.state = SagaState.INV_RESERVED; break;
case SagaState.INV_RESERVED:
await this.payment.charge(saga.orderId);
saga.state = SagaState.PAID; break;
case SagaState.PAID:
await this.orders.confirm(saga.orderId);
saga.state = SagaState.COMPLETED; break;
}
await this.repo.save(saga); // HAR qadamdan keyin SAQLA -> crash bo'lsa davom ettiriladi
}
// ishga tushganda: tugallanmagan saga'larni yuklab, davom ettiradi yoki kompensatsiya qiladi
Bu naqshni Temporal, Camunda, AWS Step Functions kabi "workflow engine"lar tayyor beradi: saga holatini o‘zi saqlaydi, retry/timeout/tiklanishni boshqaradi. Murakkab, uzoq jarayonlar uchun o‘zing yozishdan afzal.
Saga + Outbox / Event Sourcing
dual-write · outboxSaga’ning har qadamida yashirin muammo bor: mahalliy bazani yangilash va keyingi qadam uchun event yuborish — bu ikkalasi atomik bo‘lishi kerak. Bu — 3-mavzudagi dual-write muammosi.
Qadam bazani yangiladi, keyin event yuboraman deganda — o‘rtada qulaydi. Endi baza o‘zgargan, lekin event ketmagan → saga to‘xtab qoladi (keyingi qadam trigger bo‘lmaydi). Yoki event ketdi-yu, baza saqlanmadi.
Yechim — Transactional Outbox
Har qadamda mahalliy o‘zgarish va chiqadigan eventni bitta mahalliy tranzaksiyada yozamiz (outbox jadvaliga). Alohida relay outbox’dan ishonchli publish qiladi:
// Har saga qadami: mahalliy o'zgarish + event BITTA tranzaksiyada (Outbox, 3-mavzu)
await this.prisma.$transaction(async (tx) => {
await tx.inventory.update({ where: { id }, data: { reserved: true } }); // biznes
await tx.outbox.create({ data: { type: "inventory.reserved", payload } }); // event
});
// alohida relay outbox'dan o'qib, event'ni ishonchli publish qiladi
// -> mahalliy o'zgarish VA uning eventi atomik (dual-write muammosi hal bo'ldi)
Event Sourcing (10-mavzu) buni tabiiy hal qiladi: qadam natijasi allaqachon event sifatida saqlanadi (haqiqat manbai), va process manager (10-mavzu) o‘sha eventga reaksiya qilib keyingi qadamni boshlaydi. Saga + ES + Outbox — ishonchli taqsimlangan tranzaksiyaning to‘liq to‘plami. Bu — butun kursning birlashishi.
Try-Confirm-Cancel
reserve · confirm · cancelTCC (Try-Confirm-Cancel) — saganing muqobili. U resursni oldindan band qiladi, shuning uchun "dirty" tasdiqlangan oraliq holat bo‘lmaydi — izolyatsiya yaxshiroq.
Uch faza
Saga qadamlarni to‘liq commit qilib, xatolikda kompensatsiya qiladi. TCC boshqacha: avval hammani band (reserve) qiladi (yakuniy emas), hammasi muvaffaqiyatli bo‘lsa Confirm, aks holda Cancel:
// TCC — Try / Confirm / Cancel: resurs OLDINDAN band qilinadi (dirty commit yo'q)
async try_(orderId: string) { // 1) TRY — band qil (yakuniy emas)
await this.inventory.hold(orderId); // inventarni "hold"
await this.payment.authorize(orderId); // pulni "hold" (yechmaydi)
}
async confirm(orderId: string) { // 2) CONFIRM — yakunlash
await this.inventory.deduct(orderId); // hold'dan yech
await this.payment.capture(orderId); // hold qilingan pulni ol
}
async cancel(orderId: string) { // 3) CANCEL — bekor qilish
await this.inventory.release(orderId); // hold'ni bo'shat
await this.payment.void(orderId); // authorizatsiyani bekor qil
}
| Saga | TCC | |
|---|---|---|
| Oraliq holat | To‘liq commit (dirty ko‘rinishi mumkin) | Faqat "band" (yakuniy emas) |
| Izolyatsiya | Zaif (countermeasure kerak) | Kuchliroq |
| Talab | Kompensatsiya amali | Resurs "reserve/hold"ni qo‘llashi kerak |
TCC yaxshiroq izolyatsiya beradi, lekin har resurs (inventar, to‘lov) hold/reserveni qo‘llashini talab qiladi — ko‘proq ish. Saga esa universalroq (istalgan amalni kompensatsiya bilan). Yuqori izolyatsiya kerak bo‘lsa (to‘lov, band qilish) — TCC; umumiy holatda — Saga.
Retriable/non-retriable va observability
forward/backward recoveryHar xatolik kompensatsiya talab qilmaydi. Senior xatolarni tasniflaydi va sagani kuzatishni ta’minlaydi.
Retriable vs non-retriable — forward vs backward recovery
- Retriable (o‘tkinchi): timeout, vaqtincha ishlamaslik, tarmoq. Bu qadam aslida bajarilishi mumkin edi — kompensatsiya qilma, qayta urin (forward recovery, 14-mavzu).
- Non-retriable (biznes): "mablag‘ yetarli emas", "mahsulot yo‘q". Bu qadam hech qachon bajarilmaydi — oldingilarni bekor qil (backward recovery, kompensatsiya).
// Xatoni TASNIFLA: retriable (o'tkinchi) -> qayta urin; non-retriable (biznes) -> kompensatsiya
catch (err) {
if (isTransient(err)) { // timeout, 503, tarmoq -> FORWARD recovery
await retryWithBackoff(() => this.step()); // to'xtatmaydi, oldinga davom (14-mavzu)
} else { // "mablag' yetarli emas" -> BACKWARD recovery
await this.compensate(); // oldingi qadamlarni bekor qil
}
}
Saga observability — kuzatish qiyin
Saga taqsimlangan, asinxron, uzoq davom etadi — "qaysi buyurtma qaysi qadamda qotib qoldi?" ni bilish qiyin. Debug qilish og‘riqli.
1. Correlation/saga ID har qadam va logda — butun saga oqimini bir joyda ko‘rish. 2. Saga holatini kuzatish — har nusxa qaysi holatda (state machine, 4-bo‘lim). 3. "Qotib qolgan saga" alerti — belgilangan vaqtdan oshsa (masalan, 5 daqiqa PENDING) → ogohlantirish. 4. Vizualizatsiya — saga oqimini trace bilan ko‘rish (distributed tracing, 12-mavzu).
Yig‘ma ko‘rinish va senior cheklist
Ishonchli saga arxitekturasi — yig‘ma ko‘rinish
| Qism | Vazifa | Bo‘lim |
|---|---|---|
| Orchestrator state machine (saqlanadigan) | Qadamlarni boshqaradi, crash’dan tiklanadi | 4 |
| Outbox per qadam | Mahalliy o‘zgarish + event atomik | 5 |
| Idempotent qadam + kompensatsiya | Retry’ga chidamli | 3 |
| Semantic lock + countermeasure | Izolyatsiya anomaliyalarini yumshatadi | 3 |
| Retriable/non-retriable tasnif | Forward yoki backward recovery | 7 |
| Saga ID + state tracking + alert | Kuzatuvchanlik | 7 |
Senior tayyorlik cheklisti
| Savol / amaliyot | Bo‘lim |
|---|---|
| 2PC bloklovchi muammosini, XA va 3PC’ni bilaman; qachon mos ekanini | 1 |
| Saga izolyatsiya anomaliyalarini (dirty read, lost update) tushunaman | 2 |
| Countermeasure’larni (semantic lock, commutative, reread) qo‘llayman | 3 |
| Orkestratorni saqlanadigan state machine sifatida quraman (crash-recovery) | 4 |
| Har qadamda outbox bilan atomiklikni ta’minlayman (dual-write hal) | 5 |
| Yuqori izolyatsiya kerak joyda TCC (Try-Confirm-Cancel) ishlataman | 6 |
| Xatolarni retriable/non-retriable tasniflayman; sagani kuzataman | 7 |
Bu 13-mavzuning Deep/Senior qatlami edi — Core bilan birga, Distributed Transactions endi to‘liq.
Keyingi mavzu: “14-mavzu: Resilience Engineering” — nosozliklarga chidamli tizim (timeout, retry, circuit breaker, bulkhead) — bu darsda ko‘p bor eslatilgan retry/idempotency’ni to‘liq ochadi. Core’dan boshlaymiz.