# 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