Observability: sistemi görə bilmək
Observability: sistemi görə bilmək
Ch07-də SLO-lar yazdıq, ch11-də isə failure-lara qarşı pattern-lər qurduq. Hər ikisi bir fərziyyəyə söykənir: sistemin içində nə baş verdiyini görə bilirik. Gecə saat üçdə checkout yavaşlayanda on-call mühəndisin ilk sualı "nə xarabdır?" olur və bu suala cavab tapmaq çox vaxt problemi düzəltməkdən daha uzun çəkir. MTTR-in ən böyük hissəsi diaqnozdur.
Bu fəsil observability-ni alət seçimi kimi yox, architectural qərar kimi izah edir: hansı siqnalları toplamaq, nəyi ölçmək, nəyə görə alert vermək və niyə bunu sonradan "əlavə etmək" çətindir.
Monitoring və observability
Monitoring əvvəlcədən bildiyimiz problemləri izləyir: disk dolubmu, error rate həddi keçibmi, service cavab verirmi? Dashboard və alert-lər qabaqcadan yazılmış suallara cavab verir.
Observability isə sistemin quality attribute-udur (ch02-dəki cədvəldə var): xaricdən topladığımız siqnallara baxaraq əvvəlcədən təxmin etmədiyimiz suallara nə qədər tez cavab verə bilirik? "Niyə yalnız Android 14 istifadəçiləri, yalnız bir region-da, yalnız endirim kodu ilə ödəniş edəndə timeout alır?" Bu sual üçün heç kim əvvəlcədən dashboard qurmayıb.
Monolith-də bir process və bir log faylı var. Distributed sistemdə bir istifadəçi request-i on service-dən, iki queue-dan və üç database-dən keçir. Ch11-də gördüyümüz kimi, ən pis failure-lar yavaşlıq və partial failure-dır. Onlar heç bir komponentin öz dashboard-unda qırmızı görünmür; problem komponentlərin arasında olur.
Üç siqnal: log, metric, trace
Observability üç növ telemetry üzərində qurulur və hər birinin öz qiyməti var.
Log-lar ayrı-ayrı event-lərin qeydidir. Ən zəngin kontekst onlardadır, amma ən baha siqnal da onlardır: həcm traffic ilə birlikdə xətti artır. Sərbəst mətnli log-lar yalnız insan oxuyanda faydalıdır. Structured logging isə hər event-i sahələri olan obyekt kimi yazır (user_id, order_id, status, duration_ms). Belə log-larda axtarış etmək, filter-ləmək və aqreqasiya aparmaq mümkün olur. Xərci azaltmaq üçün uğurlu request-lərin log-larına sampling tətbiq olunur, xətalar isə həmişə tam yazılır.
Metric-lər zaman üzrə aqreqasiya olunmuş rəqəmlərdir: request sayı, error rate, latency histogram-ı. Onlar ucuzdur, tez sorğulanır və alert üçün idealdır. Zəif tərəfləri isə detalı itirmələridir: metric "error rate 3%-dir" deyir, amma hansı request-lərin niyə uğursuz olduğunu demir.
Metric-lərin gizli tələsi cardinality-dir. Hər unikal label kombinasiyası ayrıca time series yaradır. endpoint və status_code label-ləri bir neçə yüz series verir. Ona user_id əlavə etsəniz, milyonlarla series alırsınız və metric sistemi ya çox bahalaşır, ya da yıxılır. Qayda belədir: sərhədsiz dəyərlər (user, request, session ID-ləri) metric-ə yox, log-a və trace-ə aiddir.
Trace-lər bir request-in sistem boyunca keçdiyi yolu göstərir: hansı service-lər çağırıldı, hər biri nə qədər vaxt apardı, harada gözləmə yarandı. Distributed sistemdə "vaxt harada itdi?" sualına yalnız onlar birbaşa cavab verir.
Siqnal seçimi alətdən yox, verməli olduğunuz suallardan başlayır:
| Sual | Əsas siqnal | Niyə |
|---|---|---|
| Nə qədər istifadəçi təsirləndi? | Metric / SLI | Aqreqasiya olunmuş, ucuz, tarixçəsi uzun |
| SLO-nu pozuruqmu, budget nə sürətlə yanır? | Metric (burn rate) | Alert üçün stabil və sürətli |
| Checkout niyə yavaşdır? | Trace | Vaxtın hansı hop-da itdiyini göstərir |
| Bu konkret request-ə nə oldu? | Log + correlation ID | Tək event-in tam konteksti |
| Problem yalnız bir qrup istifadəçidədirmi? | Structured log / trace atributları | Yüksək cardinality-li sahələrlə filter |
| Deploy-dan sonra nə dəyişdi? | Metric (versiyaya görə) + trace | Əvvəl/sonra müqayisəsi |
| Bu node resursdan boğulurmu? | Metric (USE) | Saturation resurs səviyyəsində görünür |
Hər siqnalın öz işi var, onları bir-birinə bağlayan isə ortaq identifikatorlardır.
Nəyi ölçmək: golden signals, RED və USE
Hər şeyi ölçmək siqnalı səs-küydə itirir. Google SRE kitabındakı golden signals başlanğıc üçün yaxşı çərçivədir:
- Latency — request-lər nə qədər vaxt aparır (uğurlu və uğursuzlar ayrıca, çünki sürətli 500 cavabı ortanı aldadıcı şəkildə yaxşılaşdırır).
- Traffic — sistemə nə qədər yük gəlir (QPS, message sayı).
- Errors — uğursuz request-lərin nisbəti.
- Saturation — resurs nə qədər doludur (CPU, memory, connection pool, queue uzunluğu).
RED (Rate, Errors, Duration) request emal edən service-lər üçündür və birbaşa istifadəçi təcrübəsini əks etdirir. USE (Utilization, Saturation, Errors) isə resurslar üçündür: disk, CPU, connection pool. RED "istifadəçi nə hiss edir?", USE isə "hansı resurs darboğazdır?" sualına cavab verir.
Latency heç vaxt orta ilə ölçülməməlidir. Orta latency 80 ms olan service-də request-lərin 1%-i 3 saniyə çəkə bilər və on backend çağırışı edən səhifənin istifadəçiləri bu yavaş "tail"-ə tez-tez düşür. Percentile-lərə (p50, p95, p99) baxın və onları histogram-dan hesablayın: instance-ların öz p99-larının ortası riyazi cəhətdən mənasızdır.
Distributed tracing və correlation ID
Trace bir request-in tam yoludur. O, span-lardan ibarətdir: hər span bir iş vahididir (HTTP çağırışı, database sorğusu, queue-dan oxuma), başlanğıc və bitiş vaxtı, atributları və valideyn span-ı var. Span-lar birlikdə ağac əmələ gətirir və vaxtın harada itdiyini bir baxışda göstərir.
Bunun işləməsi üçün context propagation lazımdır: hər service gələn request-dən trace ID-ni oxumalı və etdiyi hər çağırışa ötürməlidir. HTTP və gRPC-də bu header-lərlə edilir (W3C Trace Context standartı). Eyni ID log-lara da yazılır və beləcə correlation ID üç siqnalı birləşdirir: trace-də yavaş span-ı tapır, həmin ID ilə log-larda xəta mesajını görürsünüz.
Bu sahədə de-fakto standart OpenTelemetry-dir: vendor-dan asılı olmayan API, SDK və telemetry protokolu. Onu seçmək backend-i sonradan dəyişmək imkanını saxlayır. Ch04-dəki dillə desək, bu, observability üçün seam-dir.
Hər request-i trace etmək bahadır, ona görə sampling tətbiq olunur. Head sampling qərarı request-in əvvəlində verir (məsələn, 1%): sadə və ucuzdur, amma nadir xətaları çox vaxt qaçırır. Tail sampling qərarı request bitəndən sonra verir: xətalı və yavaş trace-ləri saxlayır, normal olanların az hissəsini götürür. Daha dəyərlidir, amma bütün span-ları qərar verilənə qədər buffer-də saxlamaq üçün ayrıca infrastruktur tələb edir.
SLO əsaslı alerting
Klassik alert-lər səbəbə görə qurulur: "CPU 90%-i keçdi", "pod restart oldu". Onların çoxu istifadəçiyə təsir olmayanda belə gecə adamı oyadır. Nəticə alert fatigue-dur: komanda alert-lərə məhəl qoymamağı öyrənir və real incident səs-küydə itir.
Daha yaxşı yanaşma simptoma görə alert verməkdir: istifadəçi təcrübəsi pisləşirmi? Ch07-dəki SLO-lar bunun üçün hazır dildir. Sual "error rate həddi keçdimi?" yox, "error budget nə sürətlə yanır?" olur. Bu sürət burn rate adlanır: burn rate 1 o deməkdir ki, budget düz pəncərənin sonunda tükənəcək.
SLO 99.9%, pəncərə 30 gündür, deməli error budget 0.1%-dir. 30 gün 720 saatdır, yəni budget bərabər xərclənəndə saatda onun 1/720 hissəsi (≈0.139%) yanır. Son 1 saatda budget-in 2%-i yanıbsa, burn rate = 0.02 / (1/720) = 14.4 olur. Bu, error rate-in 14.4 × 0.1% = 1.44% olması deməkdir. Bu sürətlə bütün aylıq budget 720 / 14.4 = 50 saatda, yəni iki gündən bir az artıq müddətdə tükənəcək. Bu, gecə adamı oyatmağa dəyər.
Tək pəncərə ya gec reaksiya verir, ya da qısa dalğalanmalarda yalançı alert yaradır. Ona görə multi-window alert-lər istifadə olunur: məsələn, 1 saatlıq və 5 dəqiqəlik pəncərələrin ikisində də burn rate 14.4-dən yüksəkdirsə, page göndərilir. Qısa pəncərə problemin hələ davam etdiyini təsdiqləyir. Daha yavaş yanma (məsələn, 6 saatda budget-in 5%-i, burn rate 6) isə page yox, iş saatlarında baxılacaq ticket yaradır.
Əsas qayda: hər alert actionable olmalıdır. Alert gələndə on-call mühəndis konkret nəsə etməlidir. "Sadəcə məlumat üçün" alert dashboard-a aiddir, telefona yox.
Dashboard-lar və runbook-lar
Ch07-də gördük ki, availability-ni artırmağın ən ucuz yolu çox vaxt MTTR-i kiçiltməkdir. MTTR isə aşkarlama, diaqnoz və bərpa mərhələlərindən ibarətdir. Burn rate alert-i aşkarlamanı sürətləndirir, dashboard və runbook-lar isə diaqnozu.
Yaxşı incident dashboard-u bir suala üç dəqiqədə cavab verməyə kömək edir: problem haradadır? Yuxarıda SLI-lar və burn rate, altında service-in RED metric-ləri, daha aşağıda isə dependency-lər və resurslar (USE). Üzərində son deploy-lar və config dəyişiklikləri qeyd olunur, çünki incident-lərin böyük hissəsi dəyişiklikdən sonra başlayır.
Runbook hər alert-ə bağlı qısa sənəddir: bu alert nə deməkdir, ilk hansı qrafikə baxmalı, tipik səbəblər nədir və hansı təhlükəsiz addımlar var (rollback, feature flag-i söndürmək, traffic-i başqa region-a keçirmək). Runbook-suz alert mühəndisdən gecə saat üçdə sistemi sıfırdan öyrənməyi tələb edir.
Observability architectural qərar kimi
Observability-ni sonradan "əlavə etmək" çətindir, çünki o, hər komponentdən keçən cross-cutting concern-dir. Correlation ID-nin işləməsi üçün o, istisnasız hər hop-dan keçməlidir: bir köhnə service header-i ötürmürsə, trace orada qırılır. Asinxron sərhədlər daha çətindir: message broker-ə yazılan event-in metadata-sında trace context olmalıdır, əks halda consumer-in işi heç bir request-ə bağlanmır.
Ona görə observability platform səviyyəsində standartlaşdırılmalıdır və bu, ADR-ə layiq qərardır: ortaq telemetry kitabxanası, standart log sahələri, metric adlandırma qaydaları, propagation formatı və yeni service-lərin bunları default olaraq aldığı şablon. Ch05-dəki fitness function burada da işləyir: trace context ötürməyən service-i CI-da aşkarlamaq olar.
İki praktik məhdudiyyəti də nəzərə alın. Birincisi, xərc: telemetry asanlıqla infrastrukturun özündən baha başa gələ bilər. Ona büdcə ayırın, sampling-i və log-ların saxlanma müddətini şüurlu seçin. İkincisi, observability sisteminin özü də failure domain-dir. Monitoring production ilə eyni cluster-də və eyni region-dadırsa, region yıxılanda alert-lər də susur. Alert sistemi izlədiyi sistemdən müstəqil olmalıdır və onun özü də xaricdən yoxlanmalıdır, məsələn, sadə "heartbeat" alert-i ilə: bu siqnal gəlməyəndə kimsə xəbər tutsun.
Hazırkı sisteminiz haqqında suallar
- Son incident-də diaqnoz nə qədər çəkdi? Cavabı tapmaq üçün hansı siqnal çatışmırdı?
- Bir istifadəçi request-ini correlation ID ilə front-end-dən database-ə və asinxron consumer-lərə qədər izləyə bilirsinizmi? Zəncir harada qırılır?
- Son bir ayda gələn alert-lərin neçəsi konkret bir hərəkət tələb etdi? Qalanları niyə hələ də aktivdir?
- Monitoring sisteminiz production ilə eyni region-da yıxılsa, bundan necə və kim xəbər tutar?