IlmHamroh
Data Science va sun'iy intellekt/MLOps va deploy10/14-dars45 daqiqa
Mundarija (22)

27.10-dars: Bulut va deploy strategiyalari

27-QISM — MLOPS VA DEPLOY · 10-dars


1. Kirish va motivatsiya

Oldingi darsda 27.9-bob model API sini kichik, xavfsiz va tez quriladigan image ga joyladik. Image tayyor — endi uni qayerda ishga tushiramiz, nechta nusxada va yangi versiyani qanday chiqaramiz?

Bu uch savolning har biri alohida xato manbai. Replikalar kam bo'lsa, cho'qqi soatida kechikish sekundlarga chiqadi va so'rovlar timeout bilan tushadi. Ko'p bo'lsa, oyiga yuzlab dollar bo'sh turgan serverlarga ketadi. Yangi versiya birdaniga hamma foydalanuvchiga chiqarilsa, undagi yashirin xato bir necha daqiqada minglab odamga tegadi.

Ko'pchilik bu savollarga "his" bilan javob beradi: "4 ta replika yetadi", "serverless arzonroq", "canary xavfsizroq". Bu darsda har birini hisoblaymiz: replikalar sonini navbat nazariyasi va simulyatsiya bilan, avtomasshtablashni kun davomidagi yuklama bilan, deploy strategiyalarini yashirin xatoli versiya bilan, xarajatni esa yuklama darajasiga qarab.

Real vaziyat. Onlayn do'kon tavsiya modelining yangi versiyasini juma kuni kechqurun "blue-green" bilan chiqardi: trafik bir zumda 100% yangi versiyaga o'tdi. Versiyada bitta mahsulot toifasi uchun xato bor edi — so'rovlarning taxminan 1% i 500 qaytarardi. Umumiy xato grafigida bu ko'rinmadi, chunki odatiy xato ulushi ham 1% atrofida edi. Muammo 40 daqiqadan keyin mijozlar shikoyatidan bilindi. Agar versiya avval trafikning 5% iga chiqarilib, eski versiya bilan statistik taqqoslanganida, zarar bir necha barobar kichik bo'lardi — 3-misol aynan shuni raqamlarda ko'rsatadi.

Bu darsda deploy qarorlarini hisob bilan qabul qilamiz: nechta replika, qanday masshtablash, qanday chiqarish va qancha pul.

Bu darsda:

  • Deploy variantlari: VM, konteyner xizmati, Kubernetes, serverless, boshqariladigan ML platformalar
  • Onlayn, batch va stream bashorat
  • Navbat nazariyasi bilan quvvat rejalash: band-lik, Little qonuni, M/M/c
  • Avtomasshtablash va cold start
  • Deploy strategiyalari: recreate, rolling, blue-green, canary, shadow
  • Sog'liq tekshiruvlari va orqaga qaytish
  • Xarajat modeli: doimiy server va serverless
  • Amaliy: diskret hodisa simulyatsiyasi, avtomasshtablash, strategiyalar simulyatsiyasi, kesishish nuqtasi

ℹ Barcha misollar virtual vaqtda ishlaydi (haqiqiy soat va tarmoq yo'q) va urug' bilan deterministik. Bulut narxlari va limitlari faraziy — tartibni ko'rsatish uchun; haqiqiy qiymatlar uchun provayderning rasmiy narx sahifasiga qarang.


2. Nazariya — chuqur tushuntirish

2.1. Deploy variantlari

text
BOSHQARUV KO'P (siz javobgar)                     BOSHQARUV KAM (provayder)
<------------------------------------------------------------------------>
 VM              Kubernetes        Konteyner         Serverless     Boshqariladigan
 (o'zingiz       (klaster,         xizmati           funksiya       ML platforma
  o'rnatasiz)     orkestrator)     (image beriladi)  (kod beriladi)  (model beriladi)

MISOL NOMLAR (faqat tanish bo'lishi uchun, tavsiya emas):
  VM:                AWS EC2, Google Compute Engine, Azure VM
  Kubernetes:        EKS, GKE, AKS yoki o'z klasteringiz
  Konteyner xizmati: AWS ECS/Fargate, Google Cloud Run, Azure Container Apps
  Serverless:        AWS Lambda, Google Cloud Functions, Azure Functions
  ML platforma:      SageMaker, Vertex AI, Azure ML
Variant Qachon mos Kuchli tomoni Zaif tomoni
VM kichik jamoa, bitta xizmat, doimiy yuklama to'liq nazorat, sodda masshtablash, yangilash qo'lda
Konteyner xizmati ko'p API lar uchun sukut tanlov image beriladi, avtomasshtab klasterdan kam moslashuvchan
Kubernetes ko'p xizmat, katta jamoa, murakkab trafik kuchli, standart, ko'chma murakkab, alohida malaka kerak
Serverless kam yoki "tishli" trafik, kichik model bo'sh vaqt bepul, 0 ga masshtab cold start, xotira/vaqt limitlari, GPU odatda yo'q
ML platforma registr, monitoring, A/B tayyor kerak ML ga xos imkoniyatlar narx, provayderga bog'lanish

"Eng kuchli" emas, "eng sodda yetarli" variant — kichik jamoaga Kubernetes ko'pincha foydadan ko'ra ko'proq ish beradi; konteyner xizmati odatda yaxshi boshlang'ich nuqta.

2.2. Onlayn, batch va stream bashorat

text
ONLAYN (real vaqt, so'rov-javob)
  mijoz -> API -> model -> javob           kechikish: ms lar
  misol: firibgarlik tekshiruvi to'lov paytida, qidiruv tartiblash
  talab: past kechikish, yuqori mavjudlik, replikalar

BATCH (oldindan hisoblash)
  kunlik ish: barcha mijozlar -> model -> jadval (DB/kesh)
  ilova tayyor natijani O'QIYDI                kechikish: soatlar
  misol: kunlik ketish xavfi, haftalik tavsiyalar ro'yxati
  afzallik: arzon, sodda, qayta ishga tushirish oson
  kamchilik: yangi mijoz / yangi belgi uchun natija eski

STREAM (hodisa oqimi)
  hodisa (Kafka va h.k.) -> iste'molchi -> model -> natija oqimi
  kechikish: soniyalar
  misol: sensorlardan anomaliya, real vaqt belgilari yangilanishi

TANLOV SAVOLI: "Natija qachon kerak va kirish qachon ma'lum bo'ladi?"
  kirish oldindan ma'lum + natija kechiksa bo'ladi -> BATCH
  kirish so'rov paytida paydo bo'ladi -> ONLAYN
  hodisalar uzluksiz, javob tez, lekin so'rov-javob emas -> STREAM

Eng arzon so'rov — umuman bajarilmagan so'rov: agar natijani oldindan hisoblash mumkin bo'lsa, batch onlayn API dan ko'pincha o'nlab barobar arzon (4-misolda ham shunday chiqadi).

2.3. Navbat nazariyasi bilan quvvat rejalash

text
BELGILAR:
  lambda (lam) - kelish tezligi, so'rov/s
  mu           - bitta replika xizmat tezligi, so'rov/s (= 1 / xizmat vaqti)
  c            - replikalar (ishchilar) soni
  a = lam / mu - yuklama ("nechta replika band bo'ladi")
  rho = a / c  - BAND-LIK (utilization), 0..1

LITTLE QONUNI (har qanday barqaror tizim uchun):
  L = lam * W     tizimdagi o'rtacha so'rovlar = tezlik * o'rtacha vaqt

M/M/c (Puasson kelish, eksponensial xizmat, c server):
  P(kutish) = Erlang C(c, a)
  Wq = P(kutish) / (c * mu - lam)       navbatdagi o'rtacha kutish
  W  = Wq + 1/mu                        o'rtacha javob vaqti

ENG MUHIM XULOSA - CHIZIQSIZLIK:
  W ning maxraji (c*mu - lam) -> rho -> 1 da nolga intiladi
  rho = 0.5 -> kutish kichik
  rho = 0.9 -> kutish bir necha barobar
  rho -> 1  -> navbat CHEKSIZ o'sadi
text
QUVVAT REJALASH TARTIBI:
  1. o'lchash: cho'qqi lam, xizmat vaqti taqsimoti (o'rtacha EMAS, dumi bilan)
  2. SLA: masalan "p99 <= 450 ms"
  3. minimal c: rho < 1 dan boshlab, SLA bajarilguncha oshirish
     (formula o'rtacha uchun, persentil uchun - SIMULYATSIYA)
  4. zaxira: cho'qqi o'sishi, replika yiqilishi (N+1), deploy paytida
  5. tekshiruv: yuklama testi 27.8-bob

PASTKI CHEGARA: p99 >= xizmat vaqtining O'ZI p99.
  Replika qo'shish navbatni yo'qotadi, lekin modelni tezlashtirmaydi.

Band-likni 1 ga yaqinlashtirmang: kechikish chiziqli emas, 0.6-0.7 atrofi odatda cho'qqi va dum uchun oqilona zaxira.

2.4. Avtomasshtablash va cold start

text
REAKTIV AVTOMASSHTABLASH (masalan, Kubernetes HPA g'oyasi):
  har T soniyada: kerakli = ceil( joriy yuklama / (mu * maqsad_band) )
  kerakli > joriy  -> yangi replikalar SO'RALADI
  kerakli < joriy  -> "barqarorlik oynasi" kutiladi, keyin kamaytiriladi
  chegaralar: min_replika (ishonchlilik), max_replika (byudjet)

COLD START = yangi replika tayyor bo'lguncha vaqt:
  mashina/pod ajratish + image tortish + Python import + model yuklash
  + readiness tekshiruvi
  shu vaqt ichida yuklama ESKI replikalarga tushadi -> navbat

MUAMMOLAR:
  keskin sakrash (reklama, xabarnoma) -> cold start davomida navbat
  navbat o'sgani uchun autoscaler KO'PROQ so'raydi -> ortiqcha masshtab
  tez kamaytirish -> "tebranish" (flapping)

YECHIMLAR:
  kichik image va tez model yuklash 27.9-bob -> qisqa cold start
  pastroq maqsad band-lik (zaxira) yoki kattaroq min_replika
  jadval bo'yicha masshtab (ma'lum cho'qqilar oldidan)
  bashoratli masshtab (kechagi profil bo'yicha)

Cold start — avtomasshtablashning yashirin narxi: u qanchalik uzun bo'lsa, sakrashga javob shunchalik kech va ortiqcha replika shunchalik ko'p.

2.5. Deploy strategiyalari

text
RECREATE: hammasini to'xtat -> yangisini ishga tushir
  v1 v1 v1 | -- -- -- | v2 v2 v2        + sodda, ikki versiya birga yo'q
                ^ uzilish                - uzilish (downtime), qaytish ham uzilish

ROLLING: replikalarni birma-bir almashtirish
  v1 v1 v1 -> v2 v1 v1 -> v2 v2 v1 -> v2 v2 v2
                                        + uzilishsiz, qo'shimcha resurs kam
                                        - qaytish ham sekin, ikki versiya aralash

BLUE-GREEN: ikki to'liq muhit, trafik bir zumda almashadi
  ko'k (v1) <- 100%      yashil (v2) tayyor
  ko'k (v1)              yashil (v2) <- 100%
                                        + bir zumda qaytish (trafikni qaytarish)
                                        - 2x resurs, xato HAMMAGA tegadi

CANARY: kichik ulush -> tekshiruv -> kattaroq ulush
  v1 95% / v2 5%  -> (metrikalar yaxshi?) -> 25% -> 100%
                                        + zarar ulush bilan cheklangan
                                        - sekin, statistik tekshiruv kerak

SHADOW (mirror): v2 trafik NUSXASINI oladi, javobi tashlanadi
  mijoz -> v1 -> javob
        \-> v2 -> (faqat log va metrika)
                                        + foydalanuvchiga zarar YO'Q
                                        - 2x hisob, yon ta'sirli amallar
                                          (yozish, to'lov) bilan xavfli,
                                          biznes metrikasi o'lchanmaydi
Strategiya Uzilish Zarar kimga Qaytish tezligi Resurs
Recreate bor hammaga sekin (yana uzilish) 1x
Rolling yo'q o'sib boruvchi ulush sekin ~1x
Blue-green yo'q hammaga (qisqa) bir zumda 2x
Canary yo'q kichik ulush bir zumda ~1x
Shadow yo'q hech kimga kerak emas 2x hisob
text
CANARY NI TO'G'RI TEKSHIRISH:
  "xato grafigi yaxshi ko'rinadi" - YETARLI EMAS
  statistik test: yangi versiya xato ulushi vs eski (yoki tarixiy) ulush
    z = (x - n * p0) / sqrt(n * p0 * (1 - p0))
  MINIMAL SO'ROVLAR soni bo'lmaguncha qaror yo'q
  ko'p marta qarash -> yolg'on signal oshadi -> qat'iyroq chegara (z > 4)
  ML uchun: xato ulushidan tashqari BASHORAT TAQSIMOTI ham taqqoslanadi (27.12)

Canary ning kuchi — zararni ulush bilan cheklashda, lekin juda kichik ulush xatoni o'z bosqichida sezmaydi va yolg'on ishonch beradi.

2.6. Sog'liq tekshiruvlari va orqaga qaytish

yaml
# Kubernetes Deployment (qisqartirilgan) - rolling update va tekshiruvlar
apiVersion: apps/v1
kind: Deployment
metadata:
  name: churn-api
spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1            # bir vaqtda 1 ta qo'shimcha pod
      maxUnavailable: 0      # tayyor podlar soni kamaymaydi
  selector:
    matchLabels: {app: churn-api}
  template:
    metadata:
      labels: {app: churn-api}
    spec:
      containers:
        - name: api
          image: registry.misol.uz/ml/churn-api:1.4.2
          resources:
            requests: {cpu: "500m", memory: "512Mi"}
            limits: {memory: "1Gi"}
          readinessProbe:          # trafik berishga tayyormi (model yuklandimi)
            httpGet: {path: /ready, port: 8000}
            periodSeconds: 5
          livenessProbe:           # osilib qoldimi -> qayta ishga tushirish
            httpGet: {path: /health, port: 8000}
            periodSeconds: 10
          startupProbe:            # model yuklanishi uzoq bo'lsa
            httpGet: {path: /health, port: 8000}
            failureThreshold: 30
            periodSeconds: 2
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: churn-api
spec:
  scaleTargetRef: {apiVersion: apps/v1, kind: Deployment, name: churn-api}
  minReplicas: 2
  maxReplicas: 30
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: {type: Utilization, averageUtilization: 60}
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 600
text
READINESS vs LIVENESS:
  readiness: "trafik bera olamanmi?" - model yuklanmagan bo'lsa YO'Q
             -> pod trafikdan chiqariladi, lekin o'ldirilmaydi
  liveness:  "tirikmanmi?" - osilib qolgan bo'lsa -> qayta ishga tushirish
  XATO: liveness da DB/tashqi xizmatni tekshirish -> DB sekinlashsa,
        HAMMA podlar qayta ishga tushadi (o'z-o'ziga hujum)

ORQAGA QAYTISH (rollback) REJASI - DEPLOY DAN OLDIN:
  qaysi metrika, qanday chegara, kim qaror qiladi, necha daqiqada
  oldingi image tegi / model versiyasi darhol mavjud
  ma'lumotlar bazasi migratsiyasi orqaga mos

Readiness — model yuklanganini, liveness — jarayon tirikligini tekshiradi; orqaga qaytish rejasi deploy dan oldin yoziladi.

2.7. Xarajat modeli

text
DOIMIY SERVER (VM / konteyner, 24/7):
  oylik = instanslar * soatlik narx * 730
  instanslar = max(min_zaxira, ceil(CHO'QQI rps / bitta instans quvvati))
  -> bo'sh vaqt ham pullik; cho'qqiga to'laysiz

SERVERLESS:
  oylik = so'rovlar * (so'rov haqi + xotira_GB * davom_s * GB-s narxi)
  -> faqat ishlatilganga; o'rtachaga to'laysiz
  -> lekin: cold start, vaqt/xotira limitlari

KESISHISH NUQTASI: serverless(R) = server(R)
  kam yuklama   -> serverless arzon (server qat'iy minimal narxi)
  ko'p yuklama  -> server arzon (bitta so'rov narxi past)
  "tishli" trafik -> serverless foydasi oshadi

HISOBGA OLINMAYDIGAN (lekin muhim) XARAJATLAR:
  muhandis vaqti (Kubernetes ni qo'llab-quvvatlash)
  tarmoq trafigi (egress), log va monitoring saqlash
  GPU - soatlik narxi CPU dan ko'p barobar; band-lik past bo'lsa isrof

Narx — faraz emas, formula: yuklama, cho'qqi koeffitsiyenti va so'rov davomiyligi bilan hisoblang; natija bu uchta songa sezgir.

2.8. Tuzoqlar

Asosiy tuzoqlar: replikalar sonini o'rtacha yuklama bo'yicha tanlash; o'rtacha kechikishga qarab SLA ni baholash (p99 kerak); band-likni 0.9 ga yaqin ushlash; M/M/c formulasini og'ir dumli kechikishga ishonch bilan qo'llash; cold start ni hisobga olmaslik; liveness tekshiruviga tashqi bog'liqlikni qo'shish; canary ni "ko'z bilan" tekshirish (statistik test siz); juda kichik canary ulushi va qisqa bosqich; shadow ni yon ta'sirli amallar bilan ishlatish; orqaga qaytish rejasisiz deploy; narxni "serverless doim arzon" deb taxmin qilish; bulut narxlarini eski blog yozuvidan olish.


3. Tez ma'lumotnoma

python
import math


def erlang_c(c, a):
    """M/M/c: kelgan so'rov navbatda kutish ehtimoli (a = lam / mu)."""
    if a >= c:
        return 1.0
    yigindi = sum(a ** k / math.factorial(k) for k in range(c))
    oxirgi = a ** c / math.factorial(c) * c / (c - a)
    return oxirgi / (yigindi + oxirgi)


def ortacha_javob(lam, mu, c):
    return erlang_c(c, lam / mu) / (c * mu - lam) + 1 / mu


def canary_z(xatolar, n, p0):
    return (xatolar - n * p0) / math.sqrt(n * p0 * (1 - p0))
bash
kubectl apply -f deployment.yaml                 # e'lon qilingan holatni qo'llash
kubectl rollout status deployment/churn-api      # rolling update kuzatuvi
kubectl rollout undo deployment/churn-api        # oldingi versiyaga qaytish
kubectl get hpa churn-api                        # avtomasshtab holati
kubectl scale deployment/churn-api --replicas=8  # qo'lda masshtab

Tuzilma xulosasi

text
variant: konteyner xizmati - sukut; K8s - murakkablik oqlansa
bashorat turi: kirish oldindan ma'lum -> batch; aks holda onlayn
replikalar: SLA (p99) + simulyatsiya, band-lik 0.6-0.7, N+1
avtomasshtab: min/max, barqarorlik oynasi, qisqa cold start
deploy: canary + statistik test + tayyor rollback
narx: formula + faraziy narxlar -> rasmiy sahifa bilan tekshirish

4. Batafsil misollar

Misollar real numpy bilan (Python 3.14); vaqt — virtual. Trafik, xizmat vaqtlari va narxlar faraziy.

Misol 1 — Quvvat rejalash: M/M/c va diskret hodisa simulyatsiyasi

Trafik 40 so'rov/s, bitta so'rovga o'rtacha 80 ms (bitta replika soniyasiga 12.5 so'rov bajaradi). Replikalar soni M/M/c formulasi bilan hisoblanadi va diskret hodisa simulyatsiyasi bilan tekshiriladi: har so'rov kelish vaqtida eng erta bo'shagan replikaga boradi (uyum — heapq), javob vaqti = kutish + xizmat. Simulyatsiya persentillarni beradi — formula faqat o'rtachani. SLA — p99 <= 450 ms (faraziy).

python
"""Quvvat rejalash: M/M/c formulasi va diskret hodisa simulyatsiyasi noldan.

Virtual vaqt (soniya) - haqiqiy soat ishlatilmaydi. Trafik va xizmat vaqti
FARAZIY: 40 so'rov/s, bitta so'rovga o'rtacha 80 ms.
"""

import heapq
import math

import numpy as np

LAMBDA = 40.0          # so'rov/s (faraziy)
XIZMAT = 0.080         # o'rtacha xizmat vaqti, s (faraziy)
SLA_P99 = 0.450        # p99 kechikish chegarasi, s (faraziy)
N = 60_000             # simulyatsiya qilinadigan so'rovlar


def erlang_c(c, a):
    """Kelgan so'rov navbatda kutish ehtimoli (M/M/c)."""
    if a >= c:
        return 1.0
    yigindi = sum(a ** k / math.factorial(k) for k in range(c))
    oxirgi = a ** c / math.factorial(c) * c / (c - a)
    return oxirgi / (yigindi + oxirgi)


def nazariya(lam, xizmat, c):
    mu = 1 / xizmat
    a = lam / mu
    if a >= c:
        return a / c, 1.0, math.inf
    pw = erlang_c(c, a)
    wq = pw / (c * mu - lam)
    return a / c, pw, wq + xizmat


def simulyatsiya(lam, xizmatlar, c, rng):
    """FCFS, c ta server: har so'rov eng erta bo'shagan serverga boradi."""
    kelish = np.cumsum(rng.exponential(1 / lam, len(xizmatlar)))
    bosh = [0.0] * c                       # serverlar bo'shash vaqtlari (uyum)
    javob = np.empty(len(xizmatlar))
    for i, (t, s) in enumerate(zip(kelish.tolist(), xizmatlar.tolist())):
        erta = heapq.heappop(bosh)
        boshlash = t if t > erta else erta
        tugash = boshlash + s
        heapq.heappush(bosh, tugash)
        javob[i] = tugash - t
    return javob[N // 10:]                 # birinchi 10% - qizish davri


def pers(x):
    return np.percentile(x, [50, 95, 99]) * 1000


def main() -> None:
    rng = np.random.default_rng(0)
    xizmat_exp = rng.exponential(XIZMAT, N)

    print("=== 1. Replikalar soni: nazariya va simulyatsiya ===")
    print(f"  trafik {LAMBDA:.0f} so'rov/s, xizmat {XIZMAT * 1000:.0f} ms, "
          f"yuklama a = {LAMBDA * XIZMAT:.1f} (kamida 4 replika)")
    print(f"  {'c':>2} {'band':>5} {'P(kut)':>7} {'W naz':>7} {'W sim':>7} "
          f"{'p50':>6} {'p95':>6} {'p99':>7}  SLA")
    tanlangan = None
    for c in range(4, 9):
        band, pw, w = nazariya(LAMBDA, XIZMAT, c)
        javob = simulyatsiya(LAMBDA, xizmat_exp, c,
                             np.random.default_rng(100 + c))
        p50, p95, p99 = pers(javob)
        ok = p99 <= SLA_P99 * 1000
        if ok and tanlangan is None:
            tanlangan = c
        belgi = "ha" if ok else "yo'q"
        print(f"  {c:>2} {band:>5.2f} {pw:>7.3f} {w * 1000:>6.0f}ms "
              f"{javob.mean() * 1000:>5.0f}ms {p50:>5.0f} {p95:>6.0f} "
              f"{p99:>6.0f}  {belgi}")
    print(f"  SLA (p99 <= {SLA_P99 * 1000:.0f} ms) ni qondiradigan eng kam "
          f"replika: {tanlangan}")
    pastki = np.percentile(xizmat_exp, 99) * 1000
    print(f"  xizmat vaqtining O'ZI p99 = {pastki:.0f} ms: navbatsiz ham shu -")
    print(f"  SLA {pastki * 0.8:.0f} ms bo'lsa, hech qancha replika yordam "
          f"bermaydi (modelni tezlatish kerak)")

    print("\n=== 2. Band-lik oshsa kechikish chiziqli EMAS (c = 5) ===")
    print(f"  {'trafik':>7} {'band':>5} {'W naz, ms':>10} {'p99 sim, ms':>12}")
    wlar = []
    for lam in [20, 35, 45, 52, 58, 61]:
        band, _, w = nazariya(lam, XIZMAT, 5)
        wlar.append(w)
        javob = simulyatsiya(lam, xizmat_exp, 5, np.random.default_rng(lam))
        print(f"  {lam:>7} {band:>5.2f} {w * 1000:>10.0f} "
              f"{pers(javob)[2]:>12.0f}")
    print(f"  trafik 3 barobar (20 -> 61): o'rtacha kechikish "
          f"{wlar[-1] / wlar[0]:.1f} barobar")

    print("\n=== 3. Cho'qqi: trafik 1.5 barobar ===")
    cho = LAMBDA * 1.5
    kerak = next(c for c in range(1, 40)
                 if nazariya(cho, XIZMAT, c)[0] < 1
                 and pers(simulyatsiya(cho, xizmat_exp, c,
                                       np.random.default_rng(7)))[2]
                 <= SLA_P99 * 1000)
    print(f"  {cho:.0f} so'rov/s uchun SLA: {kerak} replika "
          f"(oddiy yuklamada {tanlangan})")
    band_cho = nazariya(cho, XIZMAT, tanlangan)[0]
    p99_cho = pers(simulyatsiya(cho, xizmat_exp, tanlangan,
                                np.random.default_rng(7)))[2]
    print(f"  {tanlangan} replika cho'qqida: band {band_cho:.2f}, "
          f"p99 {p99_cho:.0f} ms")
    print(f"  {kerak} replika oddiy vaqtda: band "
          f"{nazariya(LAMBDA, XIZMAT, kerak)[0]:.2f} - bu zaxira narxi")

    print("\n=== 4. Og'ir dumli xizmat vaqti (o'rtacha bir xil, 80 ms) ===")
    sigma = 1.2
    xizmat_ln = rng.lognormal(math.log(XIZMAT) - sigma ** 2 / 2, sigma, N)
    print(f"  lognormal o'rtacha {xizmat_ln.mean() * 1000:.1f} ms, "
          f"CV {xizmat_ln.std() / xizmat_ln.mean():.2f} "
          f"(eksponensialda CV = 1)")
    print(f"  {'c':>2} {'p99 exp':>8} {'p99 lognorm':>12}  SLA lognorm")
    for c in [tanlangan, tanlangan + 1, tanlangan + 2]:
        a = pers(simulyatsiya(LAMBDA, xizmat_exp, c,
                              np.random.default_rng(300 + c)))[2]
        b = pers(simulyatsiya(LAMBDA, xizmat_ln, c,
                              np.random.default_rng(300 + c)))[2]
        belgi = "ha" if b <= SLA_P99 * 1000 else "yo'q"
        print(f"  {c:>2} {a:>8.0f} {b:>12.0f}  {belgi}")
    print(f"  lognormal xizmatning O'ZI p99 = "
          f"{np.percentile(xizmat_ln, 99) * 1000:.0f} ms")
    print("  dum og'ir bo'lsa M/M/c formulasi p99 ni kam baholaydi -")
    print("  haqiqiy kechikish taqsimoti bilan simulyatsiya kerak")
    print("  ⭐ Band-lik 0.6-0.7 atrofida - cho'qqi va dum uchun zaxira")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Replikalar soni: nazariya va simulyatsiya ===
  trafik 40 so'rov/s, xizmat 80 ms, yuklama a = 3.2 (kamida 4 replika)
   c  band  P(kut)   W naz   W sim    p50    p95     p99  SLA
   4  0.80   0.596    140ms   137ms   105    370    542  yo'q
   5  0.64   0.289     93ms    92ms    68    262    390  ha
   6  0.53   0.127     84ms    84ms    60    246    371  ha
   7  0.46   0.051     81ms    81ms    56    242    367  ha
   8  0.40   0.018     80ms    80ms    56    241    366  ha
  SLA (p99 <= 450 ms) ni qondiradigan eng kam replika: 5
  xizmat vaqtining O'ZI p99 = 366 ms: navbatsiz ham shu -
  SLA 293 ms bo'lsa, hech qancha replika yordam bermaydi (modelni tezlatish kerak)

=== 2. Band-lik oshsa kechikish chiziqli EMAS (c = 5) ===
   trafik  band  W naz, ms  p99 sim, ms
       20  0.32         81          367
       35  0.56         87          384
       45  0.72        103          426
       52  0.83        139          568
       58  0.93        264         1189
       61  0.98        707         2811
  trafik 3 barobar (20 -> 61): o'rtacha kechikish 8.8 barobar

=== 3. Cho'qqi: trafik 1.5 barobar ===
  60 so'rov/s uchun SLA: 6 replika (oddiy yuklamada 5)
  5 replika cho'qqida: band 0.96, p99 1304 ms
  6 replika oddiy vaqtda: band 0.53 - bu zaxira narxi

=== 4. Og'ir dumli xizmat vaqti (o'rtacha bir xil, 80 ms) ===
  lognormal o'rtacha 80.3 ms, CV 1.84 (eksponensialda CV = 1)
   c  p99 exp  p99 lognorm  SLA lognorm
   5      397          677  yo'q
   6      370          645  yo'q
   7      367          642  yo'q
  lognormal xizmatning O'ZI p99 = 640 ms
  dum og'ir bo'lsa M/M/c formulasi p99 ni kam baholaydi -
  haqiqiy kechikish taqsimoti bilan simulyatsiya kerak
  ⭐ Band-lik 0.6-0.7 atrofida - cho'qqi va dum uchun zaxira

Natija tahlili.

  • 1-bo'lim — formula va simulyatsiya mos: o'rtacha javob vaqti formulada va simulyatsiyada deyarli bir xil (4 replikada 140 va 137 ms, 5 da 93 va 92 ms). Bu simulyatorimiz to'g'ri ishlashining tekshiruvi — endi unga formula bera olmaydigan narsa, persentillar uchun ishonish mumkin.
  • Minimal replika — 5: 4 replikada band-lik 0.80, kelgan so'rovning 60% i navbatda kutadi va p99 = 542 ms — SLA buzilgan. 5 replikada p99 = 390 ms. 6 dan 8 gacha p99 deyarli o'zgarmaydi (371, 367, 366) — chunki navbat allaqachon deyarli yo'q.
  • Pastki chegara: xizmat vaqtining o'zi p99 = 366 ms. Agar SLA 293 ms bo'lsa, hech qancha replika yordam bermaydi — modelni tezlashtirish (kichikroq model, kvantlash, kesh) kerak. Bu quvvat rejalashning eng ko'p unutiladigan xulosasi.
  • 2-bo'lim — chiziqsizlik: 5 replikada trafik 20 dan 61 ga (taxminan 3 barobar) oshganda o'rtacha kechikish 8.8 barobar, p99 esa 367 ms dan 2811 ms gacha oshdi. Band-lik 0.83 dan 0.93 ga o'tganda p99 ikki barobar bo'ldi — "yana ozgina trafik" oxirgi 10% da juda qimmat.
  • 3-bo'lim — cho'qqi: trafik 1.5 barobar (60 so'rov/s) bo'lsa, 5 replikada band-lik 0.96 va p99 1304 ms. Kerak — 6 replika. Lekin 6 replika oddiy vaqtda band-lik 0.53 — bu zaxiraning narxi; uni avtomasshtablash kamaytiradi (2-misol).
  • 4-bo'lim — og'ir dum: o'rtachasi bir xil (80 ms), lekin CV 1.84 bo'lgan lognormal xizmat vaqti bilan p99 640 ms dan yuqori — 7 replikada ham SLA bajarilmaydi. Haqiqiy model kechikishlari ko'pincha shunday (GC pauzasi, uzun kirishlar, kesh o'tkazib yuborish). Xulosa: formulani boshlang'ich taxmin uchun, simulyatsiyani haqiqiy kechikish taqsimoti bilan qaror uchun ishlating.

Misol 2 — Avtomasshtablash: kun davomida yuklama va cold start

Bir kunlik trafik (virtual daqiqalar): tunda 8 so'rov/s, 13:00 va 20:00 da cho'qqilar, 15:00 da 25 daqiqalik reklama sakrashi (3 barobar) — reja uni bilmaydi. Olti siyosat taqqoslanadi: ikki doimiy (odatiy cho'qqi va o'rtacha uchun) va to'rt reaktiv (cold start, maqsad band-lik va min replika farqlari bilan). Har daqiqa: quvvat, navbat (bajarilmay qolgan so'rovlar keyingi daqiqaga o'tadi), band-lik > 0.8 yoki navbat bor bo'lsa — "xavfli daqiqa". Xarajat — replika-soatlar (ishga tushayotgan replikalar ham pullik).

python
"""Avtomasshtablash simulyatsiyasi: kun davomida yuklama, cold start, xarajat.

Virtual vaqt - daqiqalar (0..1439). Trafik profili, replika quvvati va
cold start vaqtlari FARAZIY.
"""

import math
from dataclasses import dataclass

import numpy as np

MU = 12.5                  # bitta replika: so'rov/s (80 ms xizmat)
XAVFSIZ_BAND = 0.80        # shundan yuqori band-lik - SLA xavfi
DAQIQA = 1440


def trafik_profili(rng):
    """So'rov/s: tungi past, kunduzi ikki cho'qqi, 15:00 da keskin sakrash."""
    t = np.arange(DAQIQA)
    soat = t / 60
    asos = (8 + 30 * np.exp(-((soat - 13) / 2.5) ** 2)
            + 38 * np.exp(-((soat - 20) / 2.0) ** 2))
    sakrash = np.where((t >= 900) & (t < 925), 3.0, 1.0)   # reklama
    kutilgan = asos * sakrash
    return asos, rng.poisson(kutilgan * 60) / 60            # reja, haqiqiy


@dataclass(frozen=True)
class Siyosat:
    nom: str
    turi: str                  # "doimiy" yoki "reaktiv"
    doimiy: int = 0
    maqsad_band: float = 0.6
    cold_start: int = 4        # daqiqa: image tortish + model yuklash
    kamaytirish_kutish: int = 10
    min_r: int = 2
    max_r: int = 30


def simulyatsiya(trafik, s):
    tayyor = s.doimiy if s.turi == "doimiy" else s.min_r
    kutilmoqda = []            # (tayyor bo'ladigan daqiqa, soni)
    past_qator = 0
    navbat = 0.0               # bajarilmay qolgan so'rovlar
    replika_daq, buzilgan, kechikkan, max_navbat = 0, 0, 0.0, 0.0
    tarix = []
    for t in range(DAQIQA):
        # ishga tushayotganlar tayyor bo'ladi
        tayyor += sum(n for tt, n in kutilmoqda if tt <= t)
        kutilmoqda = [(tt, n) for tt, n in kutilmoqda if tt > t]
        quvvat = tayyor * MU * 60
        talab = trafik[t] * 60 + navbat
        bajarildi = min(talab, quvvat)
        navbat = talab - bajarildi
        band = trafik[t] * 60 / quvvat
        if band > XAVFSIZ_BAND or navbat > 0:
            buzilgan += 1
        kechikkan += navbat
        max_navbat = max(max_navbat, navbat)
        replika_daq += tayyor + sum(n for _, n in kutilmoqda)  # ular ham pullik
        tarix.append(tayyor)

        if s.turi == "reaktiv":     # har daqiqa oxirida qaror
            kerak = math.ceil((trafik[t] + navbat / 60) / (MU * s.maqsad_band))
            kerak = min(max(kerak, s.min_r), s.max_r)
            jami = tayyor + sum(n for _, n in kutilmoqda)
            if kerak > jami:
                kutilmoqda.append((t + 1 + s.cold_start, kerak - jami))
                past_qator = 0
            elif kerak < tayyor:
                past_qator += 1
                if past_qator >= s.kamaytirish_kutish:
                    tayyor = max(kerak, s.min_r)
                    past_qator = 0
            else:
                past_qator = 0
    return {"replika_soat": replika_daq / 60, "buzilgan": buzilgan,
            "kechikkan": kechikkan, "max_navbat": max_navbat,
            "max_r": max(tarix), "min_r": min(tarix)}


def main() -> None:
    rng = np.random.default_rng(42)
    reja, trafik = trafik_profili(rng)
    print("=== 1. Kunlik trafik (virtual vaqt, so'rov/s) ===")
    for soat in [3, 9, 13, 15, 17, 20, 23]:
        print(f"  {soat:02d}:00-{soat:02d}:59  o'rtacha "
              f"{trafik[soat * 60:(soat + 1) * 60].mean():>6.1f}")
    print(f"  kunlik o'rtacha {trafik.mean():.1f}, cho'qqi {trafik.max():.1f}, "
          f"cho'qqi/o'rtacha = {trafik.max() / trafik.mean():.1f}")

    # reja faqat ODATIY profilni biladi - reklama sakrashini emas
    cho = math.ceil(reja.max() / (MU * 0.6))
    ort = math.ceil(reja.mean() / (MU * 0.6))
    print(f"  reja: odatiy cho'qqi {reja.max():.1f} -> {cho} replika, "
          f"o'rtacha {reja.mean():.1f} -> {ort} replika")
    siyosatlar = [
        Siyosat("doimiy, cho'qqi uchun", "doimiy", doimiy=cho),
        Siyosat("doimiy, o'rtacha uchun", "doimiy", doimiy=ort),
        Siyosat("reaktiv, cold start 4", "reaktiv", cold_start=4),
        Siyosat("reaktiv, cold start 1", "reaktiv", cold_start=1),
        Siyosat("reaktiv cs4, maqsad 0.45", "reaktiv", cold_start=4,
                maqsad_band=0.45),
        Siyosat("reaktiv cs4, min 6", "reaktiv", cold_start=4, min_r=6),
    ]

    print("\n=== 2. Siyosatlar taqqoslash (1 kun) ===")
    print(f"  {'siyosat':<25} {'replika-soat':>12} {'xavfli daq':>10} "
          f"{'navbat':>10} {'replika':>8}")
    natijalar = {}
    for s in siyosatlar:
        n = simulyatsiya(trafik, s)
        natijalar[s.nom] = n
        print(f"  {s.nom:<25} {n['replika_soat']:>12.1f} {n['buzilgan']:>10} "
              f"{n['kechikkan']:>10.0f} {n['min_r']:>5}-{n['max_r']}")

    print("\n=== 3. Qaror: xavfli <= 10 daq, navbat <= 10000, eng arzon ===")
    mos = {k: v for k, v in natijalar.items()
           if v["buzilgan"] <= 10 and v["kechikkan"] <= 10_000}
    eng = min(mos, key=lambda k: mos[k]["replika_soat"])
    asos = natijalar[siyosatlar[0].nom]["replika_soat"]
    print(f"  talabga mos: {len(mos)} ta")
    for k in sorted(mos, key=lambda k: mos[k]["replika_soat"]):
        print(f"    {k:<25} {mos[k]['replika_soat']:>6.1f} replika-soat")
    print(f"  eng arzoni: {eng}; cho'qqi uchun doimiyga nisbatan tejash "
          f"{1 - mos[eng]['replika_soat'] / asos:.1%}")

    print("\n=== 4. Cold start ta'siri (reaktiv, maqsad 0.6) ===")
    for cs in [0, 1, 2, 4, 8]:
        s = Siyosat(f"cs {cs}", "reaktiv", cold_start=cs)
        n = simulyatsiya(trafik, s)
        print(f"  cold start {cs} daq: xavfli {n['buzilgan']:>3} daq, "
              f"navbat {n['kechikkan']:>6.0f} so'rov-daq, "
              f"max {n['max_r']} replika")
    print("  cold start = image hajmi + model yuklash: kichik image 27.9-bob")
    print("  avtomasshtablashni TEZROQ qiladi")
    print("  ⭐ Avtomasshtablash pulni tejaydi, lekin sakrashga kechikib javob beradi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Kunlik trafik (virtual vaqt, so'rov/s) ===
  03:00-03:59  o'rtacha    8.0
  09:00-09:59  o'rtacha   12.3
  13:00-13:59  o'rtacha   36.5
  15:00-15:59  o'rtacha   37.8
  17:00-17:59  o'rtacha   17.5
  20:00-20:59  o'rtacha   43.1
  23:00-23:59  o'rtacha   10.0
  kunlik o'rtacha 19.9, cho'qqi 73.0, cho'qqi/o'rtacha = 3.7
  reja: odatiy cho'qqi 46.0 -> 7 replika, o'rtacha 19.1 -> 3 replika

=== 2. Siyosatlar taqqoslash (1 kun) ===
  siyosat                   replika-soat xavfli daq     navbat  replika
  doimiy, cho'qqi uchun            168.0          3          0     7-7
  doimiy, o'rtacha uchun            72.0        451    5757801     3-3
  reaktiv, cold start 4             85.6          6      19431     2-24
  reaktiv, cold start 1             83.6          2       3720     2-15
  reaktiv cs4, maqsad 0.45         102.0          5       7564     2-20
  reaktiv cs4, min 6               146.8          5          0     6-10

=== 3. Qaror: xavfli <= 10 daq, navbat <= 10000, eng arzon ===
  talabga mos: 4 ta
    reaktiv, cold start 1       83.6 replika-soat
    reaktiv cs4, maqsad 0.45   102.0 replika-soat
    reaktiv cs4, min 6         146.8 replika-soat
    doimiy, cho'qqi uchun      168.0 replika-soat
  eng arzoni: reaktiv, cold start 1; cho'qqi uchun doimiyga nisbatan tejash 50.2%

=== 4. Cold start ta'siri (reaktiv, maqsad 0.6) ===
  cold start 0 daq: xavfli   1 daq, navbat   1267 so'rov-daq, max 13 replika
  cold start 1 daq: xavfli   2 daq, navbat   3720 so'rov-daq, max 15 replika
  cold start 2 daq: xavfli   3 daq, navbat   7554 so'rov-daq, max 19 replika
  cold start 4 daq: xavfli   6 daq, navbat  19431 so'rov-daq, max 24 replika
  cold start 8 daq: xavfli  10 daq, navbat  59788 so'rov-daq, max 30 replika
  cold start = image hajmi + model yuklash: kichik image 27.9-bob
  avtomasshtablashni TEZROQ qiladi
  ⭐ Avtomasshtablash pulni tejaydi, lekin sakrashga kechikib javob beradi

Natija tahlili.

  • 1-bo'lim: kunlik o'rtacha 19.9, cho'qqi 73.0 so'rov/s — nisbat 3.7. Reja faqat odatiy profilni ko'radi: cho'qqi 46.0 (7 replika), o'rtacha 19.1 (3 replika).
  • 2-bo'lim, doimiy siyosatlar: "cho'qqi uchun" 7 replika — 168 replika-soat, reklama sakrashida ham 3 xavfli daqiqa (sakrash rejadan tashqari), lekin navbat yo'q. "O'rtacha uchun" 3 replika — 72 replika-soat, lekin 451 xavfli daqiqa va ulkan navbat: kunduzi tizim yuklamani ko'tara olmaydi. O'rtacha yuklama bo'yicha rejalash — eng keng tarqalgan xato.
  • Reaktiv siyosatlar 84-147 replika-soat oralig'ida. Cold start 4 daqiqa bo'lsa, sakrashda 6 xavfli daqiqa va 19431 so'rov-daqiqa navbat, cold start 1 daqiqada — 2 va 3720. maqsad 0.45 (ko'proq zaxira) va min 6 navbatni kamaytiradi, lekin qimmatroq.
  • 3-bo'lim — qaror: talabga (xavfli <= 10 daqiqa, navbat <= 10000) to'rt siyosat mos keldi; eng arzoni — cold start 1 daqiqalik reaktiv: 83.6 replika-soat, cho'qqi uchun doimiydan 50.2% arzon. E'tibor bering: g'olib sozlama emas, muhandislik natijasi — qisqa cold start kichik image va tez model yuklash bilan olinadi 27.9-bob.
  • 4-bo'lim — kutilmagan tomoni: cold start oshgani sari nafaqat navbat (1267 dan 59788 gacha), balki maksimal replikalar ham oshdi (13 dan 30 gacha). Sabab: replikalar kutilayotganda navbat o'sadi, autoscaler navbatni ham hisobga olib yana so'raydi va sakrash o'tganda ortiqcha replikalar qoladi. Bu — ortiqcha masshtablash, uzun cold start ning ikkinchi narxi.

Misol 3 — Deploy strategiyalari: yashirin xato qancha zarar yetkazadi

Yangi versiyada yashirin bug bor: odatiy 1% xatoga qo'shimcha 1%. Trafik 600 so'rov/daqiqa. Monitoring yangi versiya so'rovlaridagi xatolarni tarixiy 1% bilan z-test orqali taqqoslaydi (z > 4, kamida 200 so'rov) va 5 daqiqa kechikish bilan ko'radi (metrika quvuri + baholash oralig'i). Aniqlangach orqaga qaytiladi (recreate — 2 daqiqa uzilish bilan, rolling — 6 daqiqa, qolganlari — bir zumda). Har strategiya 300 urug'da; "zarar" — bug tufayli xato olgan foydalanuvchilar (recreate da uzilish vaqtidagi hamma so'rovlar ham).

python
"""Deploy strategiyalari: yashirin xatoli versiya nechta foydalanuvchiga zarar
yetkazadi va qachon aniqlanadi. Virtual vaqt - daqiqalar; 300 urug'.

Faraziy: 600 so'rov/daq, eski versiya xato ulushi 1%, yangi versiyada
qo'shimcha 1% xato (yashirin bug), monitoring 5 daqiqa kechikadi.
"""

import math

import numpy as np

TRAFIK = 600            # so'rov/daqiqa
P0 = 0.01               # odatiy xato ulushi (tarixdan ma'lum)
UFQ = 180               # kuzatish ufqi, daqiqa
Z_CHEGARA = 4.0         # ogohlantirish chegarasi
MIN_SOROV = 200         # shundan kam so'rovda qaror qilinmaydi
KECHIKISH = 5           # monitoring kechikishi, daqiqa
BUG = 0.01              # yangi versiyadagi qo'shimcha xato ulushi


def ulush_jadvali(nom, t, canary=0.05):
    """Deploy boshlangandan t daqiqa o'tgach yangi versiyaga ketadigan ulush.
    Qaytaradi: (yangi ulush, foydalanuvchi ko'radimi, ishlamay qolish)."""
    if nom == "recreate":
        return (0.0, True, True) if t < 2 else (1.0, True, False)
    if nom == "rolling":                       # 10 replika, har 3 daqiqada 1
        return min(1.0, (t // 3 + 1) / 10), True, False
    if nom == "blue-green":
        return 1.0, True, False
    if nom == "canary":                        # ulush -> 25% -> 100%
        if t < 30:
            return canary, True, False
        return (0.25 if t < 60 else 1.0), True, False
    if nom == "shadow":                        # nusxa trafik, javob tashlanadi
        return 1.0, False, False
    raise ValueError(nom)


ORQAGA_QAYTISH = {"recreate": 2, "rolling": 6, "blue-green": 0,
                  "canary": 0, "shadow": 0}    # daqiqa (faraziy)


def yurish(nom, bug, rng, canary=0.05):
    """Bitta deploy: zarar ko'rgan foydalanuvchilar va aniqlash daqiqasi.
    Monitoring KECHIKISH daqiqa orqada: t da faqat t-KECHIKISH gacha
    bo'lgan ma'lumotni ko'radi (metrika quvuri + baholash oralig'i)."""
    jam_n, jam_x = [], []            # har daqiqa oxiridagi yig'indilar
    n_yangi = xato_yangi = 0
    zarar = 0
    aniqlandi = None
    for t in range(UFQ):
        ulush, korinadi, ishlamaydi = ulush_jadvali(nom, t, canary)
        if aniqlandi is not None:
            if t >= aniqlandi + ORQAGA_QAYTISH[nom]:
                break                           # eski versiyaga qaytildi
            if nom == "recreate":
                zarar += TRAFIK                 # qayta ishga tushirish: uzilish
                continue
        if ishlamaydi:
            zarar += TRAFIK
        else:
            n = rng.binomial(TRAFIK, ulush)
            asos_xato = rng.binomial(n, P0)
            bug_xato = rng.binomial(n, bug)
            if korinadi:
                zarar += bug_xato
            n_yangi += n
            xato_yangi += asos_xato + bug_xato
        jam_n.append(n_yangi)
        jam_x.append(xato_yangi)
        k = t - KECHIKISH                       # monitoring ko'rgan oxirgi daq
        if aniqlandi is None and k >= 0 and jam_n[k] >= MIN_SOROV:
            z = (jam_x[k] - jam_n[k] * P0) / math.sqrt(jam_n[k] * P0 * (1 - P0))
            if z > Z_CHEGARA:
                aniqlandi = t
    return zarar, aniqlandi


def jamlash(nom, bug, urug_soni=300, canary=0.05):
    zararlar, vaqtlar, topilmadi = [], [], 0
    for u in range(urug_soni):
        z, a = yurish(nom, bug, np.random.default_rng(u), canary)
        zararlar.append(z)
        if a is None:
            topilmadi += 1
        else:
            vaqtlar.append(a)
    zararlar = np.array(zararlar, dtype=float)
    return (zararlar.mean(), zararlar.std(ddof=1) / math.sqrt(urug_soni),
            float(np.median(vaqtlar)) if vaqtlar else math.nan,
            topilmadi / urug_soni)


def main() -> None:
    strategiyalar = ["recreate", "rolling", "blue-green", "canary", "shadow"]

    print("=== 1. Yangi versiyaga ketadigan ulush (birinchi 70 daqiqa) ===")
    print(f"  {'strategiya':<11}" + "".join(f"{t:>7}" for t in
                                              [0, 1, 5, 20, 29, 30, 60]))
    for s in strategiyalar:
        qator = ""
        for t in [0, 1, 5, 20, 29, 30, 60]:
            ulush, korinadi, ishlamaydi = ulush_jadvali(s, t)
            belgi = "o'chiq" if ishlamaydi else (f"{ulush:.2f}" if korinadi
                                              else "nusxa")
            qator += f"{belgi:>7}"
        print(f"  {s:<11}{qator}")

    print("\n=== 2. Yashirin bug (+1% xato): 300 urug' bo'yicha ===")
    print(f"  {'strategiya':<11} {'zarar (odam)':>13} {'SE':>5} "
          f"{'aniqlash, daq':>13} {'topilmadi':>9}")
    natija = {}
    for s in strategiyalar:
        o, se, med, top = jamlash(s, bug=BUG)
        natija[s] = (o, se)
        print(f"  {s:<11} {o:>13.1f} {se:>5.1f} {med:>13.0f} {top:>9.1%}")

    print("\n=== 3. Canary ulushi: tezlik va zarar murosasi ===")
    otdi_nom = "1-bosqichdan o'tdi"
    print(f"  {'ulush':>6} {'zarar':>7} {'SE':>5} {'aniqlash, daq':>13} "
          f"{otdi_nom:>18}")
    for c in [0.01, 0.02, 0.05, 0.10, 0.25]:
        o, se, med, _ = jamlash("canary", bug=BUG, canary=c)
        otdi = 0                       # 30 daqiqada aniqlanmadi -> 25% ga
        for u in range(300):
            a = yurish("canary", BUG, np.random.default_rng(u), c)[1]
            otdi += a is None or a >= 30
        print(f"  {c:>6.0%} {o:>7.1f} {se:>5.1f} {med:>13.0f} "
              f"{otdi / 300:>18.1%}")

    print("\n=== 4. Bug kattaligi: blue-green va canary 5% ===")
    print(f"  {'bug':>6} {'strategiya':<11} {'zarar':>8} "
          f"{'aniqlash, daq':>13} {'topilmadi':>9}")
    for b in [0.003, 0.01, 0.03]:
        for s in ["blue-green", "canary"]:
            o, se, med, top = jamlash(s, bug=b)
            print(f"  {b:>6.1%} {s:<11} {o:>8.1f} {med:>13.0f} {top:>9.1%}")

    print("\n=== 5. Bug YO'Q: yolg'on orqaga qaytish ===")
    for s in ["blue-green", "canary"]:
        _, _, _, top = jamlash(s, bug=0.0)
        print(f"  {s:<11} yolg'on signal ulushi {1 - top:.1%} (z > {Z_CHEGARA})")

    print("\n=== 6. Xulosa (juftlashgan emas, mustaqil urug'lar: SE bilan) ===")
    eng = min(natija, key=lambda k: natija[k][0])
    korinadigan = {k: v for k, v in natija.items() if k != "shadow"}
    eng_k = min(korinadigan, key=lambda k: korinadigan[k][0])
    print(f"  eng kam zarar: {eng} (foydalanuvchi javobni ko'rmaydi)")
    print(f"  foydalanuvchi trafigi bilan eng kam zarar: {eng_k}")
    bg, cn = natija["blue-green"], natija["canary"]
    farq = bg[0] - cn[0]
    se = math.sqrt(bg[1] ** 2 + cn[1] ** 2)
    print(f"  blue-green - canary: {farq:.1f} +- {se:.1f} -> "
          f"{'sezilarli' if abs(farq) > 2 * se else 'sezilarsiz'}")
    print("  ⭐ Canary - zararni ulush bilan cheklaydi, blue-green - tez qaytaradi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yangi versiyaga ketadigan ulush (birinchi 70 daqiqa) ===
  strategiya       0      1      5     20     29     30     60
  recreate    o'chiq o'chiq   1.00   1.00   1.00   1.00   1.00
  rolling       0.10   0.10   0.20   0.70   1.00   1.00   1.00
  blue-green    1.00   1.00   1.00   1.00   1.00   1.00   1.00
  canary        0.05   0.05   0.05   0.05   0.05   0.25   1.00
  shadow       nusxa  nusxa  nusxa  nusxa  nusxa  nusxa  nusxa

=== 2. Yashirin bug (+1% xato): 300 urug' bo'yicha ===
  strategiya   zarar (odam)    SE aniqlash, daq topilmadi
  recreate           1849.1   0.6             9      0.0%
  rolling              51.3   1.0            15      0.0%
  blue-green           49.1   0.6             7      0.0%
  canary               22.0   0.7            38      0.0%
  shadow                0.0   0.0             7      0.0%

=== 3. Canary ulushi: tezlik va zarar murosasi ===
   ulush   zarar    SE aniqlash, daq 1-bosqichdan o'tdi
      1%    25.7   0.7            43             100.0%
      2%    23.7   0.7            42              88.3%
      5%    22.0   0.7            38              73.0%
     10%    19.7   0.6            27              42.3%
     25%    23.8   0.5            14               2.0%

=== 4. Bug kattaligi: blue-green va canary 5% ===
     bug strategiya     zarar aniqlash, daq topilmadi
    0.3% blue-green      61.3            31      0.0%
    0.3% canary          58.1            81      0.0%
    1.0% blue-green      49.1             7      0.0%
    1.0% canary          22.0            38      0.0%
    3.0% blue-green     108.9             5      0.0%
    3.0% canary          12.7            12      0.0%

=== 5. Bug YO'Q: yolg'on orqaga qaytish ===
  blue-green  yolg'on signal ulushi 0.0% (z > 4.0)
  canary      yolg'on signal ulushi 0.7% (z > 4.0)

=== 6. Xulosa (juftlashgan emas, mustaqil urug'lar: SE bilan) ===
  eng kam zarar: shadow (foydalanuvchi javobni ko'rmaydi)
  foydalanuvchi trafigi bilan eng kam zarar: canary
  blue-green - canary: 27.2 +- 0.9 -> sezilarli
  ⭐ Canary - zararni ulush bilan cheklaydi, blue-green - tez qaytaradi

Natija tahlili.

  • 2-bo'lim — asosiy jadval: recreate eng yomon 1849.1-bob — zararning asosiy qismi bugdan emas, uzilishdan: 2 daqiqa deploy va qaytishdagi uzilish. Rolling 51.3-bob va blue-green 49.1-bob deyarli teng: blue-green xatoni tez aniqlaydi (mediana 7 daqiqa), lekin shu vaqt ichida trafikning hammasi yangi versiyada. Canary — 22.0, taxminan ikki barobar kam, garchi aniqlash ancha kech bo'lsa ham (mediana 38 daqiqa). Shadow — 0: foydalanuvchi yangi versiya javobini ko'rmaydi.
  • Nima uchun canary kech aniqlaydi, lekin kam zarar beradi? Xatoni statistik ajratish uchun yangi versiyada taxminan bir xil sondagi so'rov kerak — ulushdan qat'i nazar. Farq qiluvchi narsa — monitoring kechikishi (5 daqiqa) va shu vaqt ichida yangi versiyaga ketgan trafik: blue-green da 100%, canary da 5%.
  • 3-bo'lim — canary ulushi: 5% da 73.0% hollarda xato 30 daqiqalik birinchi bosqichda topilmadi va versiya 25% ga o'tdi; 1% da — 100% hollarda. Ya'ni kichik canary xavfsiz ko'rinadi, lekin aslida xatoni keyingi bosqichga "o'tkazib yuboradi". Zarar 10% ulushda eng kichik (19.7 +- 0.6), 1% va 25% da kattaroq — ikki tomondan murosa: juda kichik ulush — sezmaydi, juda katta — ko'p zarar.
  • 4-bo'lim — bug kattaligi: katta bug (+3%) da canary ning afzalligi eng katta (12.7 va 108.9) — tez aniqlanadi va faqat 5% ga tegadi. Kichik bug (+0.3%) da farq deyarli yo'q (58.1 va 61.3): bunday kichik farqni ajratish uchun ko'p so'rov kerak va canary uni asosan 100% bosqichda topadi (mediana 81 daqiqa). Kutilgandan farqli, lekin muhim natija: canary kichik xatolardan himoya qilmaydi — ular uchun uzunroq bosqich yoki shadow kerak.
  • 5-bo'lim — yolg'on signal: bug bo'lmasa, blue-green da 0.0%, canary da 0.7% urug'da yolg'on orqaga qaytish bo'ldi. Canary uzoqroq kuzatiladi va testni ko'proq marta tekshiradi — ko'p marta qarash yolg'on signalni oshiradi (2.5-bo'lim). Shuning uchun chegara z > 4 kabi qat'iy tanlanadi.
  • 6-bo'lim: blue-green va canary zarari farqi 27.2 +- 0.9 — sezilarli. Urug'lar strategiyalar orasida alohida, shuning uchun farqning SE si ikki SE ning kvadratik yig'indisidan olindi.

Misol 4 — Xarajat modeli: server, serverless va batch

Uch variantning oylik narxi so'rovlar soniga qarab hisoblanadi. Barcha narxlar faraziy: server — soatiga $0.10, 200 so'rov/s quvvat, kamida 2 instans; serverless — $0.20 / 1 mln so'rov va $0.0000167 / GB-soniya, 1 GB, 100 ms; batch — soatiga $0.40, soniyasiga 2000 bashorat. Kesishish nuqtasi ikkiga bo'lish usuli bilan topiladi va har faraz o'zgartirilib sezgirlik tekshiriladi.

python
"""Xarajat modeli: doimiy server vs serverless vs batch - kesishish nuqtasi.

DIQQAT: barcha narxlar FARAZIY (tartibni ko'rsatish uchun). Haqiqiy narxlar
provayder, mintaqa va vaqtga qarab farq qiladi - rasmiy narx sahifasiga
qarang.
"""

import math
from dataclasses import dataclass

OY_SOAT = 730
OY_SONIYA = OY_SOAT * 3600


@dataclass(frozen=True)
class Narxlar:                           # FARAZIY
    server_soat: float = 0.10            # $/soat, bitta instans
    server_quvvat: float = 200.0         # so'rov/s, maqsad band-lik bilan
    server_min: int = 2                  # ishonchlilik uchun kamida 2
    sl_million: float = 0.20             # $ / 1 mln so'rov
    sl_gb_s: float = 0.0000167           # $ / GB-soniya
    sl_xotira_gb: float = 1.0
    sl_davom_s: float = 0.100            # bitta so'rov hisob-kitob vaqti
    issiq_s: float = 300.0               # bo'sh instans shuncha "issiq" turadi
    batch_soat: float = 0.40             # $/soat, kattaroq batch mashina
    batch_tezlik: float = 2000.0         # bashorat/s


def server_narxi(oylik, n, cho_koef=3.0):
    ortacha = oylik / OY_SONIYA
    instans = max(n.server_min, math.ceil(ortacha * cho_koef / n.server_quvvat))
    return instans * n.server_soat * OY_SOAT, instans


def serverless_narxi(oylik, n):
    bitta = n.sl_million / 1e6 + n.sl_gb_s * n.sl_xotira_gb * n.sl_davom_s
    return oylik * bitta


def cold_start_ulushi(oylik, n):
    """Puasson oqim: keyingi so'rov issiq oynadan keyin kelsa - cold start."""
    ortacha = oylik / OY_SONIYA
    return math.exp(-ortacha * n.issiq_s)


def batch_narxi(oylik, n):
    """Agar bashoratlarni oldindan hisoblash MUMKIN bo'lsa (kunlik ish)."""
    soat = oylik / n.batch_tezlik / 3600
    return max(soat, 30 * 0.25) * n.batch_soat     # kuniga kamida 15 daq


def kesishish(n, **kw):
    """serverless = server bo'ladigan oylik so'rovlar (ikkiga bo'lish)."""
    past, yuqori = 1e3, 1e11
    for _ in range(200):
        orta = math.sqrt(past * yuqori)
        if serverless_narxi(orta, n) < server_narxi(orta, n, **kw)[0]:
            past = orta
        else:
            yuqori = orta
    return past if past < 1e10 else None


def main() -> None:
    n = Narxlar()
    print("=== 1. Bitta so'rov narxi (faraziy) ===")
    sl = serverless_narxi(1, n)
    print(f"  serverless: ${sl * 1e6:.2f} / 1 mln so'rov "
          f"(so'rov haqi ${n.sl_million:.2f} + hisob "
          f"${n.sl_gb_s * n.sl_xotira_gb * n.sl_davom_s * 1e6:.2f})")
    print(f"  server: ${n.server_soat:.2f}/soat, kamida {n.server_min} ta -> "
          f"${n.server_min * n.server_soat * OY_SOAT:.0f}/oy qat'iy")

    print("\n=== 2. Oylik yuklama bo'yicha ===")
    sarlavha = ["so'rov/oy", "o'rt rps"]
    print(f"  {sarlavha[0]:>9} {sarlavha[1]:>8} {'server $':>9} {'inst':>4} "
          f"{'serverless $':>12} {'batch $':>8} {'cold %':>7}  arzon (onlayn)")
    for oylik in [1e3, 1e4, 3e4, 1e5, 1e6, 1e7, 3e7, 1e8, 3e8, 1e9]:
        s, inst = server_narxi(oylik, n)
        l = serverless_narxi(oylik, n)
        b = batch_narxi(oylik, n)
        cs = cold_start_ulushi(oylik, n)
        arzon = "serverless" if l < s else "server"
        print(f"  {oylik:>9.0e} {oylik / OY_SONIYA:>8.2f} {s:>9.0f} {inst:>4} "
              f"{l:>12.1f} {b:>8.1f} {cs:>7.1%}  {arzon}")

    print("\n=== 3. Kesishish nuqtasi ===")
    k = kesishish(n)
    print(f"  {k:.3g} so'rov/oy ~ {k / OY_SONIYA:.1f} so'rov/s o'rtacha")
    print("  undan kam - serverless arzon, ko'p - doimiy server")

    print("\n=== 4. Sezgirlik: kesishish qaysi faraziga bog'liq ===")
    variantlar = {
        "asosiy": {},
        "hisob 50 ms (tezroq model)": {"sl_davom_s": 0.05},
        "hisob 300 ms (og'irroq model)": {"sl_davom_s": 0.30},
        "xotira 2 GB": {"sl_xotira_gb": 2.0},
        "server 2x qimmat": {"server_soat": 0.20},
        "server min 1 (zaxirasiz)": {"server_min": 1},
    }
    for nom, ozgarish in variantlar.items():
        nn = Narxlar(**ozgarish)
        k2 = kesishish(nn)
        if k2 is None:
            print(f"  {nom:<30} kesishmaydi: serverless doim arzon")
        else:
            print(f"  {nom:<30} {k2:>10.3g} so'rov/oy "
                  f"({k2 / OY_SONIYA:>5.1f} rps)")

    print("\n=== 5. Cho'qqi koeffitsiyenti (1e9 so'rov/oy) ===")
    print("  server cho'qqiga, serverless o'rtachaga to'laydi")
    l = serverless_narxi(1e9, n)
    for koef in [1.5, 3.0, 6.0, 12.0, 24.0]:
        s, inst = server_narxi(1e9, n, cho_koef=koef)
        arzon = "serverless" if l < s else "server"
        print(f"  cho'qqi/o'rtacha {koef:>4}: server ${s:>5.0f} ({inst:>2} inst), "
              f"serverless ${l:.0f} -> {arzon}")
    print("  trafik qanchalik 'tishli' bo'lsa, serverless shunchalik foydali")
    print("  ⭐ Hisoblang, taxmin qilmang: yuklama, cho'qqi, cold start birga")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Bitta so'rov narxi (faraziy) ===
  serverless: $1.87 / 1 mln so'rov (so'rov haqi $0.20 + hisob $1.67)
  server: $0.10/soat, kamida 2 ta -> $146/oy qat'iy

=== 2. Oylik yuklama bo'yicha ===
  so'rov/oy o'rt rps  server $ inst serverless $  batch $  cold %  arzon (onlayn)
      1e+03     0.00       146    2          0.0      3.0   89.2%  serverless
      1e+04     0.00       146    2          0.0      3.0   31.9%  serverless
      3e+04     0.01       146    2          0.1      3.0    3.3%  serverless
      1e+05     0.04       146    2          0.2      3.0    0.0%  serverless
      1e+06     0.38       146    2          1.9      3.0    0.0%  serverless
      1e+07     3.81       146    2         18.7      3.0    0.0%  serverless
      3e+07    11.42       146    2         56.1      3.0    0.0%  serverless
      1e+08    38.05       146    2        187.0      5.6    0.0%  server
      3e+08   114.16       146    2        561.0     16.7    0.0%  server
      1e+09   380.52       438    6       1870.0     55.6    0.0%  server

=== 3. Kesishish nuqtasi ===
  7.81e+07 so'rov/oy ~ 29.7 so'rov/s o'rtacha
  undan kam - serverless arzon, ko'p - doimiy server

=== 4. Sezgirlik: kesishish qaysi faraziga bog'liq ===
  asosiy                           7.81e+07 so'rov/oy ( 29.7 rps)
  hisob 50 ms (tezroq model)       1.41e+08 so'rov/oy ( 53.7 rps)
  hisob 300 ms (og'irroq model)     2.8e+07 so'rov/oy ( 10.7 rps)
  xotira 2 GB                      4.12e+07 so'rov/oy ( 15.7 rps)
  server 2x qimmat                 1.56e+08 so'rov/oy ( 59.4 rps)
  server min 1 (zaxirasiz)          3.9e+07 so'rov/oy ( 14.9 rps)

=== 5. Cho'qqi koeffitsiyenti (1e9 so'rov/oy) ===
  server cho'qqiga, serverless o'rtachaga to'laydi
  cho'qqi/o'rtacha  1.5: server $  219 ( 3 inst), serverless $1870 -> server
  cho'qqi/o'rtacha  3.0: server $  438 ( 6 inst), serverless $1870 -> server
  cho'qqi/o'rtacha  6.0: server $  876 (12 inst), serverless $1870 -> server
  cho'qqi/o'rtacha 12.0: server $ 1679 (23 inst), serverless $1870 -> server
  cho'qqi/o'rtacha 24.0: server $ 3358 (46 inst), serverless $1870 -> serverless
  trafik qanchalik 'tishli' bo'lsa, serverless shunchalik foydali
  ⭐ Hisoblang, taxmin qilmang: yuklama, cho'qqi, cold start birga

Natija tahlili.

  • 1-bo'lim: serverless da bitta mln so'rov $1.87, shundan $1.67 — hisob vaqti (xotira x davomiylik). Ya'ni serverless narxini asosan model tezligi belgilaydi. Server esa oyiga $146 dan boshlanadi — ishonchlilik uchun kamida ikki instans, so'rov bo'lmasa ham.
  • 2-bo'lim: oyiga 3e+07 so'rovgacha serverless arzon (oyiga $56.1 va $146), 1e+08 dan boshlab — server. Yuklama 1e+09 da server $438, serverless $1870 — to'rt barobardan ortiq farq.
  • Cold start: oyiga 1e+03 so'rovda 89.2% so'rov cold start ga tushadi, 1e+04 da 31.9%. Kam trafikli serverless arzon, lekin foydalanuvchining katta qismi "sovuq" javob oladi. Yuqori yuklamada bizning soddalashtirilgan modelimiz 0% ko'rsatadi, lekin amalda masshtab ko'tarilishida ham cold start bo'ladi.
  • Batch ustuni — hamma yuklamada eng arzon ($3.0-55.6). Agar natijani oldindan hisoblash mumkin bo'lsa (2.2-bo'lim), bu variant onlayn savolini umuman olib tashlaydi.
  • 3-4-bo'limlar — kesishish: 7.81e+07 so'rov/oy, ya'ni o'rtacha 29.7 so'rov/s. Lekin bu raqam farazlarga juda sezgir: model 300 ms ishlasa — 10.7 rps, 50 ms bo'lsa — 53.7 rps; server ikki barobar qimmat bo'lsa — 59.4 rps; zaxirasiz bitta server — 14.9 rps. Ya'ni "serverless arzonmi" savoliga javob uch-to'rt marta siljiydi.
  • 5-bo'lim — cho'qqi koeffitsiyenti: server cho'qqiga moslab olinadi, serverless o'rtachaga to'laydi. Oyiga 1e+09 so'rovda cho'qqi/o'rtacha 12 gacha server arzon, 24 da esa serverless ($3358 va $1870). Doimiy server o'rniga 2-misoldagi avtomasshtablash ishlatilsa, server narxi cho'qqiga emas, haqiqiy yuklamaga yaqinlashadi.

Xulosa: bu misoldagi aniq dollar raqamlari faraziy — muhimi formula. Haqiqiy qaror uchun o'z provayderingizning rasmiy narxlarini, o'lchangan so'rov davomiyligini va trafik profilini shu formulaga qo'ying.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Replikalar o'rtacha yuklama bo'yicha" Cho'qqi va SLA (p99) bo'yicha, zaxira bilan
"Band-lik 90% — samarali" Kechikish chiziqsiz o'sadi; 0.6-0.7 oqilona
"Ko'proq replika — har doim tezroq" Navbatni yo'qotadi, xizmat vaqtini emas
"M/M/c formulasi p99 ni beradi" O'rtachani beradi; dum uchun simulyatsiya
"Avtomasshtablash sakrashni hal qiladi" Cold start davomida navbat o'sadi
"Blue-green eng xavfsiz" Tez qaytadi, lekin xato hammaga tegadi
"Canary har qanday xatoni ushlaydi" Kichik xato uchun ko'p so'rov kerak
"Canary ni grafikka qarab tekshirish yetarli" Statistik test va minimal so'rovlar soni
"Serverless doim arzon" Yuklama, davomiylik va cho'qqiga bog'liq
"Kubernetes — professional tanlov" Murakkablik oqlanmasa, ortiqcha yuk

6. Keng tarqalgan xatolar va yechimlari

1. O'rtacha bo'yicha rejalash

python
replikalar = math.ceil(ortacha_rps / mu)                      # ⚠️
replikalar = eng_kam_c(cho_qqi_rps, xizmat_namunalari, sla)   # ✅ simulyatsiya

2. O'rtacha kechikish bilan SLA

python
assert np.mean(kechikishlar) < 0.3                            # ⚠️
assert np.percentile(kechikishlar, 99) < 0.45                 # ✅

3. Liveness da tashqi bog'liqlik

yaml
livenessProbe:
  httpGet: {path: /health?db=1, port: 8000}   # ⚠️ DB sekin -> hamma pod qayta
readinessProbe:
  httpGet: {path: /ready, port: 8000}         # ✅ bog'liqliklar - readiness da

4. Canary ni ko'z bilan tekshirish

python
if yangi_xato_ulushi < 0.02:                                  # ⚠️ "yaxshi ko'rinadi"
    oshir()
if n >= MIN_SOROV and canary_z(x, n, p0) <= 4:                # ✅ test + minimal n
    oshir()

5. Juda kichik va qisqa canary

text
canary 1%, 10 daqiqa -> "hammasi yaxshi" -> 100%        # ⚠️ statistik kuch yo'q
kerakli so'rovlar sonini oldindan hisoblang;
ulush va bosqich uzunligini shunga qarab tanlang          # ✅

6. Cold start ni e'tiborsiz qoldirish

yaml
minReplicas: 1          # ⚠️ sakrashda 1 replika + uzun cold start
minReplicas: 3          # ✅ + kichik image, jadval bo'yicha oldindan masshtab

7. Rollback rejasisiz deploy

text
"xato chiqsa ko'ramiz"                                      # ⚠️
metrika + chegara + mas'ul + oldingi teg tayyor + mashq     # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 11-qism (o'tilgan): gipoteza testlari — canary tekshiruvidagi z-test va ko'p marta qarash muammosi
  • 27.5-dars (o'tilgan): model registri — rollback uchun oldingi versiya darhol mavjud
  • 27.8-dars (o'tilgan): yuklama testi — xizmat vaqti taqsimotini o'lchash, quvvat rejalashning kirishi
  • 27.9-dars (o'tilgan): kichik image — qisqa cold start
  • 27.11-dars: monitoring — canary va avtomasshtablash qaror qiladigan metrikalar qanday yig'iladi
  • 27.13-dars: A/B test — canary ning "sifat" versiyasi: xatolar emas, biznes metrikasi taqqoslanadi

8. Eng yaxshi amaliyotlar

  1. Eng sodda yetarli variant: odatda boshqariladigan konteyner xizmati.

  2. Natijani oldindan hisoblash mumkinmi — avval batch ni ko'rib chiqing.

  3. Replikalar — cho'qqi va p99 SLA bo'yicha, simulyatsiya bilan.

  4. Band-lik 0.6-0.7, N+1 zaxira.

  5. Avtomasshtab: min/max, barqarorlik oynasi, qisqa cold start.

  6. Canary: statistik test, minimal so'rovlar soni, bosqichlar.

  7. Readiness va liveness alohida; liveness da tashqi bog'liqlik yo'q.

  8. Rollback rejasi deploy dan oldin, oldingi versiya tayyor.

  9. Narxni formula bilan hisoblang; narxlarni rasmiy sahifadan oling.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

text
1.  Band-lik (rho) qanday hisoblanadi?
2.  Little qonuni nima deydi?
3.  rho -> 1 da kechikish qanday o'zgaradi?
4.  M/M/c formulasi p99 ni beradimi?
5.  p99 ning pastki chegarasi nima?
6.  Cold start nimalardan iborat?
7.  Blue-green ning asosiy afzalligi va xavfi?
8.  Canary nima uchun kichik xatoni kech topadi?
9.  Shadow ning cheklovlari?
10. Readiness va liveness farqi?
11. Qachon batch bashorat afzal?
12. Serverless narxini asosan nima belgilaydi?
Javoblar
  1. rho = lam / (c * mu)
  2. L = lam * W
  3. Chiziqsiz, cheksizgacha o'sadi
  4. Yo'q — o'rtachani; persentil uchun simulyatsiya
  5. Xizmat vaqtining o'zi p99
  6. Resurs ajratish, image tortish, import, model yuklash, readiness
  7. Bir zumda qaytish; xato hammaga tegadi
  8. Ajratish uchun kerakli so'rovlar soni ulushga bog'liq emas
  9. 2x hisob, yon ta'sirli amallar, biznes metrikasi yo'q
  10. Readiness — trafikka tayyorlik, liveness — tiriklik
  11. Kirish oldindan ma'lum va natija kechiksa bo'ladi
  12. Hisob vaqti (xotira x davomiylik) va so'rovlar soni

Vazifa 2: Xatolarni tuzating

text
1. "Kuniga o'rtacha 20 rps, bitta replika 12.5 rps -> 2 replika yetadi."
2. "p50 = 90 ms, demak SLA (p99 <= 300 ms) bajariladi."
3. livenessProbe: /health?db=1&redis=1
4. "Canary 1% ni 10 daqiqa kuzatdik, xato grafigi tekis - 100% ga chiqaramiz."
5. "Serverless doim arzonroq, chunki bo'sh vaqt bepul."
Javoblar
  1. Cho'qqi (masalan, 3.7x) va band-lik 0.6-0.7 bo'yicha: ceil(20 * 3.7 / (12.5 * 0.6)) = 10 atrofida, keyin simulyatsiya bilan tekshirish (yoki avtomasshtab).
  2. p50 dan p99 haqida xulosa chiqmaydi — p99 ni o'lchang yoki simulyatsiya qiling; og'ir dumda p99 p50 dan ko'p barobar katta.
  3. Liveness faqat jarayonni tekshiradi (/health); DB va Redis — readiness da.
  4. 10 daqiqada 1% dan taxminan 60 so'rov — statistik kuch yo'q. Kerakli n ni hisoblang, z-testni ishlating, ulush/bosqichni kattalashtiring.
  5. Kesishish nuqtasini hisoblang: yuqori va tekis yuklamada doimiy server arzonroq.

Vazifa 3: Quvvat rejalash

1-misolni o'z xizmatingiz uchun moslang: (1) 27.8-darsdagi yuklama testidan olingan (yoki faraziy) 1000 ta kechikish namunasini xizmat vaqti sifatida qayta namunalang (rng.choice); (2) cho'qqi trafik uchun p99 SLA ni qondiradigan eng kam replikani toping; (3) bitta replika yiqilganda (N+1) SLA saqlanadimi?

Vazifa 4: Jadval bo'yicha masshtab

2-misolga yettinchi siyosat qo'shing: kechagi profil bo'yicha har soat boshida min_r ni oldindan o'rnatish (kechagi o'sha soat trafiki / (mu * 0.6)) + reaktiv. Reklama sakrashi bu siyosatda qanday natija beradi? Replika-soat va xavfli daqiqalarni taqqoslang.

Vazifa 5: Canary ni ketma-ket test bilan

3-misoldagi z-testni ikki tomonlama taqqoslashga almashtiring: yangi versiya xatolari tarixiy P0 bilan emas, bir vaqtdagi eski versiya xatolari bilan taqqoslansin (ikki ulush z-testi). Bug yo'q holatda yolg'on signal ulushini va +1% bugda zararni oldingi usul bilan taqqoslang. Qachon bir vaqtdagi taqqoslash muhimroq (kunlik mavsumiylik haqida o'ylang)?

Vazifa 6: Xarajat

4-misolga "avtomasshtablanuvchi server" variantini qo'shing: instanslar soni har soatda trafikka qarab (2-misoldagi kunlik profil bilan) o'zgaradi, minimal 2. Kesishish nuqtasi qanday siljiydi? Natijani jadval bilan ko'rsating.

Vazifa 7: O'ylash

Kichik startap: bitta tabular model (10 ms), trafik kuniga 20 000 so'rov, lekin ertalab 9:00 da 10 daqiqa ichida kunlik trafikning 30% i keladi (xabarnoma yuborilgandan keyin). Jamoada DevOps muhandisi yo'q. CTO Kubernetes klasterini taklif qilmoqda. Nima tavsiya qilasiz?

Javob

Qisqa javob: Kubernetes emas. Trafik kichik va bitta sakrash oldindan ma'lum — boshqariladigan konteyner xizmati yoki serverless, sakrash uchun esa jadval bo'yicha oldindan masshtab.

1. Yuklamani hisoblash

  • kuniga 20 000 so'rov — o'rtacha 0.23 so'rov/s
  • 9:00 dagi sakrash: 6 000 so'rov / 600 soniya = 10 so'rov/s
  • 10 ms model bilan bitta replika ~100 so'rov/s — sakrash ham bitta-ikkita replikaga sig'adi

2. Variantlar

Variant Mos keladimi Izoh
Kubernetes yo'q klaster narxi va qo'llab-quvvatlash yuki foydadan ko'p
Konteyner xizmati, min 1-2 ha sodda; 27.9 dagi image to'g'ridan-to'g'ri
Serverless ha, ehtiyot bilan juda kam trafik -> ko'p cold start (4-misol)
Batch balki agar tavsiya xabarnomadan OLDIN hisoblansa - eng arzon

3. Sakrash uchun

  • xabarnoma jadvali ma'lum — 8:55 da replikalarni oldindan ko'tarish (jadval bo'yicha masshtab)
  • yoki xabarnomani 10 daqiqaga emas, 30 daqiqaga yoyish (mahsulot qarori!)
  • serverless tanlansa — "issiq ushlab turish" (provisioned/min instances) faqat shu oyna uchun

4. Eng yaxshi savol

Xabarnomadagi tavsiya oldindan hisoblanishi mumkinmi? Agar ha — kechasi batch ish (2.2-bo'lim), ertalab API faqat tayyor natijani o'qiydi. Onlayn model umuman kerak bo'lmasligi mumkin.

Xulosa: infratuzilma murakkabligi yuklama va jamoaga mos bo'lishi kerak. Avval hisoblang (0.23 va 10 so'rov/s), keyin eng sodda yetarli variantni tanlang; Kubernetes ga trafik va jamoa o'sganda qaytish mumkin — konteyner image bir xil qoladi.

Nimani mustahkamlaydi: 2.2, 2.3, 2.5, 2.7-bo'limlar.


Xulosa

Bu darsda image ni qayerda, nechta nusxada va qanday chiqarishni hisob bilan hal qildik.

Eng muhim uch fikr:

  1. Quvvat — cho'qqi va p99 bo'yicha, simulyatsiya bilan. 1-misolda 40 so'rov/s uchun p99 SLA ni 5 replika qondirdi, lekin 1.5 barobar cho'qqi uchun 6 kerak bo'ldi; kechikish band-lik bilan chiziqsiz o'sdi va xizmat vaqtining o'zi p99 ning pastki chegarasi bo'lib chiqdi. Og'ir dumli kechikishda M/M/c formulasi yetarli emas. 2-misolda o'rtacha yuklama bo'yicha rejalash 451 xavfli daqiqa berdi, qisqa cold start li avtomasshtablash esa cho'qqi uchun doimiy serverlardan 50.2% arzon bo'ldi.

  2. Deploy strategiyasi — zararni cheklash vositasi. 3-misolda +1% yashirin bugda canary zarari blue-green nikidan taxminan ikki barobar kam bo'ldi, recreate esa uzilish tufayli eng yomoni. Lekin canary kichik xatolarni o'z bosqichida sezmaydi: 5% ulushda 73.0% hollarda xato keyingi bosqichga o'tdi, +0.3% bugda esa canary deyarli foyda bermadi. Statistik test, minimal so'rovlar soni va tayyor rollback — majburiy.

  3. Narx — formula, faraz emas. 4-misolda (faraziy narxlar bilan) kesishish nuqtasi o'rtacha 29.7 so'rov/s atrofida chiqdi, lekin model davomiyligi, server narxi va cho'qqi koeffitsiyentiga qarab bir necha barobar siljidi. Natijani oldindan hisoblash mumkin bo'lsa, batch hammasidan arzon.

Keyingi darsda Monitoring: ishlab chiqarishdagi model va tizimni qanday kuzatish — kechikish va xatolar, kirish ma'lumotlari va bashorat taqsimoti, belgilar kechikishi, ogohlantirish qoidalari va xato byudjeti.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
27.10-dars: Bulut va deploy strategiyalari — IlmHamroh