Bu darsda nima bor
1–4-qismlar taqsimlangan tranzaksiyani noldan quradi: nega kerak, nega oddiy tranzaksiya ishlamaydi, 2PC va nega undan qochiladi, va Saga naqshi (mahalliy tranzaksiyalar + kompensatsiya). 5–6-qismlar — choreography vs orchestration (NestJS) va kompensatsiyaning qiyinchiliklari (idempotency, izolyatsiya). 7-qism qachon Saga kerak (va qachon to‘g‘ri chegaralar bilan uni umuman keltirmaslik) ekanini hal qiladi.
Nega kerak — tranzaksiya chegaradan o‘tmaydi
Oddiy o‘xshatish: uy sotib olishda bir necha mustaqil tomon (bank, notarius, sotuvchi) ishtirok etadi. Hech biri boshqasining ishini "orqaga qaytara" olmaydi. Agar bank kreditni rad etsa — notarius allaqachon qilgan ishni alohida amal bilan bekor qilish kerak, "undo" tugmasi yo‘q.
Monolitda bitta baza bilan tranzaksiya oson: BEGIN … COMMIT, ACID hammasini "yo hammasi, yo hech nima" qiladi. Lekin mikroservisda (database-per-service, 1-mavzu) bitta biznes amali bir necha xizmat va bazaga tegadi.
"Buyurtma ber" amali: Buyurtma xizmati yozadi → Inventar xizmati mahsulot band qiladi → To‘lov xizmati pul yechadi. Har biri alohida bazada. Agar to‘lov oxirida muvaffaqiyatsiz bo‘lsa — buyurtma yaratilgan, inventar band qilingan, lekin pul yo‘q. Endi inventar abadiy band bo‘lib qoladi. Bitta ACID tranzaksiya bularni qamrab ololmaydi.
Xizmatlar aro izchillikni saqlashning maxsus yo‘llari kerak. Ikki asosiy yondashuv: 2PC (kuchli, lekin qochiladi) va Saga (mikroservis standarti — mahalliy tranzaksiyalar + kompensatsiya).
Nega oddiy tranzaksiya ishlamaydi
Avval nega oddiy tranzaksiya yetmasligini aniq tushunamiz:
ACID tranzaksiya — bitta baza ulanishining xususiyati. Uch xil bazada uch xil ulanish bor, ularni bitta BEGIN…COMMITga bog‘lab bo‘lmaydi. Demak: yo hammasini birlashtiruvchi koordinator kerak (2PC), yo butunlay boshqa model (Saga).
Bu ma’lumot chegaralari (1-mavzu database-per-service)ning tabiiy oqibati. Xizmatlarni ajratganingda — ularning bazalari ham ajraladi, va tranzaksiya endi "bepul" emas.
2PC va nega undan qochiladi
2PC · prepare/commitBirinchi yechim — barcha bazalarni bitta koordinator bilan birlashtirish: 2PC (Two-Phase Commit). Ishlaydi, lekin mikroservisda undan qochiladi.
2PC qanday ishlaydi
Koordinator ikki fazada boshqaradi:
Faza 1 (prepare): koordinator hammadan "commit qila olasizmi?" deb so‘raydi, har biri tayyorlanadi va qulflaydi, "ha" deydi. Faza 2 (commit): hamma "ha" desa — koordinator "commit" buyuradi; kimdir "yo‘q" desa — hamma "abort" qiladi. Atomiklik kafolatlanadi.
Bloklovchi: prepare fazasida qulflar ushlab turiladi; koordinator faza orasida o‘lsa — ishtirokchilar abadiy qulfda qolishi mumkin.
Koordinator SPOF va sinxron (sekin).
Mavjudlik pasayadi: bitta ishtirokchi sekin/o‘lik bo‘lsa — hammasi kutadi.
Bu — yuqori mavjudlikli mikroservis falsafasiga (CAP, 11-mavzu) zid. Shuning uchun zamonaviy mikroservis 2PC o‘rniga Saga tanlaydi.
Saga — asosiy naqsh
saga · kompensatsiyaSaga — mikroservis uchun standart yechim. G‘oyasi oddiy: bitta katta tranzaksiya o‘rniga — ketma-ket mahalliy tranzaksiyalar, va xatolikda kompensatsiya (bekor qiluvchi amallar).
Saga qanday ishlaydi
Har xizmat o‘z mahalliy ACID tranzaksiyasini bajaradi va keyingisini ishga tushiradi. Biror qadam muvaffaqiyatsiz bo‘lsa — oldingi qadamlarni teskari tartibda bekor qiluvchi (compensating) tranzaksiyalar ishga tushadi:
Muhim: bu ACID emas, eventual consistency. Oralig‘ida tizim vaqtincha nomuvofiq bo‘lishi mumkin (buyurtma bor, lekin hali tasdiqlanmagan), lekin oxir-oqibat izchil holatga keladi — yo hammasi bajariladi, yo hammasi bekor qilinadi.
Farq muhim: 2PC/ACID rollback qiladi (hech narsa bo‘lmagandek). Saga’da qadam allaqachon commit bo‘lgan — uni "orqaga qaytarib" bo‘lmaydi, buning o‘rniga yangi, teskari amal qilinadi (pul yechildi → refund qilinadi, "un-charge" emas).
Choreography vs Orchestration
NestJS sagaSaga’ni muvofiqlashtirishning ikki uslubi bor:
1 · Orchestration — markaziy koordinator
Bitta orkestrator qadamlarni ketma-ket chaqiradi, holatni kuzatadi va xatolikda kompensatsiyani boshqaradi. Mantiq bir joyda — murakkab jarayonlar uchun aniqroq:
// ORCHESTRATION SAGA: markaziy koordinator qadamlar + kompensatsiyalarni boshqaradi
async placeOrder(dto: CreateOrderDto) {
const undo: (() => Promise<void>)[] = []; // kompensatsiya stack'i
try {
const order = await this.orders.create(dto); // 1-qadam
undo.push(() => this.orders.cancel(order.id));
await this.inventory.reserve(order.id, dto.items); // 2-qadam
undo.push(() => this.inventory.release(order.id));
await this.payment.charge(order.id, dto.amount); // 3-qadam
undo.push(() => this.payment.refund(order.id)); // refund = kompensatsiya
await this.orders.confirm(order.id); // yakuniy
return order;
} catch (err) {
for (const compensate of undo.reverse()) { // TESKARI tartibda bekor qil
await compensate(); // idempotent bo'lishi SHART
}
throw new SagaFailedException(err);
}
}
2 · Choreography — markaziy koordinatorsiz
Koordinator yo‘q; har xizmat eventga reaksiya qilib, keyingi eventni chiqaradi (3-mavzu). Oddiy oqimlar uchun yengil, lekin mantiq tarqoq:
// CHOREOGRAPHY SAGA: markaziy koordinator YO'Q; har xizmat eventga reaksiya qiladi
@EventPattern("order.created")
async onOrderCreated(order: Order) {
try {
await this.reserve(order.items);
this.client.emit("inventory.reserved", { orderId: order.id }); // keyingi qadam
} catch {
this.client.emit("order.failed", { orderId: order.id }); // kompensatsiya trigger
}
}
| Choreography | Orchestration | |
|---|---|---|
| Boshqaruv | Tarqoq (event bilan) | Markaziy (orkestrator) |
| Mantiq | Xizmatlarga tarqalgan | Bir joyda |
| Qulaylik | Oddiy oqimlar | Murakkab, ko‘p qadamli |
| Kamchilik | Kuzatish/debug qiyin | Orkestrator — markaz |
Kompensatsiya va qiyinchiliklar
idempotency · isolationKompensatsiya sodda ko‘rinadi, lekin amalda bir necha nozik muammo bor. Senior ularni oldindan hisobga oladi.
Kompensatsiyaning qiyin tomonlari
- Kompensatsiya ham muvaffaqiyatsiz bo‘lishi mumkin: "inventarni bo‘shat" ham xato bersa? → retry + idempotency (14-mavzu) shart. Kompensatsiya qayta-qayta xavfsiz bajarilishi kerak.
- Ba’zi amallarni bekor qilib bo‘lmaydi: email yuborildi, SMS ketdi — "un-send" yo‘q. Yechim: bunday amallarni saga oxiriga qo‘y (hammasi tasdiqlangach), yoki "bekor qilindi" xabari yubor.
- Izolyatsiya yo‘q: saga davomida boshqa tranzaksiya oralig‘idagi holatni ko‘rishi mumkin (buyurtma yaratilgan, lekin hali tasdiqlanmagan). Bu — "dirty read"ga o‘xshash muammo.
Izolyatsiya muammosi uchun oddiy yechimlar: semantic lock (oralig‘idagi yozuvni "pending" deb belgilash — boshqalar buni ko‘rib, kutadi yoki e’tiborsiz qoldiradi), qisqa oraliq holatlar, va idempotent qadamlar. (Chuqurroq countermeasure’lar Deep qatlamda.)
Har bir saga qadami va har bir kompensatsiya idempotent bo‘lishi shart: retry yoki takror yuborilsa, ikki marta bajarilmasin. Buni ta’minlash uchun har amalga noyob ID va dedup (3, 9-mavzular idempotency).
Qachon Saga (va qachon kerak emas)
Saga kuchli, lekin har biznes amali uchun emas. Eng yaxshi taqsimlangan tranzaksiya — ko‘pincha uning umuman kerak bo‘lmagani.
1. Avval — kerakmi? Agar bog‘liq ma’lumot bitta xizmat/aggregat ichida bo‘lsa (yaxshi chegaralar, 2-mavzu), oddiy mahalliy tranzaksiya yetadi — taqsimlangan tranzaksiya kerak emas. To‘g‘ri domen dizayni ko‘p muammoni yo‘qotadi.
2. 2PC’dan qoch mikroservisda (bloklovchi, SPOF). Zarur bo‘lsa — Saga.
3. Uslub tanlash: oddiy, kam qadamli oqim → choreography; murakkab, ko‘p qadamli, kuzatuv muhim → orchestration.
4. Har qadam va kompensatsiya idempotent bo‘lsin; bekor qilib bo‘lmaydigan amallarni oxirga qo‘y.
5. Eventual consistency’ni qabul qil — foydalanuvchiga oraliq holatni ("qayta ishlanmoqda") to‘g‘ri ko‘rsat.
Saga — 1-mavzudagi (mikroservis resilience) va 10-mavzudagi (process manager) g‘oyalarning davomi. Kompensatsiya, retry va idempotency esa 14-mavzu (Resilience Engineering) bilan chambarchas.
Eslab qolish kerak bo‘lgan 5 jumla
- Bitta ACID tranzaksiya faqat bitta baza ichida ishlaydi. Mikroservisda (database-per-service) biznes amali ko‘p bazaga tegadi — oddiy tranzaksiya yetmaydi.
- 2PC (prepare + commit) atomiklik beradi, lekin bloklovchi, SPOF, sekin — mikroservisda qochiladi.
- Saga — standart yechim: ketma-ket mahalliy tranzaksiyalar + xatolikda kompensatsiya (rollback emas — refund kabi yangi teskari amal). Eventual consistency.
- Choreography (event, tarqoq — oddiy oqim) vs Orchestration (markaziy koordinator — murakkab oqim).
- Qiyin tomonlar: kompensatsiya ham fail bo‘lishi, bekor qilib bo‘lmaydigan amallar, izolyatsiya yo‘qligi. Har qadam idempotent bo‘lishi shart. Eng yaxshisi — to‘g‘ri chegaralar bilan taqsimlangan tranzaksiyani umuman keltirmaslik.
Bu mavzuning Deep/Senior qatlami (2PC/3PC va XA chuqur, saga izolyatsiya anomaliyalari va countermeasure’lar — semantic lock/commutative/pessimistic view/reread/version, orchestrator state machine + persistence, saga + outbox/event sourcing, TCC — Try-Confirm-Cancel, retriable vs non-retriable xatolar, saga observability) kerak bo‘lsa — ayting.
Yoki keyingi mavzu: “14-mavzu: Resilience Engineering” — nosozliklarga chidamli tizim (timeout, retry, circuit breaker).