الملفات
ghaymah-exam-ayashosha-sre/q2-postmortem/postmortem-report.md
2026-07-29 05:21:40 +03:00

274 أسطر
9.2 KiB
Markdown
خام اللوم التاريخ

هذا الملف يحتوي على أحرف Unicode غامضة

هذا الملف يحتوي على أحرف Unicode قد تُخلط مع أحرف أخرى. إذا كنت تعتقد أن هذا مقصود، يمكنك تجاهل هذا التحذير بأمان. استخدم زر الهروب للكشف عنها.

# Q2 — تحليل حادثة انقطاع (Postmortem)
**التاريخ:** 28 يوليو 2026
**المدة:** 45 دقيقة
**الخدمة:** تطبيق Node.js على غيمة (`nodeapp-production`)
**التأثير:** انقطاع كامل عن المستخدمين — HTTP 502/503
**السبب المباشر:** OOMKilled متكرر (نفاد الذاكرة)
---
## 1. الملخص التنفيذي
في 28 يوليو 2026، تعطّل تطبيق الإنتاج على **Ghaymah Cloud** لمدة **45 دقيقة** بسبب قتل الحاويات المتكرر من نوع **OOMKilled**.
ارتفع استهلاك الذاكرة تدريجياً بعد نشر إصدار جديد، حتى تجاوز الحد المخصص للحاوية (`512 MiB` — فئة `t1`).
بدأت الحاويات في الدورة: تشغيل → امتلاء الذاكرة → OOMKill → إعادة تشغيل، مما جعل **Health Probes** تفشل وخرجت جميع النسخ من **Load Balancer**.
**السبب الجذري:** حد ذاكرة غير كافٍ + تسريب ذاكرة (memory leak) في middleware جديد + غياب تنبيهات مبكرة و auto-scaling.
**الإجراء الفوري:** رفع حجم الحاوية إلى `ρ-l` (1 GiB) وزيادة `count` من 2 إلى 4، ثم rollback للإصدار السابق.
---
## 2. Timeline
| الوقت (UTC+3) | الحدث |
|---------------|--------|
| 14:00 | حركة طبيعية — 2 حاويات، استهلاك ذاكرة ~55% |
| 14:12 | نشر إصدار `v1.4.2` (rolling deploy) |
| 14:18 | الذاكرة ترتفع إلى ~78% على الحاويات الجديدة |
| 14:22 | **أول OOMKill** — الحاوية `pod-7f3a` تُقتل من Kernel |
| 14:24 | إعادة تشغيل تلقائية — Health probe يفشل لـ 30 ثانية |
| 14:26 | OOMKill ثاني — بدء **restart loop** |
| 14:30 | LB يزيل كل الحاويات من rotation — **بداية الانقطاع الكامل** |
| 14:35 | تنبيه uptime يرسل (تأخر 13 دقيقة عن أول OOMKill) |
| 14:40 | مهندس on-call يراجع logs — يجد `OOMKilled` و `Exit Code 137` |
| 14:42 | rollback إلى `v1.4.1` + رفع `size` إلى `ρ-l` |
| 14:45 | Health probes تنجح — **استعادة الخدمة** |
**MTTR:** 45 دقيقة
**MTTD (Mean Time To Detect):** ~13 دقيقة (بطيء)
---
## 3. Root Cause Analysis
### 3.1 السبب المباشر (Immediate Cause)
Linux Kernel قتل عملية الحاوية لأنها تجاوزت **memory limit** المحدد في `.ghaymah.json`:
```json
"resourceTier": "t1" // 512 MiB RAM
```
رسالة النظام:
```text
State: OOMKilled
Exit Code: 137
Reason: Memory limit exceeded
```
### 3.2 السبب الجذري (Root Cause)
| # | السبب | التفصيل |
|---|--------|---------|
| 1 | **حد ذاكرة منخفض** | `t1` (512 MiB) غير مناسب لحمل الإنتاج بعد النشر الجديد |
| 2 | **Memory leak** | middleware logging في `v1.4.2` يخزّن request bodies في array بدون حد أقصى |
| 3 | **لا auto-scaling** | `count: 2` ثابت — لم يُضف حاويات عند ارتفاع الحمل |
| 4 | **تنبيهات متأخرة** | لا يوجد alert على memory > 80% أو restart count |
### 3.3 العوامل المساهمة
- لم يُجرَ load test على `v1.4.2` قبل الإنتاج
- Rolling deploy أبقى 20% من الحاويات القديمة لكن الجديدة consumptive أكثر
- لا مراقبة لـ `container_restart_count`
---
## 4. التوصيات (Action Items)
| # | الإجراء | الأولوية | المسؤول | الحالة |
|---|---------|----------|---------|--------|
| 1 | إصلاح memory leak في middleware | P0 | Backend | ✅ تم |
| 2 | رفع الحد الأدنى للذاكرة إلى `ρ` (768 MiB) | P0 | SRE | ✅ تم |
| 3 | تفعيل auto-scaling (انظر القسم 2 أدناه) | P1 | SRE | 🔄 قيد التنفيذ |
| 4 | تنبيه RasidAI عند memory > 80% لـ 2 دقيقة | P1 | SRE | 🔄 قيد التنفيذ |
| 5 | تنبيه عند `restart_count > 3` في 10 دقائق | P1 | SRE | 📋 مخطط |
| 6 | load test إلزامي قبل deploy لـ main | P2 | DevOps | 📋 مخطط |
| 7 | إضافة `/health` يفحص memory usage | P2 | Backend | 📋 مخطط |
---
## 5. سياسة Auto-Scaling لمنصة غيمة
غيمة توفر مفتاحين رئيسيين في `.ghaymah.json`:
- **`count:`** — عدد النسخ (Horizontal Scaling)
- **`size:`** — فئة CPU/RAM: `ρ`, `ρ-m`, `ρ-l`, `ρ-xl` (Vertical Scaling)
### 5.1 Horizontal Pod Scaling (HPA)
```
زِد count عندما:
- متوسط CPU > 70% لمدة 3 دقائق، أو
- متوسط Memory > 75% لمدة 3 دقائق، أو
- p95 latency > 800ms لمدة 5 دقائق
قلّل count عندما:
- CPU < 30% AND Memory < 40% لمدة 10 دقائق
الحدود:
- min_count: 2
- max_count: 10
- scale_up_cooldown: 60s
- scale_down_cooldown: 300s
```
**مثال في `.ghaymah.json`:**
```json
{
"count": 2,
"autoscaling": {
"enabled": true,
"min": 2,
"max": 10,
"metrics": [
{ "type": "memory", "target": 75, "duration": "3m" },
{ "type": "cpu", "target": 70, "duration": "3m" }
]
}
}
```
### 5.2 Vertical Scaling (VPA-lite)
```
ارفع size عندما:
- Memory > 85% على ALL instances لمدة 5 دقائق
- OOMKill حدث مرة واحدة على الأقل
مسار الترقية:
t1 (512 MiB) → ρ (768 MiB) → ρ-l (1 GiB) → ρ-xl (2 GiB)
لا تُخفِض size تلقائياً — يدوي فقط بعد مراجعة 7 أيام
```
### 5.3 سياسة منع OOMKilled
```
1. memory_limit = observed_peak × 1.3 (هامش 30%)
2. إذا restart_count > 2 في 5 min → scale up فوراً (count +1 أو size +1)
3. rolling deploy: لا تزيد أكثر من 50% من الحاويات دفعة واحدة
4. Graceful shutdown: SIGTERM grace period = 30s قبل SIGKILL
```
### 5.4 Flowchart
```text
Memory > 75% لـ 3 min?
├─ نعم → count + 1 (حتى max)
└─ لا → استمر
OOMKill detected?
├─ نعم → size + 1 فوراً + alert P0
└─ لا → استمر
Memory > 85% على كل instances?
├─ نعم → size + 1
└─ لا → OK
```
---
## 6. الكشف المبكر — أدوات مراقبة غيمة
### 6.1 RasidAI Monitoring
- مراقبة real-time للتطبيقات على غيمة
- **تنبيهات مقترحة:**
- Memory utilization > **80%** لمدة 2 دقيقة → Warning
- Memory utilization > **90%** لمدة 1 دقيقة → Critical
- Container restart > **3** في 10 دقائق → Critical
- Health probe failures > **2** متتالية → Critical
### 6.2 Logs (JSON — 30 يوم retention)
```bash
gy logs app nodeapp-production --env production --follow
```
**ما نبحث عنه:**
```text
OOMKilled
Exit code 137
FATAL ERROR: Reached heap limit
JavaScript heap out of memory
```
- كل log يحتوي **trace-id** — نربط الطلبات قبل الانهيار
- Dashboard في RasidAI: رسم memory usage vs limit over time
### 6.3 Health & Retry Probes
غيمة تدعم HTTP/TCP probes:
```json
"healthCheck": {
"path": "/health",
"interval": 10,
"timeout": 5,
"unhealthyThreshold": 2
}
```
**تحسين `/health`:**
```javascript
app.get('/health', (req, res) => {
const used = process.memoryUsage().heapUsed / 1024 / 1024
if (used > 400) return res.status(503).json({ status: 'degraded', memory_mb: used })
res.json({ status: 'ok', memory_mb: used })
})
```
→ الحاوية تخرج من LB **قبل** OOMKill
### 6.4 CLI — فحص سريع
```bash
gy resource app status --env production
gy resource app logs --env production --tail 100
```
### 6.5 لوحة مراقبة (Dashboard)
| Metric | Threshold Warning | Threshold Critical |
|--------|-------------------|---------------------|
| Memory % | 80% | 90% |
| CPU % | 70% | 85% |
| Restart count / 10min | 1 | 3 |
| p95 latency | 500ms | 1000ms |
| Error rate (5xx) | 1% | 5% |
### 6.6 كيف كان يمكن اكتشافها قبل الانقطاع؟
```text
14:18 Memory 78% → ⚠️ Warning alert (كان سيُرسل)
14:20 Memory 85% → 🔴 Critical alert
14:22 OOMKill → 🔴 Auto scale-up + P0 page
14:30 Outage → ❌ لم يحدث (في الواقع)
```
**الفجوة:** لم تكن التنبيهات مفعّلة → **MTTD 13 دقيقة بدلاً من 2 دقيقة**.
---
## 7. الدروس المستفادة
1. **OOMKilled = Exit 137** — أول شيء نفحصه في logs بعد أي restart غير متوقع
2. حد الذاكرة يجب أن يُحسب من **P99 + 30%** وليس من التقدير
3. Auto-scaling أفقي **و** عمودي معاً — HPA وحده لا يكفي إذا leak في كل instance
4. Health endpoint يجب أن يفحص **memory** وليس `return 200` فقط
5. RasidAI + alerts = MTTD أقل من 5 دقائق → يمنع 45 دقيقة outage
---
## 8. المراجع
- [Ghaymah Cloud — التوسع التلقائي](https://ghaymah.systems/)
- Ghaymah Programs Features — `count:`, `size:`, Health Probes, RasidAI
- SLA غيمة: 99.9% uptime per region