Upload files to "q4-scalability"
هذا الالتزام موجود في:
57
q4-scalability/architecture.md
Normal file
57
q4-scalability/architecture.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Q4 — معمارية تطبيق يستقبل 15,000 req/s على غيمة
|
||||||
|
|
||||||
|
## Architecture Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
U[المستخدمون<br/>15,000 req/s] --> DNS[DNS<br/>ghaymah.systems / نطاق مخصص]
|
||||||
|
DNS --> LB["Load Balancer مُدار<br/>(SSL Termination + Health Checks)"]
|
||||||
|
|
||||||
|
LB --> AS["Auto-Scaling Group<br/>Container Fleet"]
|
||||||
|
|
||||||
|
subgraph Fleet["أسطول الحاويات (39 container - راجع calculations.md)"]
|
||||||
|
C1["Container 1<br/>g5.large"]
|
||||||
|
C2["Container 2<br/>g5.large"]
|
||||||
|
C3["..."]
|
||||||
|
C39["Container 39<br/>g5.large"]
|
||||||
|
end
|
||||||
|
|
||||||
|
AS --> C1
|
||||||
|
AS --> C2
|
||||||
|
AS --> C3
|
||||||
|
AS --> C39
|
||||||
|
|
||||||
|
C1 --> CACHE[("Redis Cache<br/>(Sessions / Hot Data)")]
|
||||||
|
C2 --> CACHE
|
||||||
|
C39 --> CACHE
|
||||||
|
|
||||||
|
C1 --> DB[("PostgreSQL مُدارة<br/>Primary + Read Replica")]
|
||||||
|
C2 --> DB
|
||||||
|
C39 --> DB
|
||||||
|
|
||||||
|
C1 --> BS[("Block Storage<br/>Uploads / Persistent Files")]
|
||||||
|
C39 --> BS
|
||||||
|
|
||||||
|
DB --> BK["نسخ احتياطي يومي/كل ساعة<br/>(ghaymah Backup)"]
|
||||||
|
|
||||||
|
subgraph Observability["المراقبة"]
|
||||||
|
MET[Metrics Collector]
|
||||||
|
LOGS[Log Aggregator]
|
||||||
|
ALERT[Alerting → Slack/Telegram]
|
||||||
|
end
|
||||||
|
|
||||||
|
C1 -.-> MET
|
||||||
|
C39 -.-> MET
|
||||||
|
MET --> ALERT
|
||||||
|
C1 -.-> LOGS
|
||||||
|
C39 -.-> LOGS
|
||||||
|
```
|
||||||
|
|
||||||
|
## قرارات التصميم
|
||||||
|
|
||||||
|
1. **Load Balancer مُدار أمام الأسطول:** يوزّع الحمل بخوارزمية round-robin/least-connections، ينهي SSL مركزياً بدل كل حاوية، ويستبعد الحاويات الفاشلة في health check تلقائياً — هذا يمنع نقطة فشل واحدة (single point of failure).
|
||||||
|
2. **Auto-Scaling Group بدل عدد ثابت:** الحمل نادراً ما يكون ثابتاً على مدار اليوم؛ نحتاج الحد الأدنى لتغطية 15K req/s + الهامش، لكن التوسع الإضافي (burst) يجب أن يكون تلقائياً بدل توفير أقصى سعة دائماً (توفير تكلفة).
|
||||||
|
3. **فصل التخزين المؤقت (Redis) عن قاعدة البيانات:** لتقليل الحمل على PostgreSQL في القراءات المتكررة (sessions، rate limiting counters)، وهذا ضروري عند 15K req/s لأن قاعدة بيانات واحدة لن تتحمل هذا الحجم من الاستعلامات المباشرة.
|
||||||
|
4. **PostgreSQL Primary + Read Replica:** فصل القراءة عن الكتابة يوزّع الحمل، ويحسّن التعافي من الكوارث (RTO أقل عند فشل Primary).
|
||||||
|
5. **Block Storage منفصل للحالة الدائمة (uploads):** الحاويات نفسها stateless وقابلة للاستبدال والتوسع الأفقي بحرية؛ أي بيانات يجب أن تبقى (ملفات مرفوعة) تُخزَّن في Block Storage مشترك بدل القرص المحلي للحاوية (الذي يُفقد عند إعادة الجدولة).
|
||||||
|
6. **مراقبة وتنبيه منفصلين (Observability layer):** لاكتشاف الانحرافات (زيادة زمن الاستجابة، ارتفاع معدل الأخطاء) قبل أن تتحول لانقطاع كامل، خصوصاً عند هذا الحجم من الحركة.
|
||||||
44
q4-scalability/calculations.md
Normal file
44
q4-scalability/calculations.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Q4 — الحسابات والاستراتيجيات
|
||||||
|
|
||||||
|
## 1. حساب عدد الحاويات المطلوبة
|
||||||
|
|
||||||
|
**المعطيات:**
|
||||||
|
- الحمل المستهدف: 15,000 req/s
|
||||||
|
- سعة الحاوية الواحدة: 500 req/s
|
||||||
|
- هامش أمان: 30% (لتغطية تذبذب الحمل، فشل حاوية واحدة أو أكثر أثناء rolling deploys، وتفادي التشغيل عند 100% سعة القصوى باستمرار)
|
||||||
|
|
||||||
|
**الحساب:**
|
||||||
|
|
||||||
|
```
|
||||||
|
الحمل المطلوب توفير سعة له = 15,000 req/s × 1.30 (هامش 30%) = 19,500 req/s
|
||||||
|
عدد الحاويات = 19,500 ÷ 500 req/s لكل حاوية = 39 حاوية
|
||||||
|
```
|
||||||
|
|
||||||
|
> بدون الهامش، الحد الأدنى النظري هو 30 حاوية (15,000 ÷ 500). لكن التشغيل عند 100% من السعة القصوى بدون أي هامش يعني أن أي زيادة طفيفة في الحمل أو فقدان حاوية واحدة يسبب تدهوراً فورياً في الأداء أو انقطاعاً جزئياً؛ لذلك 39 حاوية هي الرقم الآمن للتشغيل الفعلي.
|
||||||
|
|
||||||
|
**التوصية العملية:**
|
||||||
|
- `min_replicas: 39` (أو 40 للتقريب لأعلى وسهولة القسمة على مناطق التوفر)
|
||||||
|
- `max_replicas: 60` لاستيعاب حالات الذروة غير المتوقعة (حملات تسويقية، فيروسية) دون تدخل يدوي
|
||||||
|
- توزيع الـ 39 حاوية على 3 مناطق توفر (availability zones) إن كانت متاحة على غيمة، بمعدل 13 حاوية لكل منطقة، لتحمّل فشل منطقة كاملة.
|
||||||
|
|
||||||
|
## 2. استراتيجية Cold Start للحاويات الجديدة
|
||||||
|
|
||||||
|
المشكلة: عند التوسع الأفقي المفاجئ (scale-out)، الحاوية الجديدة تحتاج وقتاً لسحب الصورة، بدء العملية، والاتصال بقاعدة البيانات — خلال هذا الوقت هي غير جاهزة لاستقبال حركة، وإن استقبلتها مبكراً جداً ستفشل الطلبات.
|
||||||
|
|
||||||
|
**الحل المقترح:**
|
||||||
|
|
||||||
|
1. **صور خفيفة ومُحسّنة (Slim Images):** استخدام `python:3.12-slim` أو صور alpine بدل الصور الكاملة، وطبقات Docker مُخزّنة مسبقاً (layer caching) في سجل الحاويات — يقلل زمن السحب من ثوانٍ لأجزاء من الثانية.
|
||||||
|
2. **Warm Pool (نسخ جاهزة مسبقاً):** الاحتفاظ بعدد صغير من الحاويات "دافئة" (مبدوءة لكن idle، غير مستقبلة لحركة بعد) جاهزة للتفعيل الفوري عند الحاجة، بدل بدء حاوية من الصفر عند كل قرار توسع.
|
||||||
|
3. **Readiness Probe صارم قبل استقبال الحركة:** الحاوية لا تنضم لـ Load Balancer إلا بعد نجاح `/health` عدة مرات متتالية (وليس فقط بعد بدء العملية) — هذا يمنع توجيه حركة لحاوية لم تكتمل تهيئتها بعد (مثل اتصال قاعدة البيانات).
|
||||||
|
4. **Predictive/Scheduled Scaling:** إذا كان نمط الحمل معروفاً (ذروة صباحية، حملة مجدولة)، جدولة توسّع استباقي قبل الذروة الفعلية بـ 5-10 دقائق بدل الانتظار لتفاعل reactive.
|
||||||
|
5. **Connection Pooling عند بدء التشغيل:** تهيئة connection pool لقاعدة البيانات كجزء من startup script قبل الإعلان عن الجاهزية، لتفادي زمن اتصال إضافي عند أول طلب حقيقي.
|
||||||
|
|
||||||
|
## 3. استخدام ghaymah Block Storage لـ Stateful Workloads
|
||||||
|
|
||||||
|
الحاويات في هذه المعمارية **stateless بالتصميم** (قابلة للحذف والاستبدال والتوسع بحرية)، لكن بعض الأعباء تحتاج تخزيناً دائماً:
|
||||||
|
|
||||||
|
- **ملفات المستخدمين المرفوعة (uploads):** صور، مستندات — تُخزَّن على **Block Storage** بدل القرص المحلي للحاوية، لأن القرص المحلي يُفقد عند إعادة جدولة الحاوية أو استبدالها أثناء التوسع.
|
||||||
|
- **قواعد البيانات (PostgreSQL المُدارة):** تعتمد داخلياً على Block Storage عالي الأداء (IOPS مرتفع) لضمان دوام البيانات واستمرارها حتى لو أُعيد تشغيل الحاوية التي تستضيف محرك قاعدة البيانات.
|
||||||
|
- **التوصيل:** حجم Block Storage واحد يمكن ربطه بحاوية أو خدمة واحدة في كل مرة (وليس مشتركاً بين عدة حاويات كتابة متزامنة إلا إذا كان النظام يدعم ذلك)؛ لذلك في هذه المعمارية، Block Storage يُربط بخدمة قاعدة البيانات وليس مباشرة بكل حاوية من الـ 39.
|
||||||
|
- **النسخ الاحتياطي:** الاستفادة من ميزة **النسخ الاحتياطي كل ساعة** (متوفرة من خطة g5.large فما فوق) على مستوى Block Storage نفسه، بشكل منفصل عن نسخ قاعدة البيانات المنطقية، لتغطية سيناريوهات تلف على مستوى التخزين.
|
||||||
|
- **التوسعة الفورية:** عند نمو حجم البيانات، يمكن توسعة حجم Block Storage مباشرة (`$0.10/GB/شهر` إضافية) دون إعادة نشر التطبيق بالكامل.
|
||||||
المرجع في مشكلة جديدة
حظر مستخدم