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

Resilience Engineering — Senior chuqurlik

Bu — 14-mavzuning 2-qatlami. Core darslikni o‘qib bo‘lgan deb hisoblanadi. Bu yerda eng chuqur narsalar: circuit breaker ichki mexanika, adaptiv timeout, deadline propagation, retry budget, hedged requests, bulkhead o‘lchamlash, backpressure, load shedding, self-healing, idempotency key va chaos engineering — junior’dan seniorgacha.

Daraja: SeniorMavzular: deadline · retry budget · hedging · chaosOld shart: 14-mavzu (Core)

Bu qatlamda nima bor

Core darslik asoslarni berdi. Bu Deep qatlam senior darajadagi chuqur mexanikani ochadi: circuit breaker ichki ishlashi va sozlash, adaptiv timeout va deadline propagation, retry budget va hedged requests, bulkhead o‘lchamlash (Little qonuni) va backpressure, load shedding algoritmlari, self-healing halqasi, idempotency key va "effectively-once", hamda chaos engineering. Oxirida — senior cheklist.

01
Deep · Breaker

Circuit breaker ichki mexanika

sliding window · slow-call
⚙️

Core’da circuit breaker’ning uch holatini ko‘rdik. Senior uning ichki mexanikasini va har sozlamaning ta’sirini biladi — noto‘g‘ri sozlangan breaker foyda o‘rniga zarar keltiradi.

Sliding window — qaror qanday qilinadi

Breaker "ochilishni" har xatoda emas, oyna (sliding window) statistikasi asosida hal qiladi: oxirgi N chaqiruv (count-based) yoki oxirgi T vaqt (time-based) ichidagi xato foizi. Bu tebranishni silliqlaydi.

# Circuit breaker ichki sozlamalari (resilience4j uslubi)
slidingWindowType: COUNT_BASED         # oxirgi N chaqiruv oynasi (yoki TIME_BASED)
slidingWindowSize: 100                  # 100 ta chaqiruv kuzatiladi
minimumNumberOfCalls: 20                # kamida 20 ta bo'lmasa OCHILMAYDI (kam namunaga trip yo'q)
failureRateThreshold: 50                # 50% xato -> OPEN
slowCallRateThreshold: 80               # 80% "sekin" ham -> OPEN (xato bo'lmasa ham!)
slowCallDurationThreshold: 2s           # 2s dan uzoq = "sekin"
waitDurationInOpenState: 10s            # OPEN'da 10s kutadi -> keyin HALF-OPEN
permittedNumberOfCallsInHalfOpenState: 5 # HALF-OPEN'da 5 ta sinov
oxirgi N chaqiruvda xato% chegaradan oshsa → OPEN
Sliding window: bitta xato emas, statistik xato foizi qaror qiladi
Ikki nozik nuqta

1. minimumNumberOfCalls — kam namunaga trip qilmaslik uchun. 2 tadan 1 tasi fail bo‘lsa (50%) darhol ochilmasin — kamida 20 ta bo‘lsin. 2. slowCallRateThreshold — breaker faqat xatoga emas, sekin chaqiruvlarga ham ochilishi kerak: sekin xizmat oqimlarni yeydi (kaskad), garchi "xato" qaytarmasa ham. Buni ko‘pchilik unutadi.

02
Deep · Timeout

Adaptiv timeout va deadline propagation

deadline · gRPC
⏱️

Static timeout qo‘pol: juda qisqa bo‘lsa — normal so‘rovlarni kesadi; juda uzun bo‘lsa — kaskadga imkon beradi. Senior adaptiv timeout va deadline propagationni biladi.

Adaptiv timeout

Belgilangan raqam o‘rniga — kuzatilgan kechikishga qarab: masalan, timeout = p99 × 1.5. Xizmat sekinlashsa, timeout ham moslashadi. Bu normal o‘zgaruvchanlikni kesmasdan, haqiqiy osilishni ushlaydi.

Deadline propagation — behuda ishni yo‘qotish

Muammo

Foydalanuvchi 2s kutadi, keyin ketadi. Lekin so‘rov ichkarida A→B→C bo‘ylab ketyapti — C hali ishlayapti, garchi chaqiruvchi allaqachon voz kechgan. Bu — behuda ish, resurs isrofi.

Yechim: so‘rovga umumiy deadline (absolyut vaqt) ber; har hop qolgan vaqtni hisoblab, undan ko‘p ishlamaydi va keyingisiga uzatadi:

// DEADLINE PROPAGATION: umumiy muddat; har hop QOLGANini uzatadi
async function callWithDeadline(deadline: number) {   // deadline = absolyut vaqt (ms)
  const remaining = deadline - Date.now();
  if (remaining <= 0) throw new DeadlineExceeded();    // vaqt tugadi -> ishlamay xato ber

  return this.http.get(url, {
    timeout: remaining,                                // qolgan vaqtdan ko'p kutma
    headers: { "x-deadline": String(deadline) },       // keyingi xizmat ham QOLGANini biladi
  });
}
// -> hech bir xizmat "chaqiruvchi allaqachon voz kechgan" so'rovga ishlamaydi (behuda ish yo'q)
A (qoldi 2000ms) B (qoldi 1600ms) C (qoldi 1100ms)
Deadline har hop’da kamayadi; tugasa — hech kim behuda ishlamaydi (gRPC buni tabiiy qo‘llaydi)
03
Deep · Retry

Retry budget va hedged requests

retry budget · hedging
🎯

Core’da retry’ni ko‘rdik. Senior darajada uni byudjet bilan cheklaydi va tail latency uchun hedged requests ishlatadi.

Retry budget — bo‘ronni matematik to‘xtatish

"3 marta retry" yetarli emas: ommaviy nosozlikda har mijoz 3x yuboradi → yuk 4x. Retry budget — retry’larni umumiy trafikning foizi sifatida cheklaydi (masalan, 10%). Byudjet tugasa — retry qilinmaydi, tizim himoyalanadi:

// RETRY BUDGET: retry'lar umumiy trafikning ~10%idan oshmasin (retry storm'ni to'sadi)
if (this.retryBudget.tryAcquire()) {        // token bucket: har request byudjet qo'shadi
  await retryWithBackoff(() => call());
} else {
  throw err;                                // byudjet tugadi -> retry YO'Q (tizimni himoya)
}

Hedged requests — tail latency’ga qarshi

p99 kechikish odatda bitta sekin replika tufayli. Hedged (backup) request: birinchi so‘rov p95’dan sekinlashsa — ikkinchisini boshqa replikaga yuborasan, qaysi biri oldin kelsa — o‘shani olasan:

// HEDGED REQUEST: birinchi so'rov p95'dan sekinlashsa -> ikkinchisini boshqa replikaga
async function hedged<T>(call: () => Promise<T>): Promise<T> {
  const first = call();
  const backup = delay(P95_MS).then(() => call());   // p95'dan keyin ikkinchi urinish
  return Promise.race([first, backup]);              // qaysi biri OLDIN kelsa -> o'sha
}
// tail latency (p99)'ni keskin kamaytiradi; qo'shimcha yuk CHEGARALANGAN (faqat sekinlarga)
1-so‘rov (sekin 🐢) backup (tez ✓) p95’da hedge
Hedged request: sekin so‘rovni backup bilan "musobaqalashtirib" tail’ni kesadi
Muvozanat

Hedged request qo‘shimcha yuk keltiradi — shuning uchun faqat p95’dan oshgan (kam sonli sekin) so‘rovlar uchun ishlatiladi va retry budget bilan cheklanadi. Aks holda yukni ikki barobar oshirasan. Bu — "The Tail at Scale" (Google) yondashuvi.

04
Deep · Bulkhead

O‘lchamlash va backpressure

Little qonuni · backpressure
📏

Core’da bulkhead g‘oyasini ko‘rdik. Senior uni to‘g‘ri o‘lchaydi va backpressure bilan to‘ldiradi.

Bulkhead o‘lchamlash — Little qonuni

"Nechta bir vaqtli chaqiruvga ruxsat berish?" tasodifan tanlanmaydi. Little qonuni: concurrency = throughput × latency. Agar bog‘liqlik 100 req/s ni 50ms’da bajarsa — ~5 bir vaqtli slot yetadi. Buni bilib, semaphore o‘lchamini to‘g‘ri qo‘yasan:

// BULKHEAD (semaphore): har bog'liqlikka bir vaqtda ruxsat etilgan max chaqiruv
// O'LCHAM (Little's Law):  concurrency = throughput * latency
//   masalan 100 req/s * 0.05s = 5  ->  ~5-10 slot yetarli
const paymentBulkhead = new Semaphore(10);   // to'lovga bir vaqtda max 10 chaqiruv

const ok = await paymentBulkhead.tryAcquire(50 /*ms kut*/);
if (!ok) throw new BulkheadFullException();   // to'lgan -> DARHOL rad (fail fast)
try { return await this.payment.charge(); }
finally { paymentBulkhead.release(); }

Backpressure — "sekinlash" signali

Muammo

Downstream sekinlashsa, upstream so‘rovlarni cheksiz buferlaydi — xotira to‘ladi, kechikish o‘sadi, oxiri OOM bilan qulaydi. Buferlash muammoni yashiradi, keyin portlatadi.

Yechim — backpressure

Cheksiz bufer o‘rniga — chegaralangan navbat; to‘lsa, upstream’ga "sekinlash" signali beriladi (yoki rad etiladi). Bu TCP oqim nazoratiga o‘xshaydi: qabul qiluvchi tayyor bo‘lganda yuboriladi. Reactive Streams (va RxJS) buni tabiiy qo‘llaydi. Prinsip: muammoni yashirma, tez signal ber.

05
Deep · Shedding

Load shedding algoritmlari

CoDel · priority · brownout
🚮

Core’da "ortiqcha yukni rad et" dedik. Senior darajada qaysi so‘rovni, qachon rad etishni aqlli algoritm hal qiladi.

Oddiy rate limit yetarli emas

Qat’iy "sekundiga 1000 so‘rov" cheklovi qo‘pol: yuk past bo‘lsa ham keraksiz rad etadi, tizim allaqachon cho‘kayotgan bo‘lsa — kech qoladi. Aqlliroq yondashuvlar:

AlgoritmG‘oya
Priority-basedYuk oshsa — avval past prioritetli (analitika, batch) so‘rovlarni tashla, kritiklarini (to‘lov) saqla
Latency-based (CoDel)Navbatda kutish vaqti oshsa — tashla (soni emas, kechikish signal). Tizim haqiqatan bosilganda reaksiya qiladi
LIFO under loadBosim ostida — eng yangi so‘rovni birinchi xizmat qil (eskilari allaqachon timeout bo‘lgan bo‘lishi mumkin)
Adaptive (health-based)Server sog‘lig‘iga (CPU, navbat) qarab qabul darajasini dinamik sozla
Prinsip

Load shedding’ning maqsadi — "brownout": to‘liq qorong‘ilik (o‘lish) o‘rniga xira yorug‘lik (cheklangan, lekin ishlaydigan xizmat). Google/Facebook’ning yondashuvi: kechikish/navbatga qarab tashlash — chunki bu tizim haqiqatan bosilganini ko‘rsatadi, oddiy so‘rov soni emas.

06
Deep · Self-heal

Self-healing halqasi

outlier · autoscale
🔧

Self-healing — tizim nosozlikni o‘zi aniqlab, tuzatadi (odam aralashuvisiz). Bu oldingi naqshlarni avtomatlashtirish halqasi.

Self-healing halqasi

Aniqla → izolyatsiya qil → tikla → qayta qo‘sh. Amalda bu oldingi mavzular birlashmasi:

  • Health check (5-mavzu) — o‘lik/sog‘lom instance’ni aniqlaydi; liveness buzilsa — pod avtomatik qayta ishga tushadi.
  • Outlier detection (5-mavzu Deep) — tinmay xato beradigan instance’ni trafikdan avtomatik chiqaradi, tuzalsa qaytaradi.
  • Autoscaling (5-mavzu Deep) — yuk oshsa avtomatik ko‘proq instance.
  • Circuit breaker (bu mavzu) — o‘layotgan bog‘liqlikni avtomatik uzadi va half-open bilan tuzalishini o‘zi sinaydi.
Aniqla Izolyatsiya Tikla Qayta qo‘sh
Self-healing halqasi: odam aralashuvisiz avtomatik tiklanish
Kubernetes bilan

K8s bu halqaning ko‘p qismini beradi: liveness probe → restart, readiness probe → trafikdan chiqarish, HPA → autoscale. Ilova tomonda circuit breaker + retry + health endpoint qo‘shsang — to‘liq self-healing tizim.

07
Deep · Idempotency

Idempotency key va exactly-once

effectively-once
🔑

Kurs davomida "idempotent bo‘lsin" dedik (3, 13-mavzular). Senior darajada — idempotency key mexanikasi va "exactly-once" afsonasi.

Idempotency key qanday ishlaydi

Mijoz har amalga noyob kalit yuboradi (masalan, Idempotency-Key header). Server: bu kalit ko‘rilganmi? Ha bo‘lsa — saqlangan natijani qaytar (qayta bajarmasdan); yo‘q bo‘lsa — bajar, natijani kalit bilan saqla:

// IDEMPOTENCY KEY: mijoz noyob kalit yuboradi; server dedup qiladi (retry xavfsiz)
async function handle(key: string, body: any) {
  const existing = await this.store.get(key);
  if (existing) return existing.result;              // TAKROR -> saqlangan natijani qaytar

  const locked = await this.store.acquireLock(key);  // parallel takrorni to'sish (SETNX)
  if (!locked) throw new ConflictException("In progress");

  const result = await this.process(body);           // FAQAT bir marta bajariladi
  await this.store.save(key, result, { ttl: "24h" });
  return result;
}
Nozik nuqta — race condition

Ikki bir xil kalitli so‘rov bir vaqtda kelsa — ikkalasi "ko‘rilmagan" deb topib, ikki marta bajaradi. Yechim: kalit bo‘yicha qulf (Redis SETNX, 4-mavzu) — faqat bittasi bajaradi, ikkinchisi kutadi yoki natijani oladi.

"Exactly-once" afsonasi

Muhim haqiqat: tarmoqda chinakam "exactly-once delivery" imkonsiz (xabar yetdimi yoki ack yo‘qoldimi — bila olmaysan). Amalda erishiladigan narsa: at-least-once yetkazish + idempotent qayta ishlash = "effectively-once". Ya’ni xabar bir necha marta kelishi mumkin, lekin idempotency uni bir marta bajarilgandek qiladi. Bu — 3 va 13-mavzularning yakuniy tushunchasi.

08
Deep · Chaos

Chaos engineering va senior cheklist

🐒

Resilience naqshlarini qurding — lekin ular haqiqatan ishlaydimi? Buni bilishning yagona yo‘li — chaos engineering: ataylab nosozlik keltirib, tizim chidashini tekshirish.

Chaos engineering amaliyoti

  • Gipoteza: "To‘lov xizmati o‘lsa, buyurtma fallback bilan ishlashda davom etadi" — deb taxmin qil.
  • Steady-state metrika: normal holatni o‘lchab ol (SLO, 12-mavzu).
  • Nosozlik kirit: ataylab xizmatni o‘chir, kechikish qo‘sh, tarmoqni uz.
  • Blast radius nazorati: avval kichik (bitta instance, oz trafik), ishonch ortsa kengaytir.
  • Natija: gipoteza tasdiqlansa — yaxshi; buzilsa — zaiflik topildi, tuzatiladi (incidentdan oldin).
Vositalar va tarix

Netflix Chaos Monkey (tasodifan instance o‘chiradi) va Simian Army bu amaliyotni ommalashtirdi. Idea: nosozlik muqarrar bo‘lsa — uni nazorat ostida, ish vaqtida keltirib, tizimni doim chidamli tut. "Game day"larda jamoa birgalikda mashq qiladi.

Senior tayyorlik cheklisti

Savol / amaliyotBo‘lim
Circuit breaker’ni sliding window, min-calls, slow-call bilan to‘g‘ri sozlayman1
Adaptiv timeout va deadline propagation qo‘llayman (behuda ish yo‘q)2
Retry budget bilan bo‘ronni to‘xtataman; tail uchun hedged request3
Bulkhead’ni Little qonuni bilan o‘lchayman; backpressure bilan buferni cheklayman4
Load shedding’ni prioritet/kechikish asosida qilaman (brownout)5
Self-healing halqasini (health/outlier/autoscale/breaker) quraman6
Idempotency key + qulf ishlataman; "effectively-once"ni tushunaman7
Chaos engineering bilan resilience’ni sinab ko‘raman8

Bu 14-mavzuning Deep/Senior qatlami edi — Core bilan birga, Resilience Engineering endi to‘liq.

Endi oxirgi mavzu — “15-mavzu: Clean Architecture”. Bu butun kursni toza, saqlanadigan kod tuzilmasi bilan yakunlaydi: barcha o‘rganganingni qanday tashkil qilish. Core’dan boshlaymiz.