remove postmortem

هذا الالتزام موجود في:
ayashosha
2026-07-29 05:23:45 +03:00
الأصل d699d53a16
التزام 6ce9a8cacf

عرض الملف

@@ -1,273 +0,0 @@
# 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