Requirement-lərdən dizayna
Requirement-lərdən dizayna
Layihələrin çoxu səhv cavabdan yox, səhv sualdan başlayır. "Instagram kimi bir şey lazımdır" cümləsi ilə gələn tapşırıq dərhal diaqrama, database seçiminə və microservice-lər haqqında mübahisəyə çevrilir. Halbuki hələ heç kim neçə istifadəçi olacağını, onların nə qədər oxuyub nə qədər yazdığını və hansı qaydaların pozulmaz olduğunu bilmir.
Bu fəsil "nə qurmalıyıq?" sualından ölçülə bilən architectural driver-lərə keçidi izah edir: requirement-ləri necə toplamaq, constraint-ləri arzulardan necə ayırmaq və bir neçə dəqiqəlik hesablama ilə hansı qərarların artıq verildiyini necə görmək.
Üç növ architectural driver
Architecture-u formalaşdıran hər şey üç qrupdan birinə düşür:
- Functional requirement-lər. Sistemin nə etdiyi: "istifadəçi foto yükləyir", "izlədiyi insanların fotolarını feed-də görür". Onlar sistemin nə olduğunu müəyyən edir, amma nadir hallarda necə qurulacağını diktə edir. Eyni feature-ləri monolith də, onlarla service də yerinə yetirə bilər.
- Quality attribute-lər. Sistemin bunu nə qədər yaxşı etdiyi. Onları ch02-də ətraflı müzakirə etdik: scenario formasında yazılmalı və sıralanmalıdırlar. Architecture-un əsas hissəsini məhz onlar müəyyən edir.
- Constraint-lər. Artıq verilmiş və müzakirə olunmayan qərarlar. Onlar seçim sahəsini daraldır.
Faydalı vərdiş: hər yeni requirement-i eşidəndə özünüzə sual verin ki, bu, üç qrupdan hansına aiddir. "Sistem sürətli olmalıdır" functional requirement kimi səslənir, amma əslində ölçüsü olmayan quality attribute-dir. "PostgreSQL istifadə edəcəyik" isə requirement deyil, constraint və ya qərardır və hansının olduğunu bilmək vacibdir.
Constraint-lər danışıqsızdır
Constraint dizaynerin dəyişə bilmədiyi şərtdir. Onlar üç mənbədən gəlir:
- Texniki. Mövcud stack, inteqrasiya olunmalı legacy sistem, şirkətin vahid cloud provider-i, məcburi yenilənə bilməyən köhnə mobil client-lər.
- Biznes. Büdcə, deadline, komandanın bacarıqları. Üç nəfərlik, Kubernetes-lə heç vaxt işləməmiş komanda üçün "Kubernetes-də yüz service" seçim deyil, risk mənbəyidir.
- Hüquqi. Data residency (Avropa istifadəçilərinin data-sı Avropada qalmalıdır), GDPR kimi qaydalar ("unudulmaq hüququ" data-nın hər nüsxədən, backup-lar daxil, silinməsini tələb edir), audit və saxlama müddətləri.
Hüquqi constraint-lər xüsusilə bahadır, çünki gec aşkarlananda architecture-u yenidən qurmağı tələb edir. Data residency tələbi olan sistemdə tək qlobal database artıq mümkün deyil və bunu launch-dan bir ay əvvəl öyrənmək ən pis ssenaridir.
Ən çox rast gəlinən səhv constraint ilə üstünlük verilən seçimi qarışdırmaqdır. "Biz Java şirkətiyik" constraint ola bilər, əgər bütün komanda yalnız Java bilir və operational alətlər ona görə qurulub. Amma bu, sadəcə vərdiş də ola bilər. Fərqi yoxlamaq üçün soruşun: "Bu pozulsa, nə olar və bunu kim deyir?" Cavabda konkret insan və konkret nəticə yoxdursa, qarşınızdakı constraint deyil, müzakirə oluna bilən üstünlükdür. Saxta constraint-lər dizayn sahəsini lazımsız yerə daraldır. Real olanları isə ch05-dəki kimi qeydə almaq lazımdır ki, sonradan "bunu niyə belə etdik?" sualına cavab olsun.
Düzgün suallar
Requirement toplamaq dinləmək deyil, sorğu-sualdır. Klassik "neçə istifadəçi olacaq?" sualı faydalıdır, amma tək başına demək olar ki, heç nə demir. Onun arxasında daha vacib suallar gizlənir:
- Oxuma/yazma nisbəti. İstifadəçi əsasən oxuyur, yoxsa yazır? 100:1 nisbəti cache və replica-lara, 1:1 isə tamamilə fərqli storage seçiminə aparır.
- Peak. Load gün ərzində necə paylanır? Axşam saatları, kampaniyalar, futbol matçının son dəqiqəsi var?
- Data ölçüsü və artımı. Bir obyekt nə qədərdir və data nə qədər saxlanmalıdır: bir həftə, yoxsa həmişəlik?
- Coğrafiya. İstifadəçilər bir ölkədədir, yoxsa bütün dünyada? Bu, latency-ni və bəzən hüquqi constraint-ləri müəyyən edir.
- Konsistentlik. İstifadəçi öz yazdığını dərhal görməlidirmi? Başqası bir neçə saniyə gec görsə, problem varmı? Like sayı ilə bank balansı fərqli cavab tələb edir.
Hər sualın cavabını rəqəmlə almağa çalışın. Rəqəm bilinmirsə, aralıq soruşun: "min, yoxsa milyon?" Bu səviyyədə dəqiqlik çox vaxt kifayətdir.
Back-of-the-envelope estimation
Rəqəmlər olanda onları bir neçə dəqiqəyə load-a çevirmək olar. Məqsəd dəqiq cavab yox, düzgün tərtibdir: 100 request/s, yoxsa 100 000.
Əsas addımlar:
- DAU → QPS. Gündəlik aktiv istifadəçiləri bir istifadəçinin gündəlik əməliyyat sayına vurun və gündəki saniyələrə bölün.
- Average → peak. Traffic bərabər paylanmır. Adi istehlakçı məhsulu üçün peak orta göstəricidən 2–3 dəfə yüksəkdir, kampaniya və hadisələrdə isə 10 dəfə və daha çox. Sistem peak üçün ölçülür, average üçün yox.
- Storage. Gündəlik yeni data × saxlama müddəti × replication faktoru.
- Bandwidth. Saniyədəki request-lər × cavabın ölçüsü. Ayrıca daxil olan (ingress) və çıxan (egress) traffic.
Hesablamada hər fərziyyəni yazın. Sonradan rəqəm dəyişəndə nəyin dəyişdiyini görmək üçün fərziyyələr nəticədən daha dəyərlidir.
Rəqəmlərin intuisiyası
Hesablamanı tez etmək üçün bir neçə rəqəmi əzbər bilmək kifayətdir:
| Əməliyyat | Təxmini vaxt |
|---|---|
| RAM-dan oxuma | ~100 ns |
| SSD-dən random read | ~100 µs |
| Eyni datacenter daxilində round trip | ~0.5 ms |
| HDD seek | ~10 ms |
| Region-lar arası round trip | ~50–150 ms |
Cədvəlin dərsi nisbətlərdədir: RAM SSD-dən min dəfə sürətlidir, şəbəkə üzərindən başqa region-a getmək isə RAM-dan milyon dəfə yavaşdır. Bir request-də ardıcıl beş region-lar arası çağırış varsa, istifadəçi yarım saniyə gözləyir və heç bir optimizasiya bunu düzəltməyəcək.
Vahidlər üçün qısa yollar:
- 2^10 ≈ 10^3 (KB), 2^20 ≈ 10^6 (MB), 2^30 ≈ 10^9 (GB), 2^40 ≈ 10^12 (TB), 2^50 ≈ 10^15 (PB).
- 1 gün = 86 400 saniyə ≈ 10^5. Deməli, gündə 1 milyon əməliyyat təxminən 10–12 QPS-dir.
- 1 il ≈ 3 × 10^7 saniyə.
Nümunə: foto paylaşma servisi
Fərziyyələr: 10M DAU. Hər istifadəçi gündə 2 foto yükləyir və 50 foto görür. Orta foto 2 MB-dır, metadata (müəllif, vaxt, caption) təxminən 1 KB. Peak faktoru 3. Replication faktoru 3.
Upload QPS: 10M × 2 = 20M upload/gün. 20M / 86 400 ≈ 230/s orta, peak-də ≈ 700/s.
Read QPS: 10M × 50 = 500M baxış/gün. 500M / 86 400 ≈ 5 800/s orta, peak-də ≈ 17 000/s. Oxuma/yazma nisbəti 25:1-dir.
Foto storage: 20M × 2 MB = 40 TB/gün. 40 TB × 365 ≈ 14.6 PB/il. Replication ilə ≈ 44 PB/il.
Metadata storage: 20M × 1 KB = 20 GB/gün, ≈ 7.3 TB/il. Replication ilə ≈ 22 TB/il.
Bandwidth: Upload ingress 40 TB / 86 400 ≈ 460 MB/s ≈ 3.7 Gbps. Hər baxışda tam 2 MB-lıq foto göndərilsə, egress 500M × 2 MB = 1 PB/gün ≈ 11.6 GB/s ≈ 93 Gbps orta, peak-də ≈ 280 Gbps olardı.
Bu rəqəmlər artıq bir neçə qərarı məcbur edir. Foto ilə metadata eyni yerdə saxlana bilməz: 44 PB-lıq binary data object storage-a, 22 TB-lıq strukturlaşdırılmış metadata isə database-ə aiddir. Bu ölçüdə metadata ilk illərdə bir neçə maşına sığır və sharding hələ vacib deyil, foto storage-ı isə ilk gündən paylanmış olmalıdır. 93 Gbps egress birbaşa server-lərdən verilə bilməz: CDN və feed üçün kiçik ölçülü versiyalar (məsələn, 200 KB-lıq thumbnail) egress-i on dəfə azaldır. Bu building block-lara large-scale building block-lar fəslində qayıdacağıq.
Rəqəmlər nəyi məcbur edir, nəyi etmir
Hesablamanın ən dəyərli nəticəsi bəzən "hələ heç nə etməyə ehtiyac yoxdur" cavabıdır. Ümumi qaydalar:
- Oxuma-ağır sistem (nümunəmizdəki kimi 25:1 və ya daha çox): cache, read replica-lar, CDN. Yazmanı sadə saxlamaq olar.
- Yazma-ağır sistem (log-lar, IoT telemetriyası, event-lər): yazma throughput-u üçün optimallaşdırılmış storage, partition-lara bölmə, batching. Cache burada az kömək edir.
- Kiçik rəqəmlər. Peak-də 50 QPS və bir neçə GB data olan sistem üçün bir yaxşı database və iki application instance kifayətdir. Bu ölçüdə sharding, ayrıca cache layer-i və ya event-driven architecture yalnız mürəkkəblik əlavə edir.
Hesablama bu şəkildə YAGNI-yə rəqəm verir. "Gələcəkdə milyon istifadəçi olarsa?" sualına cavab "onda yenidən hesablayacağıq, bu, 100 dəfəlik artımdır və ona qədər architecture onsuz da dəyişəcək" ola bilər. Amma əksinə də işləyir: rəqəmlər bir server-in imkanlarını aşırsa, bunu ilk gündən bilmək sonradan migration-dan qat-qat ucuzdur.
Rəqəmlərin özü də driver-dir. Onları ch02-dəki scenario-lara bağlayın ("peak-də 17 000 read/s, p99 200 ms-dən aşağı"), fərziyyələri ch05-dəki kimi ADR-də qeyd edin və real traffic gələndə yoxlayın. Capacity planning bir dəfəlik hesablama yox, fərziyyələrin müntəzəm reallıqla müqayisəsidir.
Hazırkı sisteminiz haqqında suallar
- Sisteminizin peak QPS-ini, oxuma/yazma nisbətini və illik data artımını bilirsinizmi? Bilmirsinizsə, beş dəqiqəlik hesablama ilə real ölçülər arasındakı fərq nə qədərdir?
- Komandanızın "constraint" adlandırdığı üç şeyi sadalayın. Hər biri üçün "pozulsa nə olar və bunu kim deyir?" sualına cavab varmı?
- Data residency və ya saxlama müddəti ilə bağlı hüquqi tələblər varmı və onlar architecture-da harada əks olunub?
- Rəqəmlərin hələ tələb etmədiyi, amma artıq qurduğunuz bir struktur varmı? O nəyə başa gəlir?