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.
OTel Collector va pipeline
receivers · processors · exportersCore’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:
# 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] }
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.
Context propagation ichki mexanikasi
traceparent · propagator · baggageDistributed 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) => { /* ... */ });
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.
Head vs tail sampling
tail samplingMasshtabda 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 }
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.
Kardinallik va metrika dizayni
cardinality · histogramMetrikani o‘ldiradigan bir narsa bor — kardinallik portlashi. Senior buni oldindan oldini oladi.
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,ip— hech qachon. - Route’ni normallashtir:
/orders/:id(shablon),/orders/123emas. - Yuqori kardinalli ma’lumot — metrikaga emas, log yoki tracega.
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).
Error budget va burn-rate alerting
error budget · burn rateCore’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
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.
Metrika ↔ trace ↔ log bog‘lash
exemplarsUch 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
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.
Log masshtabda va profiling
continuous profilingKatta 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).
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.
Yig‘ma pipeline va senior cheklist
To‘liq observability pipeline — yig‘ma ko‘rinish
| Qatlam | Vazifa | Bo‘lim |
|---|---|---|
| Ilova (OTel SDK) | Trace/metrika/log generatsiya + context propagation | 2 |
| Agent → Gateway Collector | Yig‘ish, batch, tail sampling, yo‘naltirish | 1, 3 |
| Prometheus / Tempo / Loki | Metrika / trace / log backend | 1 |
| Grafana (exemplars) | Yagona ko‘rinish, uch ustunni bog‘lash | 6 |
| SLO + burn-rate alert | Foydalanuvchiga mutanosib ogohlantirish | 5 |
| Continuous profiling | Kod darajasidagi sabab | 7 |
Senior tayyorlik cheklisti
| Savol / amaliyot | Bo‘lim |
|---|---|
| OTel Collector pipeline (agent+gateway) quraman; ilovani backend’dan ajrataman | 1 |
| Context propagation (traceparent) va broker bo‘ylab trace’ni uzataman | 2 |
| Tail sampling bilan xato/sekin trace’larni kafolatli saqlayman | 3 |
| Kardinallikni boshqaraman; metrika/histogram to‘g‘ri dizayn qilaman | 4 |
| SLO/error budget/multi-burn-rate alert quraman (alert fatigue’siz) | 5 |
| Exemplar va trace_id bilan uch ustunni bir zanjirga bog‘layman | 6 |
| Log’ni masshtabda boshqaraman; continuous profiling bilan kod sababini topaman | 7 |
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.