Availability, fault tolerance və SLO-lar
Availability, fault tolerance və SLO-lar
"Sistem həmişə işləməlidir" requirement deyil, arzudur. Heç bir sistem həmişə işləmir. Hardware xarab olur, deploy-lar səhv gedir, cloud provider-in bütöv bir zonası saatlarla əlçatmaz qalır. Real sual budur: nə qədər tez-tez, nə qədər uzun müddətə və kim üçün işləməməsinə razıyıq və bu razılığın qiyməti nədir?
Bu fəsil availability-ni rəqəmlə ifadə etməyi, onu SLO-lar vasitəsilə komanda üçün iş alətinə çevirməyi və fault tolerance-ı təsadüfdən dizayna keçirməyi izah edir.
Availability-ni rəqəmlə ifadə etmək
Ən sadə tərif: availability sistemin istifadəyə yararlı olduğu vaxtın ümumi vaxta nisbətidir. Onu adətən "nines" ilə ifadə edirlər:
| Availability | İldə icazə verilən downtime | Ayda icazə verilən downtime |
|---|---|---|
| 99% ("two nines") | 3.65 gün | 7.3 saat |
| 99.9% | 8.8 saat | 43.8 dəqiqə |
| 99.95% | 4.4 saat | 21.9 dəqiqə |
| 99.99% | 52.6 dəqiqə | 4.4 dəqiqə |
| 99.999% | 5.3 dəqiqə | 26 saniyə |
Cədvəlin ən vacib dərsi sağ sütundadır. 99.99% hədəfi ayda dörd dəqiqədən bir az artıq downtime deməkdir. Bu müddətdə on-call mühəndis telefonuna baxıb laptop-unu aça bilməz. Deməli, dörd "9"-dan başlayaraq recovery insanlar tərəfindən yox, avtomatik edilməlidir. Bu da architecture qərarıdır.
Eyni rəqəmə başqa tərəfdən də baxmaq olar:
Availability = MTBF / (MTBF + MTTR)
Burada MTBF iki failure arasındakı orta vaxt, MTTR isə failure-dan sonra bərpa üçün lazım olan orta vaxtdır. Formula vacib bir şeyi göstərir: availability-ni artırmağın iki yolu var. Failure-ları azaltmaq (MTBF-i böyütmək) və ya onlardan daha tez çıxmaq (MTTR-i kiçiltmək). Praktikada ikinci yol çox vaxt daha ucuzdur. Hər bug-ın qarşısını almaq mümkün deyil, amma bir dəqiqəlik rollback qurmaq mümkündür.
Dependency-lər availability-ni vurub azaldır
Sistem tək komponentdən ibarət deyil. Request yolunda bir neçə komponent ardıcıl dayananda onların availability-ləri bir-birinə vurulur:
Checkout service 99.95%, onun database-i 99.95%, xarici payment provider isə 99.9% availability-yə malikdir. Checkout-un ümumi availability-si 0.9995 × 0.9995 × 0.999 ≈ 99.8% olur. Bu, ildə təxminən 17.5 saat deməkdir: hər komponentin ayrı-ayrılıqda vəd etdiyindən iki dəfədən çox.
Nəticə sadədir: siz heç vaxt critical path-dəki ən zəif dependency-dən daha available ola bilməzsiniz. Hər yeni synchronous çağırış availability-ni azaldır. Ch03-də qeyd olunan distributed monolith-in pis tərəflərindən biri məhz budur.
Paralel komponentlərdə riyaziyyat əksinə işləyir. Hər biri 99% available olan iki müstəqil replica-dan heç olmasa birinin işləmə ehtimalı 1 − (0.01 × 0.01) = 99.99%-dir. Redundancy-nin gücü buradan gəlir.
Amma bir şərt var: müstəqil. Eyni zonada, eyni rack-da yerləşən, eyni config-lə və eyni anda deploy edilən iki replica müstəqil deyil. Onlar birlikdə yıxılır və riyaziyyat işləmir. Real outage-lərin böyük hissəsi məhz belə correlated failure-lardan yaranır.
SLI, SLO və SLA
"Availability" sözünün özü də qeyri-müəyyəndir. Ch02-də quality attribute scenario-ları ilə etdiyimiz kimi, onu ölçülə bilən formaya salmaq lazımdır. Bunun üçün üç səviyyəli lüğət istifadə olunur:
- SLI (Service Level Indicator): ölçü. Ən faydalı forma nisbətdir: yaxşı event-lər / bütün etibarlı event-lər. Məsələn: "5xx qaytarmayan və 300 ms-dən tez cavab verən HTTP request-lərin faizi."
- SLO (Service Level Objective): həmin ölçü üçün müəyyən vaxt pəncərəsində hədəf. Məsələn: "28 günlük pəncərədə request-lərin 99.9%-i yaxşı olmalıdır."
- SLA (Service Level Agreement): müştəri ilə müqavilə. Pozulanda nəticəsi var, adətən pul geri qaytarılır və ya kredit verilir.
Üç praktik qayda:
- SLI istifadəçinin gözü ilə ölçülməlidir. Server-in CPU-su sağlam ola bilər, istifadəçi isə yenə də timeout alır. Ölçünü istifadəçiyə ən yaxın nöqtədən, yəni load balancer-dən və ya client-dən götürün.
- SLO SLA-dan sərt olmalıdır. Müştəriyə 99.5% vəd edirsinizsə, daxili hədəfiniz 99.9% olmalıdır. Aradakı fərq müqavilə pozulmamışdan əvvəl reaksiya vermək üçün vaxtdır.
- 100% hədəf deyil. O, nə mümkündür, nə də lazımdır. İstifadəçinin öz Wi-Fi-ı və telefonu sizin sisteminizdən daha az etibarlıdır. Ondan artıq etibarlılığa sərf olunan pul heç kimin görmədiyi fərqə xərclənir.
Error budget: reliability ilə sürət arasında danışıq
SLO-nun ən güclü tərəfi onun tərsidir. 99.9% SLO 0.1% error budget deməkdir. Ayda 10 milyon request emal edən service üçün bu, ayda 10 000 uğursuz request-ə icazə deməkdir.
Bu rəqəm komandalar arasındakı ən köhnə mübahisəni həll edir. Product komandası daha tez release etmək istəyir, operations isə sabitlik istəyir. Error budget hər ikisinə ortaq valyuta verir:
- Budget qalıb? Risk götürmək olar: daha tez-tez deploy, eksperimentlər, böyük refactoring-lər.
- Budget xərclənib? Yeni feature-lər dayandırılır və komanda reliability işinə keçir, ta ki pəncərə bərpa olunana qədər.
Bu qayda yalnız əvvəlcədən yazılıb razılaşdırılanda işləyir. Bu, error budget policy adlanır və ch05-dəki mənada ADR-ə layiq qərardır: onu sonradan dəyişmək təşkilati cəhətdən bahadır və hamı onun niyə belə olduğunu bilməlidir.
Fault tolerance tactic-ləri
Fault tolerance komponent xarab olanda sistemin istifadəçiyə xidmət etməyə davam etməsi deməkdir. Ch02-nin dili ilə desək, aşağıdakılar availability üçün tactic-lərdir:
- Redundancy. Hər critical komponentin ehtiyatı olsun. N+1 bir node itkisinə dözür. N+2 isə bir node planlı maintenance-də olarkən digərinin gözlənilmədən xarab olmasına da dözür.
- Replication. Data-nın bir neçə nüsxədə saxlanması. Burada consistency ilə bağlı çətin seçimlər var, onlara data haqqındakı fəsildə qayıdacağıq.
- Failover. Xarab olan komponentin yerini ehtiyatın tutması. Active-passive modeldə ehtiyat gözləyir: sadədir, amma keçid vaxt aparır və ehtiyat nadir hallarda real yük altında test olunur. Active-active modeldə bütün nüsxələr eyni anda traffic qəbul edir: keçid demək olar ki, anidir, amma state-in sinxronlaşdırılması xeyli çətinləşir.
- Failure detection. Health check-lər, heartbeat-lər, timeout-lar. Failover yalnız failure-u nə qədər tez aşkarlaya bildiyiniz qədər sürətlidir.
- Stateless service-lər. State-i olmayan instance-ı öldürüb yenisini başlatmaq olar. State-i kənara, yəni database-ə, cache-ə və ya queue-ya çıxarmaq redundancy-ni ucuzlaşdırır.
Failure domain-lər
Failure domain eyni səbəbdən birlikdə xarab ola bilən hər şeyin sərhədidir. Fiziki səviyyədə bunlar host, rack, availability zone (AZ) və region-dur. Amma ən təhlükəli failure domain-lər məntiqi olanlardır:
- Deploy. Bütün instance-lara eyni anda çatan səhv build.
- Config. Bütün region-lara eyni anda yayılan səhv feature flag.
- Ortaq dependency. Hamının istifadə etdiyi bir DNS, auth service və ya message broker.
Sual həmişə eynidir: bu komponent xarab olanda zərər nə qədər yayılır? Cybersecurity-də bu, blast radius adlanır və reliability-də də eyni məna daşıyır. Onu kiçiltməyin yolları: replica-ları fərqli zonalara paylamaq, deploy-ları mərhələlərlə etmək (deployment strategiyalarına ayrıca fəsildə baxacağıq) və böyük sistemləri müstəqil "cell"-lərə bölmək. Belə ki, bir cell-in yıxılması istifadəçilərin yalnız bir hissəsinə təsir etsin.
Gündəlik diaqramlarda gizlənən səhv: "üç replica-mız var" deyirik, amma üçü də eyni AZ-dadır. Bu, üç replica deyil, bir failure domain-dir.
Hər "9"-un qiyməti
Hər əlavə "9" təxminən on dəfə az downtime deməkdir və adətən on dəfəyə yaxın daha çox səy tələb edir. 99.9%-ə yaxşı monitoring və sürətli rollback ilə çatmaq olar. 99.99% avtomatik failover, multi-AZ yerləşdirmə və ciddi on-call tələb edir. 99.999% isə multi-region active-active, chaos engineering və bütün bunları idarə edən böyük komanda deməkdir.
Buna görə availability bütün sistem üçün bir rəqəm olmamalıdır. Ch02-dəki sual burada da işləyir: hansı outage xəbərlərə düşərdi? Checkout və login üçün dörd "9" əsaslandırılmış ola bilər. Tövsiyələr bloku üçün isə iki "9" kifayətdir, xüsusən də o, xarab olanda səhifə sadəcə onsuz render olunursa.
Availability-ni yuxarıdan aşağıya bir rəqəm kimi tələb etmək yox, hər istifadəçi axını üçün ayrıca seçmək və hər birinin qiymətini bilmək lazımdır.
Hazırkı sisteminiz haqqında suallar
- Ən vacib istifadəçi axınınız üçün bir SLI yazın. Onu bu gün ölçə bilirsinizmi, yoxsa yalnız server-in sağlamlığını ölçürsünüz?
- Bu axının critical path-indəki bütün synchronous dependency-ləri sadalayın və availability-lərini vurun. Nəticə vəd etdiyinizdən yüksəkdirmi?
- Sizin "redundant" komponentləriniz həqiqətən müstəqildirmi? Onları eyni anda yıxa biləcək bir deploy, config və ya zona varmı?
- Son outage-dən sonra recovery nə qədər çəkdi? Onu yarıya endirmək üçün ən ucuz dəyişiklik hansıdır?