Ghaymah intern
هذا الالتزام موجود في:
133
q4-scalability/scalability-report.md
Normal file
133
q4-scalability/scalability-report.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# قابلية التوسع وتوزيع الأحمال — تطبيق يستقبل 15,000 req/s على غيمة
|
||||
|
||||
## 1. Architecture Diagram
|
||||
|
||||

|
||||
|
||||
### شرح طبقات المعمارية
|
||||
|
||||
| الطبقة | الدور |
|
||||
|---|---|
|
||||
| **CDN / DNS** (اختياري) | تقديم الملفات الثابتة (صور، CSS، JS) بعيدًا عن السيرفرات الأساسية لتخفيف الحمل |
|
||||
| **Ghaymah Load Balancer** | يوزّع الـ 15,000 request/second على كل الحاويات المتاحة، ويستبعد أي حاوية فشلت في فحص `/health` |
|
||||
| **طبقة التطبيق (Auto-scaling Group)** | 39 حاوية تشغّل نفس كود التطبيق، بدون حالة (Stateless) — أي حاوية تقدر تخدم أي طلب |
|
||||
| **Valkey (Cache)** | يخزّن نتائج متكررة الطلب في الذاكرة لتقليل عدد المرات اللي التطبيق محتاج فيها يرجع لقاعدة البيانات |
|
||||
| **PgBouncer (Connection Pooler)** | يمنع كل حاوية من فتح اتصال منفصل بقاعدة البيانات — بيجمع الاتصالات في مجموعة مشتركة محدودة |
|
||||
| **PostgreSQL + Ghaymah Block Storage** | قاعدة البيانات الوحيدة اللي عندها حالة (Stateful) — بياناتها محفوظة على Block Storage مستقل عن دورة حياة الحاوية |
|
||||
| **Grafana / Uptime Kuma** | مراقبة اتجاه الموارد وحالة كل حاوية لحظيًا |
|
||||
|
||||
**لماذا الحاويات Stateless؟** عشان الـ Load Balancer يقدر يوزّع أي طلب على أي حاوية من غير ما يهتم "مين خدم الطلب اللي فات" — أي بيانات محتاجة تتحفظ (Session, User data) بتتخزن في Valkey أو PostgreSQL مش داخل الحاوية نفسها.
|
||||
|
||||
---
|
||||
|
||||
## 2. حساب عدد الحاويات المطلوبة
|
||||
|
||||
### المعطيات
|
||||
- الحمل الكلي: **15,000 request/second**
|
||||
- سعة الحاوية الواحدة: **500 request/second**
|
||||
- هامش أمان: **30%**
|
||||
|
||||
### طريقة الحساب
|
||||
|
||||
الهدف من هامش الأمان هو **عدم تشغيل أي حاوية على أقصى طاقتها بالكامل** — بيسيب مساحة للتعامل مع أي ارتفاع مفاجئ في الحمل (Traffic spike) من غير ما يحصل تعطّل.
|
||||
|
||||
**الخطوة 1: العدد الأساسي بدون هامش**
|
||||
```
|
||||
عدد الحاويات الأساسي = إجمالي الطلبات ÷ سعة الحاوية
|
||||
= 15,000 ÷ 500
|
||||
= 30 حاوية
|
||||
```
|
||||
|
||||
**الخطوة 2: إضافة هامش الأمان 30%**
|
||||
```
|
||||
عدد الحاويات النهائي = 30 × (1 + 0.30)
|
||||
= 30 × 1.30
|
||||
= 39 حاوية
|
||||
```
|
||||
|
||||
### ✅ النتيجة: **39 حاوية**
|
||||
|
||||
> ملاحظة: فيه طريقة حساب بديلة لنفس المفهوم — اعتبار إن كل حاوية بتشتغل بحد أقصى 70% من طاقتها بس (500 × 0.7 = 350 req/s فعّالة)، وده بيدّي `15,000 ÷ 350 ≈ 43` حاوية. الطريقتين صحيحتين مفاهيميًا (الهدف "هامش أمان")، لكن التفسير الأول (39 حاوية) هو الأقرب لصياغة "العدد + هامش 30%" في نص المهمة، فهو المعتمد هنا.
|
||||
|
||||
### جدول توضيحي لأحمال مختلفة (Auto-scaling Table)
|
||||
|
||||
| الحمل الحالي (req/s) | العدد الأساسي | العدد بعد هامش 30% |
|
||||
|---|---|---|
|
||||
| 5,000 | 10 | 13 |
|
||||
| 10,000 | 20 | 26 |
|
||||
| 15,000 | 30 | **39** |
|
||||
| 20,000 | 40 | 52 |
|
||||
|
||||
هذا الجدول هو أساس سياسة Auto-scaling: كل ما زاد الحمل الفعلي، تزيد المنصة عدد الحاويات تلقائيًا بنفس النسبة.
|
||||
|
||||
---
|
||||
|
||||
## 3. استراتيجية Cold Start للحاويات الجديدة
|
||||
|
||||
**المشكلة:** لما Auto-scaling يقرر يضيف حاوية جديدة فجأة (بسبب ارتفاع الحمل)، الحاوية الجديدة بتاخد وقت (Cold Start) قبل ما تبقى جاهزة فعليًا تستقبل طلبات — تحميل التطبيق، فتح اتصالات قاعدة البيانات، تسخين الكاش المحلي... إلخ. لو الـ Load Balancer وجّه طلبات ليها فورًا، ممكن تفشل أو تكون بطيئة جدًا.
|
||||
|
||||
### الاستراتيجية المقترحة
|
||||
|
||||
| # | الإجراء | الفائدة |
|
||||
|---|---|---|
|
||||
| 1 | **Minimum Warm Pool** — حافظ دايمًا على عدد أدنى من الحاويات شغالة (مثلًا 10 حاويات) حتى وقت الحمل المنخفض | يقلل الاعتماد على Cold Start في الحالات العادية؛ التوسع بيبقى غالبًا زيادة على حاويات موجودة أصلًا مش بداية من الصفر |
|
||||
| 2 | **Readiness Probe قبل استقبال الترافيك** | الحاوية الجديدة متتسجلش في الـ Load Balancer إلا بعد ما ترد بنجاح على فحص `/health` أو `/ready` — يمنع توجيه طلبات لحاوية لسه بتبدأ |
|
||||
| 3 | **صور Docker خفيفة ومبنية مسبقًا (Pre-built lightweight images)** | استخدام صور Alpine بدل الصور الكاملة، وبناء الطبقات (Layers) بترتيب يخلي الأجزاء المتغيرة بس تحتاج إعادة تحميل — يقلل وقت الـ pull والبدء |
|
||||
| 4 | **Connection Pool Warm-up عند البدء** | فتح اتصالات قاعدة البيانات (عبر PgBouncer) والكاش (Valkey) فورًا عند إقلاع الحاوية، قبل ما تستقبل أول طلب حقيقي |
|
||||
| 5 | **Predictive/Scheduled Scaling** | لو أوقات الذروة معروفة ومتكررة (مثلًا كل يوم الساعة كذا)، جدولة زيادة الحاويات مسبقًا بدل انتظار الحمل يرتفع فعليًا ثم رد الفعل |
|
||||
| 6 | **Gradual Traffic Ramp-up (Canary-style)** | بعد ما الحاوية الجديدة تجتاز فحص الصحة، وجّهلها نسبة صغيرة من الترافيك الأول (مثلًا 10%) وزوّدها تدريجيًا، بدل ما تستقبل حصتها الكاملة فورًا |
|
||||
| 7 | **Cooldown/Stabilization Window** | فترة انتظار قصيرة (دقيقة أو دقيقتين) بعد كل قرار توسّع قبل اتخاذ قرار توسّع جديد — يمنع "التذبذب" (Flapping) في عدد الحاويات |
|
||||
|
||||
### التسلسل الزمني المقترح لإضافة حاوية جديدة
|
||||
```
|
||||
قرار Auto-scaling (الحمل تجاوز العتبة)
|
||||
│
|
||||
▼
|
||||
سحب/تشغيل الصورة (Image pull - سريع لو الصورة خفيفة ومخزنة مسبقًا على العقدة)
|
||||
│
|
||||
▼
|
||||
بدء التطبيق + Connection Pool Warm-up
|
||||
│
|
||||
▼
|
||||
Readiness Probe ينجح
|
||||
│
|
||||
▼
|
||||
التسجيل في Load Balancer بحصة ترافيك صغيرة (10%)
|
||||
│
|
||||
▼
|
||||
زيادة الحصة تدريجيًا لحد الوصول لحصة كاملة عادية
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. استخدام Ghaymah Block Storage للـ Stateful Workloads
|
||||
|
||||
### ليه الحاويات نفسها مش مكان مناسب لتخزين البيانات؟
|
||||
الحاويات في المعمارية دي **Stateless بالتصميم** — ممكن تتقفل أو تتستبدل في أي وقت (Auto-scaling, إعادة نشر, فشل مفاجئ) من غير أي تحذير. أي بيانات محفوظة جوه الحاوية نفسها بتضيع فور ما الحاوية تتقفل.
|
||||
|
||||
### دور Block Storage
|
||||
**Ghaymah Block Storage** هو تخزين دائم (Persistent Volume) مستقل تمامًا عن دورة حياة أي حاوية معينة — بيتحط (Attach) على الحاوية اللي محتاجاه، ولو الحاوية دي اتقفلت أو اتستبدلت، الـ Volume بياناته باقية وممكن يتحط على حاوية جديدة.
|
||||
|
||||
### أهم الاستخدامات في هذه المعمارية
|
||||
|
||||
| الحالة | استخدام Block Storage |
|
||||
|---|---|
|
||||
| **قاعدة بيانات PostgreSQL** | ملفات البيانات (Data directory) بتتخزن على Volume منفصل، مش داخل حاوية قاعدة البيانات نفسها — لو الحاوية اتعاد تشغيلها أو اتستبدلت (تحديث نسخة مثلًا)، البيانات باقية |
|
||||
| **رفع ملفات المستخدمين (User uploads)** | لو التطبيق بيسمح برفع صور/ملفات، بتتخزن على Volume مشترك بدل تخزينها محليًا داخل حاوية واحدة (اللي ممكن تختفي وتاخد الملفات معاها) |
|
||||
| **أرشفة اللوجز طويلة المدى** | لوجز التطبيق التفصيلية اللي محتاجة تتحفظ لفترة أطول من عمر الحاوية |
|
||||
| **نسخ احتياطية (Backups)** | تصدير نسخ احتياطية دورية من قاعدة البيانات على Volume منفصل، مستقل عن أي Container instance |
|
||||
|
||||
### مبادئ أساسية للاستخدام الصحيح
|
||||
1. **فصل التخزين عن الحوسبة (Decouple storage from compute):** الحاوية تُعامل كموردة مؤقتة قابلة للاستبدال، والـ Volume هو مكان "الحقيقة الدائمة" للبيانات
|
||||
2. **حاوية واحدة فعّالة للكتابة في كل مرة** (لقواعد البيانات التقليدية) — لتفادي تعارض الكتابة المتزامنة على نفس الـ Volume
|
||||
3. **نسخ احتياطي دوري للـ Volume نفسه**، مش الاعتماد عليه كمصدر وحيد للبيانات
|
||||
4. **قياس الأداء (IOPS/Throughput)** المطلوب حسب حمل قاعدة البيانات — قواعد البيانات عالية الكتابة محتاجة Block Storage بأداء أعلى من مجرد تخزين ملفات ثابتة
|
||||
|
||||
### كيف يتكامل هذا مع باقي المعمارية
|
||||
```
|
||||
حاوية PostgreSQL (Stateless container, قابلة للاستبدال)
|
||||
│
|
||||
▼ (attach)
|
||||
Ghaymah Block Storage Volume (البيانات الفعلية، دائمة)
|
||||
```
|
||||
لو حاوية قاعدة البيانات احتاجت تُعاد تشغيلها (تحديث، صيانة، أو حتى فشل)، حاوية جديدة تتشغل وتاخد نفس الـ Volume المرفق — البيانات ما بتضيعش، وده الفرق الجوهري بين التعامل مع الـ 39 حاوية التطبيقية (Stateless، ممكن تتستبدل بحرية) وحاوية قاعدة البيانات (Stateful، البيانات لازم تتحفظ عبر Block Storage).
|
||||
المرجع في مشكلة جديدة
حظر مستخدم