تخيّل لوحة القيادة في سيارة. العدادات (السرعة، دوران المحرك، مستوى الوقود) تعطي قيمة رقمية في كل لحظة : هذه هي المقاييس. الصندوق الأسود، أي مسجّل الأحداث في سيارة حديثة، يدوّن ما حدث، سطراً بسطر، مع الوقت الدقيق : هذه هي السجلات (logs). المصابيح التحذيرية (الزيت، البطارية، المحرك) تضيء وحدها عندما تخرج قيمة مراقَبة عن نطاقها الطبيعي، دون أن تضطر إلى التحديق في كل عداد باستمرار : هذه هي التنبيهات. نظام GPS، الذي يعيد رسم المسار الكامل الذي سلكته مع الوقت المستغرق في كل مقطع، هو التتبع (trace). تعود هذه الصورة في الوحدة بأكملها : كل خدمة في المختبر تلعب دور إحدى هذه القطع الأربع.
| قطعة لوحة القيادة | ما تمثله | خدمة المختبر التي تلعب هذا الدور |
|---|---|---|
| العدادات | المقاييس | Prometheus (الذي يقرأ node-exporter وcadvisor وAPI) |
| الصندوق الأسود | السجلات | Loki، الذي يغذيه Alloy |
| المصابيح التحذيرية | التنبيهات | Alertmanager، الذي يُخطر webhook |
| GPS الذي يعيد رسم المسار | التتبعات | لا شيء في هذا المختبر (يُذكر في الوحدة 7) |
| الزجاج الأمامي | ما تنظر إليه أنت | Grafana |
لا نراقب نظاماً من باب المتعة. نراقبه لأن شيئاً ما سينكسر يوماً ما، وسيلزم فهم ماذا وأين ومنذ متى، قبل أن يكلّف ذلك غالياً. الأعطال الثلاثة أدناه عامة : كل شركة كتبت ونشرت بنفسها تقرير ما بعد الحادث (post-mortem) الخاص بها. إنها تُظهر ما تتيحه قابلية المراقبة، وما لا تتيحه دائماً من المحاولة الأولى.
Cloudflare، 18 نوفمبر 2025 : عندما لا تكفي المقاييس وحدها. في الساعة 11:20 بالتوقيت العالمي، توقفت شبكة Cloudflare عن توجيه جزء كبير من الحركة العالمية بشكل صحيح : زوار مواقع عملائها يتلقون صفحة خطأ. السبب : تغيير في الصلاحيات على عنقود قاعدة بيانات ClickHouse ضاعف حجم ملف إعداد داخلي (ملف « الخصائص » لنظام مكافحة الروبوتات)، الذي تجاوز حداً مثبتاً في الكود وتسبب في انهيار الوكيل المركزي. مقاييس أخطاء HTTP 5xx مرئية منذ الدقيقة الأولى، في قمة واضحة على الرسم البياني. لكن الملف لم يكن يُولَّد بشكل معيب إلا بصورة متقطعة، وعلى جزء فقط من العنقود : كانت الحركة تعود ثم تسقط في العطل كل خمس دقائق. هذا التذبذب جعل الفريق يعتقد في البداية أن الأمر يتعلق بهجوم حجب خدمة، لا بعطل داخلي. كان لا بد من مقاطعة المقاييس مع سجلات وحدة مكافحة الروبوتات لتحديد السبب الحقيقي. عادت الحركة الرئيسية في 14:30، وعادت كل الأنظمة إلى طبيعتها في 17:06 : قرابة 5 ساعات و46 دقيقة بين بداية الحادث ونهايته الكاملة. المصدر الرسمي : Cloudflare outage on November 18, 2025.
AWS S3، 28 فبراير 2017 : عندما تعتمد أداة الإشراف على النظام الذي تراقبه. في الساعة 9:37 (بتوقيت المحيط الهادئ)، نفّذ مهندس في Amazon S3 أمر صيانة كان من المفترض أن يسحب بضعة خوادم من نظام فرعي للفوترة، في منطقة فرجينيا الشمالية (us-east-1). خطأ في الكتابة سحب عدداً من الخوادم أكبر بكثير مما كان مخططاً وأسقط نظامين فرعيين حرجين في S3 : الفهرس (البيانات الوصفية وموقع الكائنات) والتوزيع (تخصيص التخزين الجديد). أصبح S3 عاجزاً عن معالجة طلبات GET وLIST وPUT وDELETE، وسقطت معه عمليات التشغيل الجديدة لمثيلات EC2 وEBS وLambda، ولوحة حالة AWS الرسمية نفسها، التي كانت تعتمد على S3 لتحديث نفسها. اضطرت AWS إلى إبلاغ حالة العطل عبر حسابها على Twitter. عاد الفهرس بالكامل في 13:18، والتوزيع في 13:54 : حوالي 4 ساعات و17 دقيقة بين بداية الحادث والعودة إلى الوضع الطبيعي. المصدر الرسمي : Summary of the Amazon S3 Service Disruption in the Northern Virginia (US-EAST-1) Region.
GitHub، 14 أغسطس 2024 : عندما يُطلق الإشراف نفسه العطل. في الساعة 22:59 بالتوقيت العالمي، نشرت GitHub تغييراً في الإعداد على قواعد بياناتها. هذا التغيير كسر قدرة هذه القواعد على الاستجابة بشكل صحيح لفحوصات الصحة (health checks) المرسلة من طبقة التوجيه. ولعدم تلقيها استجابة صالحة، أعلنت طبقة التوجيه أن هذه القواعد « في حالة سيئة » وسحبت صلاحية القراءة : أصبح GitHub.com غير متاح لجميع المستخدمين من 23:02 إلى 23:38 بالتوقيت العالمي، أي 36 دقيقة. صحّح الفريق الأمر بإلغاء تغيير الإعداد، ثم أكّد عبر مراقبة مستمرة أن الاتصال قد عاد قبل إغلاق الحادث في 00:30 من اليوم التالي. النقطة التي يجب تذكرها : ليس غياب الإشراف هو ما تسبب في العطل، بل إحدى آليات الإشراف نفسها، أي فحص الصحة، الذي أطلقه بسبب سوء إعداده. المصدر الرسمي : GitHub Availability Report: August 2024.
تتقاطع الأعطال الثلاثة في نقطة واحدة : في الحالات الثلاث، عرفت الشركة بسرعة كبيرة أن شيئاً ما لا يسير على ما يرام (مقاييس الأخطاء تتحرك في ثوانٍ). ما يستغرق وقتاً هو معرفة لماذا. وهذا بالضبط ما يجعلك مختبر هذه الدورة تبنيه، على نطاق صغير، على جهازك.
المراقبة (monitoring) تتابع مؤشرات مختارة مسبقاً، بعتبات معروفة سلفاً : « معدل الأخطاء يتجاوز 5 % ». وهي فعالة لعطل سبق أن رأيناه. قابلية المراقبة (observabilité) هي القدرة على فهم الحالة الداخلية لنظام انطلاقاً من الإشارات التي ينتجها أصلاً (مقاييسه وسجلاته وتتبعاته)، بما في ذلك لسؤال لم نتوقعه، دون إعادة نشر كود للبحث عنه. المراقبة تقول « شيء ما لا يسير على ما يرام » ؛ قابلية المراقبة تساعد على الإجابة « لماذا، وأين، ومنذ متى ».
| المصطلح | التعريف في جملة واحدة | أين نجده في المختبر |
|---|---|---|
| المراقبة (Monitoring) | متابعة مؤشرات معروفة مسبقاً والتنبيه عند تجاوز عتبة. | القواعد العشر في prometheus/regles/alertes.yml (الوحدة 6) |
| قابلية المراقبة (Observabilité) | فهم الحالة الداخلية لنظام انطلاقاً من مقاييسه وسجلاته وتتبعاته، حتى لسؤال غير متوقع. | مجموعة Prometheus وLoki وGrafana في المختبر |
| مقياس (Métrique) | قيمة رقمية تُقاس على فترات منتظمة، وتشكّل سلسلة زمنية. | http_requetes_total، التي يعرضها API على /metrics |
| سجل (Log) | رسالة مؤرخة يكتبها برنامج في لحظة محددة لوصف حدث. | سطر JSON يكتبه API على مخرجه القياسي، يقرؤه journal api |
| تتبع (Trace) | المسار الكامل لطلب عبر عدة خدمات، مع مدة كل مرحلة. | مذكور في هذه الدورة، غير مجهَّز في هذا المختبر (الوحدة 7) |
| تنبيه (Alerte) | إشعار تلقائي يُرسل عندما تبقى حالة مقاسة صحيحة لمدة معينة. | APIInjoignable، الذي يوجهه Alertmanager نحو webhook |
| SLI (Service Level Indicator) | قياس كمي لمستوى الخدمة المُلاحَظ فعلياً. | معدل استجابات 5xx لـ API على 5 دقائق (api:taux_erreurs_5m) |
| SLO (Service Level Objective) | الهدف الداخلي المحدد على SLI، على فترة معينة. | « أقل من 5 % من الأخطاء » : عتبة التنبيه TauxErreursEleve |
| SLA (Service Level Agreement) | الالتزام التعاقدي تجاه العميل، مع عقوبة في حالة عدم الاحترام. | خارج المختبر : بند في عقد مع عميل |
مرجع تعريفات SLI وSLO وSLA : Google SRE Book — Service Level Objectives. لقابلية المراقبة من منظور أدوات الدورة : Prometheus — Overview وGrafana — Observability.
الفرق الجوهري بين المراقبة وقابلية المراقبة : المراقبة تجيب عن أسئلة مكتوبة مسبقاً (« هل يتجاوز معدل الأخطاء 5 % ؟ »). قابلية المراقبة تتيح طرح سؤال لم نتوقعه (« أي الطلبات استغرقت أكثر من 500 مللي ثانية بين 19:33 و19:34 ؟ ») والحصول على الجواب انطلاقاً مما سجّله النظام أصلاً.
grep على الخادم أو استعلام SQLقبل Prometheus وGrafana، كان فريق المنصة يتصل عبر SSH بالخادم ويكتب grep ERROR /var/log/api.log. هذا يعمل، لجهاز واحد، وملف واحد، ولحظة واحدة. لكن :
grep لا يرى إلا ما هو مكتوب على هذا الخادم، في هذا الملف. مع عدة حاويات لـ API تعمل بالتوازي، يجب الاتصال بكل واحدة والمقاطعة يدوياً.grep لا يحتفظ بأي تاريخ خارج الملف الحالي : عندما يدور الملف (log rotation) أو تعاد تشغيل الحاوية، يضيع ما لم يُقرأ.grep لا يحسب أي اتجاه : يعرض أسطراً، لا منحنى « نسبة الأخطاء خلال الدقائق الخمس الأخيرة ».SELECT count(*) FROM inscriptions) يقول كم عدد التسجيلات الموجودة الآن. لا يقول شيئاً عن كمون طلبات HTTP، ولا عن معدل الخطأ، ولا عن حالة الحاويات : هذه المعلومات ليست في هذه القاعدة.grep ولا استعلام SQL يُخطر أحداً تلقائياً. يجب تذكّر تشغيلهما، مراراً وتكراراً، أو انتظار شكوى مستخدم.تجيب قابلية المراقبة عن هذه النواقص : تمركز المقاييس والسجلات من جميع المثيلات، وتحتفظ بتاريخ قابل للاستعلام، وتحسب الاتجاهات، وتُخطر تلقائياً، دون انتظار طرح السؤال.
تنضم إلى الفريق الذي يشغّل منصة الدورات عبر الإنترنت المستخدمة في الدورات الأخرى من الكتالوج. قلب النظام هو API، API الكتالوج، مكتوب بلغة Python مع FastAPI، ويعرض 64 دورة (من C0001 إلى C0064) على المسارات /cours و/cours/{id} و/inscriptions و/lent و/sante و/metrics. برنامج ثانٍ، مولّد الحمل (الخدمة charge)، يستدعي هذا الـ API باستمرار، كما يفعل مئات الطلاب وهم يتصفحون الكتالوج، أو يسجلون في دورة، أو يقعون على صفحة لم تعد موجودة.
تطرح رئيسة فريقك سؤالاً بسيطاً، لكن لا يجيب عنه أي grep ولا أي استعلام SQL دفعة واحدة : « هل يعمل ؟ لمن ؟ منذ متى ؟ ولماذا ينكسر ؟ » لا تريد الاتصال بالخادم. تريد لوحة معلومات يمكنها فتحها بنفسها، وتنبيهاً يُخطرها قبل أن يكتب طالب ليشتكي.
هذا هو الخيط الناظم للدورة. كل وحدة تضيف قطعة : المقاييس وPromQL (الوحدة 2)، وتجهيز API نفسه بالقياس (الوحدة 3)، ولوحات معلومات Grafana (الوحدة 4)، والسجلات مع Loki (الوحدة 5)، والتنبيهات التي تُخطر قبل الشكوى (الوحدة 6). الوحدة 7 تجمع كل شيء. وفي كل مرحلة، يتيح لك المختبر كسر جزء من المنصة عمداً (.\labo.ps1 casser api وcasser erreurs وcasser lenteur وcasser disque) لتتعلم قراءة العطل في الأدوات قبل إصلاحه.
| الخدمة (اسم الحاوية) | الدور | المنفذ على جهازك |
|---|---|---|
api (labo-api) | الخدمة المراقَبة : /cours و/inscriptions و/sante، ومقاييسها الخاصة على /metrics | 8000 |
charge (labo-charge) | يحاكي طلاباً يستخدمون المنصة، حتى يكون هناك شيء لمراقبته | لا شيء |
prometheus (labo-prometheus) | يجلب (scrape) مقاييس كل خدمة كل 15 ثانية، ويخزنها كسلاسل زمنية، ويقيّم قواعد التنبيه | 9090 |
alertmanager (labo-alertmanager) | يستقبل التنبيهات التي يطلقها Prometheus، ويجمعها، ويوجهها نحو مستقبِل | 9093 |
webhook (labo-webhook) | يستقبل تنبيهات Alertmanager ويعرضها : ما سيتلقاه نظام المناوبة | 8090 |
alloy (labo-alloy) | يكتشف حاويات Docker وينقل سجلاتها نحو Loki | 12345 |
loki (labo-loki) | يخزن السجلات ويفهرسها حسب التسميات (labels)، لا حسب نصها الكامل | 3100 |
node-exporter (labo-node-exporter) | يعرض مقاييس الجهاز المضيف (CPU، الذاكرة، القرص) بصيغة Prometheus | 9100 |
cadvisor (labo-cadvisor) | يعرض مقاييس كل حاوية (CPU، الذاكرة، الشبكة) بصيغة Prometheus | 8080 |
grafana (labo-grafana) | واجهة موحدة لاستكشاف وعرض Prometheus وLoki وAlertmanager | 3000 (GRAFANA_PORT) |
لم تثبّت المختبر بعد : هذا عمل الدرسين 03 و04. هذه الخطوات تجعلك تقرأ أربع مخرجات حقيقية، مأخوذة من جهاز الدورة، حتى تتعرف على مقياس وسجل وتنبيه عندما تنتجها بنفسك. أبقِ هذه الصفحة مفتوحة أثناء الدرس 04 : ستجد كل واحدة من هذه المخرجات الأربع على الشاشة.
مقياس، كما يقرؤه Prometheus. كل 15 ثانية، يستدعي Prometheus العنوان http://api:8000/metrics. إليك أربعة أسطر من هذه الصفحة، على جهاز الدورة :
# HELP http_requetes_total Nombre de requêtes HTTP reçues, par méthode, route normalisée et code de réponse.
# TYPE http_requetes_total counter
http_requetes_total{code="200",methode="GET",route="/cours"} 3247.0
http_requetes_total{code="500",methode="GET",route="/cours"} 32.0ما يجب رؤيته : للمقياس اسم (http_requetes_total)، وتسميات بين أقواس معقوفة (code وmethode وroute)، وقيمة (3247.0). السطران لهما الاسم نفسه لكن تسميات مختلفة : إنهما سلسلتان متمايزتان. السطر # TYPE … counter يقول إن هذا الرقم لا يفعل سوى الازدياد. الدرس 02 يفصّل الأنواع الأربعة.
سجل، كما يكتبه API. يكتب API سطر JSON لكل طلب على مخرجه القياسي. .\labo.ps1 journal api يعرضها ؛ إليك سطرين منها، على جهاز الدورة :
labo-api | {"horodatage": "2026-09-15T19:33:25.839+00:00", "niveau": "INFO", "id_requete": "46bb533b33e9", "methode": "GET", "route": "/cours/{id}", "code": 200, "duree_ms": 13.9, "message": "GET /cours/C0038 -> 200"}
labo-api | {"horodatage": "2026-09-15T19:33:14.781+00:00", "niveau": "ERROR", "id_requete": "dc1c2ff189a6", "methode": "GET", "route": "/cours/{id}", "code": 500, "duree_ms": 0.1, "message": "GET /cours/C0019 -> 500"}ما يجب رؤيته : السجل هو حدث محدد (هذا الطلب بعينه، في هذه اللحظة بعينها، للدورة C0038)، بينما مقياس الخطوة 1 هو تراكم (3247 طلباً ناجحاً على /cours منذ بدء التشغيل). الحقل id_requete يحدد طلباً فريداً ؛ القيمة نفسها تُعاد إلى العميل في ترويسة HTTP x-id-requete. السطر الثاني خطأ 500 : ينتج المختبر عمداً 1 % منها في التشغيل العادي.
تنبيه، كما يستقبله فريق المناوبة. عندما يتوقف API (casser api)، لا يستطيع Prometheus قراءة /metrics، فتنتقل القاعدة APIInjoignable إلى firing بعد 30 ثانية، ويرسلها Alertmanager إلى webhook. إليك ما يحتويه http://localhost:8090/alertes.json حينها، على جهاز الدورة :
{"recu_a":"2026-09-15T19:41:26+00:00","etat":"firing","nom":"APIInjoignable","severite":"critique","service":"api","resume":"L'API catalogue ne répond plus","description":"Prometheus n'arrive plus à lire http://api:8000/metrics depuis 30 secondes (cible api:8000).","debut":"2026-09-15T19:41:11.496Z","fin":"0001-01-01T00:00:00Z"}ما يجب رؤيته : للتنبيه اسم، وخطورة، وملخص يقرؤه الإنسان، وحالة firing (إنه يرن). الحقل fin يحمل تاريخاً فارغاً ما دام التنبيه جارياً ؛ بعد reparer، يصل إشعار ثانٍ مع "etat":"resolved" وتاريخ نهاية حقيقي. لم يضطر أحد إلى تحديث صفحة : المصباح أضاء وحده.
النظرة الشاملة، في أمر واحد. .\labo.ps1 etat يلخص حالة الخدمات العشر والإشراف. على جهاز الدورة، في التشغيل العادي :
== Supervision ==
✔ Prometheus répond — cibles up : 8/8
séries en mémoire : 12350
alertes : 0 active(s), 0 en attente (pending)
✔ Alertmanager répond (http://localhost:9093)
✔ Grafana répond (http://localhost:3000)
✔ Loki répond (http://localhost:3100)
✔ API catalogue répond — version 1.0.0, 64 cours
✔ Webhook répond — 0 alerte(s) reçue(s) (http://localhost:8090)
Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.ما يجب رؤيته : 8/8 cibles up (يقرأ Prometheus ثماني صفحات /metrics : الخدمات العشر ناقص charge وwebhook، اللتين لا تعرضان أي صفحة)، و12350 سلسلة في الذاكرة (يختلف هذا الرقم من جهاز إلى آخر)، و0 alertes actives. هذا هو السطر الذي يجب أن تجده في نهاية كل تمرين في الدورة.
القاعدة التي تربط المقياس بالتنبيه. لم يخرج تنبيه الخطوة 3 من العدم : إنه مكتوب في ملف من الحقيبة، prometheus/regles/alertes.yml، الذي يقيّم Prometheus كل قاعدة فيه كل 15 ثانية (evaluation_interval: 15s في prometheus/prometheus.yml). إليك الأولى من القواعد العشر، كما هي في الحقيبة :
groups:
- name: api-catalogue
rules:
- alert: APIInjoignable
expr: up{job="api"} == 0
for: 30s
labels:
severite: critique
service: api
annotations:
resume: "L'API catalogue ne répond plus"
description: "Prometheus n'arrive plus à lire http://api:8000/metrics depuis 30 secondes (cible {{ $labels.instance }})."ما يجب رؤيته : expr هو مقياس (up، الذي يصنعه Prometheus بنفسه عند كل قراءة : 1 إذا استجاب الهدف، و0 خلاف ذلك) مقارَن بقيمة ؛ for: 30s هي المدة التي يجب أن تبقى فيها الحالة صحيحة قبل أن يرن التنبيه ؛ resume وdescription هما بالضبط النص الذي عرضه webhook في الخطوة 3، مع استبدال {{ $labels.instance }} بـ api:8000. التنبيه هو مقياس وعتبة ومدة : لا أكثر. الوحدة 6 ستجعلك تكتب تنبيهاتك الخاصة.
هذا الدرس لا يجعلك تثبّت شيئاً، لكن ثلاثة التباسات تعود منذ الدرس 04. الرسائل أدناه استُحضرت فعلياً على جهاز الدورة.
« API معطل، إنه يجيب بـ 404 » : لا. الاستجابة 404 هي استجابة سليمة من خدمة تعمل وتقول « هذا المورد غير موجود ». في المختبر، http://localhost:8000/cours/C9999 يجيب :
HTTP 404 {"detail":"cours C9999 introuvable"}أما API متوقف فعلاً فلا يجيب بأي شيء على الإطلاق. أثناء casser api، يعيد curl http://localhost:8000/sante :
curl: (7) Failed to connect to localhost:8000 after 2237 ms: Could not connect to serverوInvoke-RestMethod http://localhost:8000/sante تحت PowerShell : Le délai de l'opération a expiré. (انتهت مهلة العملية). الاستجابة 404 هي سجل بمستوى WARNING ومقياس بـ code="404" ؛ أما API متوقف، فهو up{job="api"} بقيمة 0.
« لا يوجد أي تنبيه، الإشراف لا يعمل » : في Prometheus، يعيد المقياس ALERTS نتيجة فارغة عندما يكون كل شيء على ما يرام. على جهاز الدورة، في التشغيل العادي، يجيب API الاستعلام :
{"status":"success","data":{"resultType":"vector","result":[]}}"status":"success" مع "result":[] : الاستعلام صحيح، ببساطة لا يوجد ما يُعرض. هذا هو الوضع الطبيعي، وليس عطلاً. ALERTS لا يحتوي على سلسلة إلا لتنبيه pending أو firing.
« المقياس والسجل هما المعلومة نفسها » : لا. المقياس http_requetes_total{code="500",methode="GET",route="/cours/{id}"} 27.0 يقول إنه كانت هناك 27 خطأً على هذا المسار منذ بدء التشغيل، دون أن يقول أيّها. السجل "GET /cours/C0019 -> 500" مع "id_requete": "dc1c2ff189a6" يقول بدقة أيّها. المقياس رخيص ويُعدّ ؛ السجل مفصّل ويُقرأ. الوحدة 5 تربطهما عبر الحقل id_requete.
المراقبة تتابع عتبات معروفة مسبقاً ؛ قابلية المراقبة تتيح فهم عطل لم نتوقعه، انطلاقاً من المقاييس والسجلات والتتبعات التي ينتجها النظام أصلاً. المقياس رقم يُقاس في الزمن، له اسم وتسميات وقيمة (http_requetes_total{code="200",methode="GET",route="/cours"} 3247.0). السجل حدث مؤرخ، سطر JSON لكل طلب في المختبر، مع id_requete فريد. التنبيه يُخطر تلقائياً عندما تبقى حالة صحيحة مدة كافية (APIInjoignable بعد 30 ثانية من تعذر الوصول إلى API) ويصل إلى webhook بحالة firing ثم resolved. لوحة قيادة السيارة تلخص كل شيء : العدادات = المقاييس، الصندوق الأسود = السجلات، المصابيح التحذيرية = التنبيهات، GPS = التتبعات، الزجاج الأمامي = Grafana. لا grep على خادم واحد ولا استعلام SQL على قاعدة الأعمال يمركز التاريخ أو يحسب اتجاهاً أو يُخطر تلقائياً. الاستجابة 404 هي الاستجابة السليمة لخدمة تعمل ؛ أما API متوقف فلا يجيب بشيء وup يساوي 0. الخيط الناظم للدورة هو منصة الدورات عبر الإنترنت، وAPI الكتالوج الخاص بها بـ 64 دورة، ومولّد الحمل، وخدماتها العشر.
casser وreparer./metrics في المختبر : أنواع المقاييس الأربعة، والتسميات، والعدد الكلي (cardinalité)، ونموذج pull، والبنية الدقيقة لسطر سجل JSON.