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

Observability — Senior chuqurlik

Bu — 12-mavzuning 2-qatlami. Core darslikni o‘qib bo‘lgan deb hisoblanadi. Bu yerda eng chuqur narsalar: OTel Collector/pipeline, context propagation, sampling (head vs tail), kardinallik, SLO/error budget/burn-rate, exemplars va continuous profiling — junior’dan seniorgacha.

Daraja: SeniorMavzular: collector · tail sampling · burn-rate · exemplarsOld shart: 12-mavzu (Core)

Bu qatlamda nima bor

Core darslik asoslarni berdi. Bu Deep qatlam senior darajadagi chuqur mexanikani ochadi: OpenTelemetry Collector pipeline, context propagation ichki mexanikasi, head vs tail sampling, kardinallik va metrika dizayni, SLO/error budget/burn-rate alerting, exemplars bilan uch ustunni bog‘lash, log’ni masshtabda va continuous profiling. Oxirida — yig‘ma pipeline va senior cheklist.

01
Deep · Collector

OTel Collector va pipeline

receivers · processors · exporters
🚇

Core’da ilova to‘g‘ridan-to‘g‘ri backend’ga yubordi. Senior arxitekturada orada OpenTelemetry Collector turadi — u ilovani backend’dan ajratib, markaziy pipeline beradi.

Collector nima uchun

Ilova OTLP orqali hammasini (trace, metrika, log) Collectorga yuboradi. Collector esa: batch qiladi, filtr/transform qiladi, sampling qiladi (keyingi bo‘limlar) va kerakli backend’larga yo‘naltiradi. Ilova qaysi backend borligini bilmaydi — faqat Collector’ni biladi:

Ilova (OTel) Collectorreceive→process→export Tempo (trace) Prometheus Loki (log)
Collector: ilovani backend’dan ajratadi, markaziy pipeline beradi
# otel-collector.yaml — receivers -> processors -> exporters
receivers:
  otlp:                                     # ilovadan OTLP qabul qiladi (gRPC/HTTP)
    protocols: { grpc: {}, http: {} }
processors:
  batch: {}                                 # to'plamlab yuboradi (samaradorlik)
  memory_limiter: {}                        # collector'ni OOM'dan himoya qiladi
exporters:
  otlp/tempo:  { endpoint: "tempo:4317" }   # trace -> Tempo
  prometheus:  { endpoint: "0.0.0.0:8889" } # metrika -> Prometheus scrape
  loki:        { endpoint: "http://loki:3100/loki/api/v1/push" }  # log -> Loki
service:
  pipelines:
    traces:  { receivers: [otlp], processors: [batch], exporters: [otlp/tempo] }
    metrics: { receivers: [otlp], processors: [batch], exporters: [prometheus] }
    logs:    { receivers: [otlp], processors: [batch], exporters: [loki] }
Topologiya — agent + gateway

Odatda ikki qatlam: har node’da agent collector (yengil, lokal yig‘adi) va markaziy gateway collector (og‘ir ish — tail sampling, agregatsiya). Bu masshtab va tail sampling (3-bo‘lim) uchun zarur.

02
Deep · Context

Context propagation ichki mexanikasi

traceparent · propagator · baggage
🔗

Distributed tracing sehrining asosi — context propagation: trace ID va span kontekstining bir xizmatdan boshqasiga qanday o‘tishi.

W3C Trace Context

Standart — traceparent header. U trace ID, ota-span ID va flag’larni olib yuradi. Har xizmat kelgan traceparentni o‘qib, o‘z span’ini uning bolasi qilib qo‘shadi:

// W3C traceparent header — trace kontekstini SERVISLAR BO'YLAB uzatadi:
// traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
//              |  |________________________________|  |______________| |
//           version        trace-id (32 hex)          span-id (16 hex) flags (sampled=1)

Propagator: inject va extract

Chiquvchi so‘rovga kontekst inject qilinadi (header’ga yoziladi), kiruvchida extract qilinadi (o‘qiladi). Bu HTTP’da avtomatik. Lekin broker (Kafka/RabbitMQ — 3-mavzu) orqali o‘tganda qo‘lda uzatish kerak — aks holda trace uziladi:

// Broker bo'ylab trace: kontekstni MESSAGE HEADER'iga inject qilamiz (3-mavzu)
const headers: Record<string, string> = {};
propagation.inject(context.active(), headers);          // traceparent -> headers
await producer.send({ topic: "orders", messages: [{ value, headers }] });

// consumer tomonda: header'dan extract qilib, trace'ni DAVOM ettiramiz
const ctx = propagation.extract(context.active(), msg.headers);
tracer.startActiveSpan("process-order", { }, ctx, (span) => { /* ... */ });
Baggage

traceparentdan tashqari baggage ham bor — ixtiyoriy kalit-qiymatlarni (masalan, tenant_id, user_tier) butun so‘rov bo‘ylab tarqatish. Bu barcha span/logga umumiy kontekst qo‘shadi. Ehtiyot: baggage har hop’da uzatiladi, ko‘p qo‘ymang.

03
Deep · Sampling

Head vs tail sampling

tail sampling
🎣

Masshtabda har so‘rovni trace qilib bo‘lmaydi (narx, hajm). Shuning uchun sampling — qaysi trace’larni saqlashni tanlash. Ikki asosiy yondashuv bor.

Head sampling — boshda qaror

Trace boshlanganda (root’da) qaror qilinadi: masalan, "har 100 tadan 1 tasini saqla". Oddiy va arzon. Lekin muammo: qaror boshda qilingani uchun — nodir xato yoki sekin trace ham 99% ehtimol bilan tashlanadi (aynan kerak bo‘lgani!).

Tail sampling — oxirda qaror (aqlliroq)

Qaror trace tugagach, collector’da qilinadi — endi trace’ning natijasini bilamiz. Demak: barcha xatoli va sekin trace’larni saqlaymiz, qolganidan ozini:

# TAIL SAMPLING (collector'da) — trace TUGAGACH qaror qilinadi
processors:
  tail_sampling:
    policies:
      - name: keep-errors                    # BARCHA xatoli trace'larni saqla
        type: status_code
        status_code: { status_codes: [ERROR] }
      - name: keep-slow                       # BARCHA sekin trace'larni saqla
        type: latency
        latency: { threshold_ms: 500 }
      - name: sample-rest                     # qolganidan faqat 5%
        type: probabilistic
        probabilistic: { sampling_percentage: 5 }
Head: boshda 1% tanlab (ko‘r) xato tashlanishi mumkin ✕ Tail: oxirda aqlli xato+sekin doim saqlanadi ✓
Tail sampling: qimmatli (xato/sekin) trace’lar hech qachon yo‘qolmaydi
Tail sampling narxi

Tail sampling collector’da butun trace’ni buferlashni talab qiladi — demak bitta trace’ning barcha span’lari bir collector’ga tushishi kerak (trace ID bo‘yicha load balancing). Bu murakkabroq va ko‘proq resurs, lekin natija ancha qimmatli. Boshlash uchun head sampling, o‘sganda tail.

04
Deep · Metrics

Kardinallik va metrika dizayni

cardinality · histogram
💥

Metrikani o‘ldiradigan bir narsa bor — kardinallik portlashi. Senior buni oldindan oldini oladi.

Muammo

Prometheus’da har bir noyob label kombinatsiyasi = alohida vaqt qatori (time series). Agar label’ga user_id (million foydalanuvchi) yoki xom URL (/orders/123, /orders/124...) qo‘ysang — millionlab qator paydo bo‘ladi, Prometheus xotirasi tugaydi va yiqiladi.

Metrika dizayn qoidalari

  • Label qiymatlari chegaralangan bo‘lsin: method (5 ta), status (~10 ta), route (o‘nlab) — mumkin. user_id, order_id, iphech qachon.
  • Route’ni normallashtir: /orders/:id (shablon), /orders/123 emas.
  • Yuqori kardinalli ma’lumot — metrikaga emas, log yoki tracega.
Metrika turlari

Counter — faqat o‘sadi (so‘rov soni, xatolar). Gauge — ko‘tarilib-tushadi (joriy ulanishlar, xotira). Histogram — taqsimot (kechikish bucket’lari — p50/p99 shundan). Summary — mijozda hisoblangan kvantillar. Kechikish uchun odatda histogram (server tomonda agregatlanadi, exemplar qo‘llab-quvvatlaydi).

05
Deep · SLO

Error budget va burn-rate alerting

error budget · burn rate
🔥

Core’da SLO’ni tanishtirdik. Senior darajada u error budget va burn-rate alerting bilan to‘liq tizimga aylanadi — bu alert fatigue’ni ham hal qiladi.

Error budget

Agar SLO = 99.9% bo‘lsa, error budget = 0.1% — ya’ni so‘rovlarning 0.1%i "buzilishga ruxsat etilgan". Bu — muhandislik uchun "byudjet": undan tez sarflasang muammo, sekin sarflasang — hammasi joyida.

Burn rate — budjet qanchalik tez yonyapti

Bitta oddiy "xato > X" alert yomon: ozgina sakrash ham chalintiradi (alert fatigue), yoki sekin oqib turgan muammoni o‘tkazib yuboradi. Multi-window multi-burn-rate yechadi: tez yonish → darhol page; sekin yonish → ticket:

# MULTI-BURN-RATE alert — budjetni TEZ yoqsa page, SEKIN yoqsa ticket
# SLO = 99.9%  ->  error budget = 0.1%
groups:
- name: slo
  rules:
  - alert: ErrorBudgetFastBurn          # 1 soatda budjetning katta qismi yonyapti
    expr: |
      error_ratio_1h > 14.4 * 0.001
      and error_ratio_5m > 14.4 * 0.001
    for: 2m
    labels: { severity: page }          # DARHOL odamni chaqir
  - alert: ErrorBudgetSlowBurn          # 6 soatda sekin yonish
    expr: error_ratio_6h > 6 * 0.001
    for: 15m
    labels: { severity: ticket }        # shoshilinch emas, ticket
Tez yonish → PAGE (hozir) Sekin yonish → TICKET Byudjet ichida → jim
Burn-rate: faqat haqiqiy, byudjetga tahdid soladigan holatda alert
Nega bu kuchli

Bu Google SRE yondashuvi: alert’lar foydalanuvchi ta’siriga mutanosib bo‘ladi. Kichik, o‘tkinchi sakrashlar chalintirmaydi; haqiqiy, byudjetni yeydigan muammo esa darajasiga qarab (page yoki ticket) xabar beradi. Error budget yana muhandislik qaroriga ham asos: byudjet tugasa — yangi feature emas, barqarorlikka e’tibor.

06
Deep · Exemplars

Metrika ↔ trace ↔ log bog‘lash

exemplars
🎯

Uch ustunni haqiqatan bog‘lash — senior belgisi. Exemplar aynan buni qiladi: metrikadagi bir nuqtadan to‘g‘ridan-to‘g‘ri o‘sha trace’ga sakrash.

Exemplar nima

Histogram bucket’iga namuna trace ID biriktiriladi. Grafana’da kechikish grafigida bir cho‘qqini ko‘rsang — o‘sha nuqtadagi exemplarni bosib, aynan o‘sha sekin so‘rovning trace’iga o‘tasan:

# Prometheus histogram + EXEMPLAR (bucket'ga namuna trace ID biriktiriladi)
http_request_duration_seconds_bucket{le="0.5"} 4283 # {trace_id="4bf92f35..."} 0.48 1620000000
#                                                     |___________________________|
#                                              exemplar: aynan shu sekin so'rovning trace'i
Metrika(p99 cho‘qqi) exemplar Trace(sekin bosqich) trace_id Log(aniq xato)
Exemplar: metrika → trace → log — bir bosishda to‘liq zanjir
Yopilgan halqa

Bu — observability’ning yakuniy maqsadi: metrika muammo borligini, trace qayerdaligini, log nima ekanligini — va exemplar hamda umumiy trace_id ularni bir zanjirga bog‘laydi. Muammoni daqiqalarda emas, sekundlarda topasan.

07
Deep · Scale

Log masshtabda va profiling

continuous profiling
🗂️

Katta tizimda loglar ham, "to‘rtinchi ustun" — continuous profiling ham alohida strategiya talab qiladi.

Log masshtabda

  • Log sampling: yuqori hajmli, takroriy loglarni tanlab saqlash (masalan, muvaffaqiyatli so‘rovlardan ozini, barcha xatolarni).
  • Indekslangan maydonlar vs to‘liq matn: faqat kerakli maydonlarni (trace_id, userId, status) indeksla — hammasini emas (Loki bu falsafada: yorliqlar bo‘yicha, matn bo‘yicha emas).
  • Retention qatlamlari: so‘nggi loglar tez (issiq), eskilari arzon arxivda (sovuq).
  • Har logda trace_id — trace bilan bog‘lash uchun (6-bo‘lim zanjiri).

Continuous profiling — to‘rtinchi ustun

Metrika/trace "qaysi xizmat/endpoint sekin"ini aytadi. Lekin "kod ichida qaysi funksiya CPU yeyapti?" — buni continuous profiling beradi: productionda doimiy, past overhead bilan CPU/xotira profillari (funksiya/qator darajasida).

Vositalar

pprof (Go/Node), eBPF asosidagi profillashtiruvchilar, Pyroscope / Parca / Grafana. Ular "flame graph" beradi — qaysi kod yo‘li vaqt/xotira yeyayotganini vizual ko‘rsatadi. Trace so‘rovni servislar aro, profiling esa kod ichida kuzatadi — ikkalasi to‘ldiradi.

08
Deep · Arxitektura

Yig‘ma pipeline va senior cheklist

To‘liq observability pipeline — yig‘ma ko‘rinish

QatlamVazifaBo‘lim
Ilova (OTel SDK)Trace/metrika/log generatsiya + context propagation2
Agent → Gateway CollectorYig‘ish, batch, tail sampling, yo‘naltirish1, 3
Prometheus / Tempo / LokiMetrika / trace / log backend1
Grafana (exemplars)Yagona ko‘rinish, uch ustunni bog‘lash6
SLO + burn-rate alertFoydalanuvchiga mutanosib ogohlantirish5
Continuous profilingKod darajasidagi sabab7

Senior tayyorlik cheklisti

Savol / amaliyotBo‘lim
OTel Collector pipeline (agent+gateway) quraman; ilovani backend’dan ajrataman1
Context propagation (traceparent) va broker bo‘ylab trace’ni uzataman2
Tail sampling bilan xato/sekin trace’larni kafolatli saqlayman3
Kardinallikni boshqaraman; metrika/histogram to‘g‘ri dizayn qilaman4
SLO/error budget/multi-burn-rate alert quraman (alert fatigue’siz)5
Exemplar va trace_id bilan uch ustunni bir zanjirga bog‘layman6
Log’ni masshtabda boshqaraman; continuous profiling bilan kod sababini topaman7

Bu 12-mavzuning Deep/Senior qatlami edi — Core bilan birga, Observability endi to‘liq.

Keyingi mavzu: “13-mavzu: Distributed Transactions” — taqsimlangan tizimda tranzaksiya muammosi va Saga naqshi (1 va 10-mavzularga ulanadi). Core’dan boshlaymiz.