Tizim dizayni kursi · 13-mavzu · DEEP / SENIOR
TuzdiDinMuhammad

Distributed Transactions — Senior chuqurlik

Bu — 13-mavzuning 2-qatlami. Core darslikni o‘qib bo‘lgan deb hisoblanadi. Bu yerda eng chuqur narsalar: 2PC/3PC/XA, saga izolyatsiya anomaliyalari va countermeasure’lar, orchestrator state machine, saga + outbox/event sourcing, TCC va retriable/non-retriable recovery — junior’dan seniorgacha.

Daraja: SeniorMavzular: XA · semantic lock · TCC · outboxOld shart: 13-mavzu (Core)

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.

01
Deep · 2PC/XA

2PC bloklash, XA va 3PC

XA · blocking · 3PC
🔒

Core’da 2PC’dan "qochiladi" dedik. Senior nega ekanini aniq mexanika bilan biladi — va XA/3PC nima ekanini.

2PC ning "bloklovchi" muammosi — aniq stsenariy

Halokat lahzasi

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.

Koordinator ✕ (o‘ldi) prepared, QULFDA bloklangan prepared, QULFDA bloklangan
Koordinator faza orasida o‘lsa — ishtirokchilar qulfda qoladi (bloklovchi)

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.

Qachon XA hali ham

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.

02
Deep · Anomalies

Saga izolyatsiya anomaliyalari

dirty read · lost update
🫥

Saga ACID’ning I (Isolation)dan mahrum. Har qadam alohida commit bo‘lgani uchun — oralig‘idagi holat ko‘rinadi, bu anomaliyalar keltiradi.

AnomaliyaNima bo‘ladi
Dirty readBoshqa tranzaksiya saga’ning tasdiqlanmagan oraliq holatini o‘qiydi (masalan, hali bekor bo‘lishi mumkin bo‘lgan buyurtmani ko‘radi)
Lost updateParallel saga bir yozuvni ustma-ust o‘zgartiradi — biri yo‘qoladi
Non-repeatable / fuzzy readBir saga davomida bir qiymatni ikki marta o‘qiganda — o‘rtada boshqa saga o‘zgartiradi
Konkret misol

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.

Bu — narx

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.

03
Deep · Countermeasures

Izolyatsiya qarshi choralari

semantic lock · reread
🛡️

Izolyatsiya anomaliyalarini yumshatish uchun bir nechta sinovdan o‘tgan countermeasure (qarshi chora) bor (Chris Richardson).

CountermeasureG‘oya
Semantic lockOraliq yozuvni *_PENDING flag bilan belgilash — boshqalar buni ko‘rib, kutadi/e’tiborsiz qoldiradi
Commutative updatesAmallarni tartibga bog‘liqmas qilish (set emas, add/subtract) — tartib buzilsa ham natija bir xil
Pessimistic viewQadamlarni xavfni kamaytiradigan tartibda joylashtirish (masalan, kredit limitni oxirida oshirish)
Reread valueO‘zgartirishdan oldin qayta o‘qib, o‘zgarmaganini tekshirish (versiya bilan — optimistik)
Version fileAmallarni 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)
Eng ko‘p ishlatiladigan — semantic lock

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.

04
Deep · Orchestrator

State machine + persistence

saga log · recovery
⚙️

Ishonchli 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):

STARTED INV_RESERVED PAID COMPLETED COMPENSATING
Saqlanadigan state machine: crash’dan keyin tiklanadi
// 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
Tayyor yechimlar

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.

05
Deep · Outbox

Saga + Outbox / Event Sourcing

dual-write · outbox
📤

Saga’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.

Dual-write muammosi saga ichida

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 bilan

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.

06
Deep · TCC

Try-Confirm-Cancel

reserve · confirm · cancel
🎫

TCC (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:

TRY (band qil) hammasi OK CONFIRM biror TRY fail CANCEL
TCC: oldin band, keyin Confirm yoki Cancel — dirty commit yo‘q
// 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
}
SagaTCC
Oraliq holatTo‘liq commit (dirty ko‘rinishi mumkin)Faqat "band" (yakuniy emas)
IzolyatsiyaZaif (countermeasure kerak)Kuchliroq
TalabKompensatsiya amaliResurs "reserve/hold"ni qo‘llashi kerak
Qaysi birini

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.

07
Deep · Recovery

Retriable/non-retriable va observability

forward/backward recovery
🔀

Har 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

Muammo

Saga taqsimlangan, asinxron, uzoq davom etadi — "qaysi buyurtma qaysi qadamda qotib qoldi?" ni bilish qiyin. Debug qilish og‘riqli.

Yechim (12-mavzu bilan)

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).

08
Deep · Arxitektura

Yig‘ma ko‘rinish va senior cheklist

Ishonchli saga arxitekturasi — yig‘ma ko‘rinish

QismVazifaBo‘lim
Orchestrator state machine (saqlanadigan)Qadamlarni boshqaradi, crash’dan tiklanadi4
Outbox per qadamMahalliy o‘zgarish + event atomik5
Idempotent qadam + kompensatsiyaRetry’ga chidamli3
Semantic lock + countermeasureIzolyatsiya anomaliyalarini yumshatadi3
Retriable/non-retriable tasnifForward yoki backward recovery7
Saga ID + state tracking + alertKuzatuvchanlik7

Senior tayyorlik cheklisti

Savol / amaliyotBo‘lim
2PC bloklovchi muammosini, XA va 3PC’ni bilaman; qachon mos ekanini1
Saga izolyatsiya anomaliyalarini (dirty read, lost update) tushunaman2
Countermeasure’larni (semantic lock, commutative, reread) qo‘llayman3
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) ishlataman6
Xatolarni retriable/non-retriable tasniflayman; sagani kuzataman7

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.