One self-hosted console to run your entire business — commerce, ERP, HRM, CRM & manufacturing

المراقبة (Observability) للأنظمة عالية الحمل: سجلات ومقاييس وتتبّع يمكنك البناء عليها

معرّف طلب، وسجلات منظّمة في OpenSearch، وأربع إشارات ذهبية، وتتبّع بالعيّنات، وتنبيهات مرتبطة بأثر المستخدم: المجموعة الصغيرة التي تكشف الطبقة البطيئة في دقائق، مع طريقة مراقبة اختبار الحمل ويوم الحدث.

Author

Anichur Rahaman

منذ 6 أيام12 min read2 views
المراقبة (Observability) للأنظمة عالية الحمل: سجلات ومقاييس وتتبّع يمكنك البناء عليها

«العملاء يقولون إن صفحة الدفع تتجمد». هكذا كتب فريق الدعم لمسؤول المنصة في موقع لبيع التذاكر عند الساعة 10:01 صباح يوم الإطلاق. بدأ البيع في العاشرة، ونقر نحو ألف شخص في الدقيقة نفسها، وكانت الخطة تفترض 440 طلبًا في الثانية. لوحة المتابعة تُظهر المعالج عند 40% ولا شيء أحمر.

أي طبقة هي البطيئة؟ مسار واحد أم عقدة واحدة أم عميل واحد؟ إن اعتمدت على واجهة إدارة وتخمين، ذهبت الدقائق العشر التالية في الجدل. وإن كان لديك معرّف طلب وبضعة أرقام مختارة بعناية، ذهبت في بحث واحد. (هذا المشهد توضيحي وليس حادثة حقيقية.)

لا تحتاج إلى منصة ضخمة لذلك. تحتاج إلى معرّف طلب، وسجلات منظّمة، والإشارات الذهبية الأربع، وتنبيهات مرتبطة بأثر المستخدم. في منصة جهّزتها لذروة مجدولة يتحرك فيها نحو ألف مستخدم في الدقيقة نفسها، كانت الخوادم بخير؛ وما كاد يؤذينا هو أن أحدًا لم يستطع أن يقول بسرعة أي طبقة هي البطيئة، ولا إن كان الرقم المخيف حقيقيًا. يبني هذا المقال المجموعة الصغيرة التي تجيب عن هذه الأسئلة، ثم يوضح كيف تراقب بها اختبار حمل ويوم الحدث.

هذا هو الجزء الرابع من سلسلة من خمسة أجزاء بعنوان «هندسة الأنظمة عالية الحمل». الجزء الأول عن ما الذي يتوسع فعلًا، والثاني عن الطوابير والعمّال، والثالث عن طبقة البيانات. أما هذا الجزء فموضوعه رؤية كل ذلك بالعين.

الـ observability في فقرة واحدة

المراقبة التقليدية تخبرك أن شيئًا ما معطوب. أما الـ observability فتتيح لك أن تسأل «لماذا؟» دون أن تنشر كودًا جديدًا أولًا. وهي تقوم على ثلاثة أنواع من البيانات تُسمّى إشارات:

  • السجلات (logs): سجل واحد لكل حدث مع تفاصيله. الأنسب لسؤال «ماذا حدث بالضبط لهذا الطلب؟»
  • المقاييس (metrics): أرقام تُؤخذ عبر الزمن. الأنسب لسؤال «هل يزداد الوضع سوءًا، وبأي سرعة؟»
  • التتبّع (traces): مسار طلب واحد عبر كل الخدمات، مع الوقت المستغرق في كل خطوة. الأنسب لسؤال «أين ذهب الوقت؟»

لا تحتاج إلى الثلاثة من اليوم الأول، ولا إلى منصة باهظة. ما تحتاجه هو أن تكون مترابطة، فتنتقل من metric أحمر إلى سجلات وtrace طلب بطيء بعينه. والخيط الذي يربطها هو معرّف الطلب (request ID).

ابدأ بمعرّف طلب يصمد عبر كل محطة

أرخص تحسين أعرفه هو معرّف واحد يرافق الطلب من الحافة إلى آخر مهمة في الطابور. في الإعداد الذي شغّلته، يحترم nginx ترويسة X-Request-Id الواردة أو ينشئ واحدة، ويمررها إلى PHP-FPM، ويكتبها كلاهما في سجلاتهما. ثم يضيفها التطبيق إلى كل سطر سجل، وينسخها إلى حمولة أي مهمة يرسلها، فيمكن ربط مهمة في الخلفية بالنقرة التي أطلقتها.

أعد المعرّف نفسه في ترويسة الاستجابة. وعندما يبلّغ عميل أو موظف دعم عن مشكلة، تكشف تلك السلسلة وحدها القصة كاملة.

مخطط يتتبع طلبًا واحدًا بمعرّفه من CDN وموازن الحمل وnginx وPHP-FPM والتطبيق ومهمة الطابور في بحث واحد داخل OpenSearch
معرّف طلب واحد تكتبه كل طبقة يحوّل خمسة ملفات سجل منفصلة إلى جدول زمني واحد.

أين يجب أن يظهر المعرّف

الطبقةما العمل
الحافة / CDNمرّر المعرّف الوارد، أو اترك الطبقة التالية تنشئه
nginx على المضيف وnginx داخل الحاويةأعد استخدام المعرّف الوارد، وأنشئ واحدًا إن لم يوجد، واكتبه في access log
PHP-FPM والتطبيقاقرأه من الترويسة وأرفقه بكل سطر سجل كسياق مشترك
مهام الطابورخزّنه في حمولة المهمة واستعده عند تشغيلها
استدعاءات HTTP الصادرةأرسله إلى الجهة التالية ليسجّله الشركاء والخدمات الداخلية أيضًا
الاستجابةأعده كترويسة ليطلبه الدعم الفني

سجلات منظّمة تصل إلى ELK أو OpenSearch

السجلات النصية العادية كُتبت ليقرأها إنسان واحدًا تلو الآخر. أما عند الحمل العالي فتحتاج إلى البحث فيها وعدّها وتصفيتها، وهذا يعني كائن JSON واحدًا في كل سطر بحقول مسمّاة. تكفي في البداية مجموعة قصيرة وثابتة من الحقول.

الحقللماذا يستحق مكانه
timeالترتيب والمطابقة مع المقاييس
request_idالخيط الذي يربط كل الطبقات
route أو path (من دون query string)تجميع الطلبات البطيئة حسب نقطة النهاية لا حسب الرابط الخام
statusنسبة الأخطاء لكل نقطة نهاية
durationالمادة الخام لحساب p95 وp99
upstream timeالتمييز بين «nginx بطيء» و«PHP بطيء»
user أو tenant id (معرّف داخلي، وليس بريدًا إلكترونيًا أبدًا)معرفة ما إذا كان عميل واحد هو سبب المشكلة

عن التسمية: ELK هو الاسم الشائع لثلاث أدوات هي Elasticsearch وLogstash وKibana، ثم أضافت حزمة Elastic Stack الأوسع ناقلات خفيفة تُسمّى Beats. وقد بدأ OpenSearch عام 2021 كنسخة متفرعة (fork) مرخّصة بـ Apache من Elasticsearch وKibana أطلقتها AWS، وفي سبتمبر 2024 انتقل إلى مؤسسة OpenSearch Software Foundation تحت مظلة Linux Foundation. لم يعد الاثنان متطابقين، لكن مسار العمل مع السجلات واحد: أرسِل، فهرِس، ابحث، ارسم. ولهذا يقول الناس «متوافق مع ELK».

لا تحتاج إلى عنقود كبير. في إعدادي، احتفظت عقدة OpenSearch صغيرة بذاكرة 2 غيغابايت ومعالج افتراضي واحد بسجلات منصة تتعامل مع ذروة حادة. هذا إعداد واحد وليس معيارًا عامًا، لكنه يوضح أن الكلفة صغيرة مقارنة بأول عطل تشخّصه في دقائق بدل ساعات.

ما الذي لا يجوز تسجيله

السجلات تُنسخ وتُفهرس وتُحفظ شهورًا، ولذلك فهي خطر على حماية البيانات. أخفِ كلمات المرور والرموز وبيانات البطاقات والتفاصيل الشخصية الكاملة قبل أن يغادر أي سطر التطبيق. سجّل المعرّفات الداخلية بدل الأسماء أو البريد أو أرقام الهواتف. واحذف الـ query string من المسارات لأنها كثيرًا ما تحمل رموزًا.

مدة الاحتفاظ ودورة حياة الفهارس

تدوير الفهارس يوميًا مع دورة حياة تلقائية يُبقي العقدة الصغيرة سليمة: تبقى الأيام الأخيرة قابلة للبحث، وتُضغط الفهارس الأقدم أو تُنقل، ويُحذف كل ما تجاوز مدة الاحتفاظ. حدّد المدة مع من يملكون ملف الخصوصية والأمن، ولا تخمّنها. ثلاثون يومًا من السجلات المفصلة نقطة بداية شائعة، والجواب الصحيح يعتمد على لوائحك.

المقاييس: الإشارات الذهبية الأربع

يسمّي كتاب Google «Site Reliability Engineering»، في فصله عن مراقبة الأنظمة الموزعة، أربع إشارات تغطي تقريبًا أي خدمة موجهة للمستخدمين. إن لم تستطع قياس غير أربعة أشياء، فقِس هذه.

الإشارةالسؤال الذي تجيب عنهفي منصة ويب وعمّال
Latency (زمن الاستجابة)كم يستغرق الطلب؟p50 وp95 وp99 لكل route، مع تتبع الطلبات الفاشلة على حدة
Traffic (الحركة)كم حجم الطلب؟طلبات في الثانية عند الحافة، ومهام مرسلة في الثانية
Errors (الأخطاء)ما نسبة الفشل؟نسبة 5xx، والمهل المنتهية، والمهام الفاشلة
Saturation (الإشباع)ما مدى امتلاء أضيق مورد؟عمّال FPM المشغولون، وعمق الطابور وعمره، واتصالات قاعدة البيانات، وذاكرة Redis

تحذيران. الأول: لا تضبط التنبيهات ولا تخطط على المتوسطات، فالمتوسط السليم يخفي ذيلًا مرعبًا. في اختبار حمل أجريته على واجهة أمامية تُرسم من جهة الخادم، تشبّعت عملية واحدة عند نحو 220 إلى 250 طلبًا في الثانية، وقفز p95 من نحو 260 ms إلى نحو 3 ثوانٍ، بينما ظلت أنوية المضيف خاملة. كان المتوسط سيبدو مقبولًا لفترة. أما الـ percentile فقال الحقيقة.

الثاني: الإشباع هو نقطة بداية المتاعب، وهو نادرًا ما يكون المعالج. في منصة كهذه أراقب هذه الأمور أولًا:

  • عمّال PHP-FPM المشغولون مقارنة بحد المجموعة الأقصى. حين يلامس الحد، تصطف الطلبات في nginx.
  • عمق الطابور وعمره لكل طابور. العمق يقول كم ينتظر، والعمر يقول كم تأخرت فعلًا.
  • اتصالات قاعدة البيانات ومعدل الكتابة، لا المعالج وحده.
  • ذاكرة Redis وعمليات الإخلاء لكل دور (cache وsessions وqueues).
  • الذاكرة لكل حاوية، لأن قتل العملية بسبب نفاد الذاكرة يبدو من الخارج كخطأ عشوائي.

التتبع مع OpenTelemetry

السجلات والمقاييس تخبرك أن الطلب كان بطيئًا. أما الـ trace فيخبرك أنه قضى 40 ms في nginx و90 ms في PHP و1.2 ثانية ينتظر استعلامًا واحدًا و30 ms في Redis. وفي نظام فيه طبقة واجهة أمامية وطبقة خلفية وعمّال، هذه أسرع طريقة لتحديد المحطة المسؤولة.

OpenTelemetry هو المعيار المحايد تجاه الموردين لإنتاج هذه البيانات. وبحسب صفحة حالة المواصفة الخاصة به، فإشارتا التتبع والسجلات مستقرتان، وكذلك واجهة المقاييس وبروتوكولها ونموذج بياناتها، بينما يتفاوت نضج حزم SDK الخاصة بكل لغة. ويوثّق مشروع PHP توفر التتبع والمقاييس والسجلات، مع امتداد اختياري للقياس التلقائي. تحقق من حالة المكتبات التي ستستخدمها بالتحديد قبل أن تلتزم.

نصيحتي أن تتبنّاه بهذا الترتيب. تأكد أولًا من وجود معرّف الطلب. ثم تتبّع المسار الحرج فقط، مثل الدفع أو تقديم النموذج، مع أخذ عينات: الاحتفاظ بكل trace عند الحمل العالي يكلّف أكثر مما يعلّم. احتفظ بكل traces الأخطاء والطلبات البطيئة، وبجزء صغير من الباقي. وضع معرّف الـ trace في أسطر السجل بجوار معرّف الطلب، لتتصل الأداتان ببعضهما.

أهداف مستوى الخدمة (SLO) وتنبيهات ذات معنى

ينبغي أن يجيب التنبيه عن سؤال واحد: هل يحتاج شخص إلى التحرك الآن؟ استخدام المعالج 85% نادرًا ما يستدعي ذلك. أما «الدفع يفشل عند 2% من المستخدمين» فيستدعيه دائمًا. هدف مستوى الخدمة يجعل ذلك محددًا: هدف مثل «99% من طلبات الدفع تنجح خلال أقل من ثانيتين على مدى 30 يومًا»، مع ميزانية أخطاء للباقي.

نوقظ شخصًا من أجلتذكرة أو رسالة دردشة تكفي من أجل
نسبة أخطاء الدفع تتجاوز حد استهلاك SLOقرص يمتلئ ببطء
p95 لمسار حرج فوق الهدف لعدة دقائقعقدة واحدة بمعالج مرتفع دون تأثر المستخدمين
عمر طابور التقديمات في ازديادمهمة واحدة فشلت ثم نجحت بعد إعادة المحاولة
المهام الفاشلة ترتفع بسرعةشهادة تنتهي بعد ثلاثة أسابيع

مثال محسوب يوضح السبب. لنفترض أن الدفع يتلقى 3,000,000 طلب في 30 يومًا وأن الهدف نجاح 99%، فتكون ميزانية الأخطاء 30,000 طلب فاشل أو بطيء جدًا. خلال ذروة مدتها عشر دقائق بمعدل 440 طلبًا في الثانية تخدم 264,000 طلب. إن فشل 2% منها فهذا يعني 5,280 إخفاقًا، أي نحو 18% من ميزانية الشهر كله تُستهلك في عشر دقائق. هذا تنبيه يستدعي إيقاظ شخص، مهما قال المعالج. (أرقام توضيحية.)

كل تنبيه يوقظ أحدًا بلا سبب يعلّم الفريق تجاهل التنبيه التالي. راجع التنبيهات بعد كل حدث، واحذف الصاخب منها أو خفّض مرتبته.

لوحة يوم الحدث

لأي ذروة مجدولة أبني شاشة واحدة فقط. في الأعلى الإشارات الذهبية للمسارات الحرجة، وتحتها أرقام الإشباع، وبجانبها عمق الطابور وعمره، وخط يبيّن معدل الطلبات المستهدف. لا شيء غير ذلك. لوحة تحتاج إلى تمرير لن يقرأها أحد في دقيقة الذروة.

مخطط تقريبي للوحة يوم الحدث بألواح الزمن والحركة والأخطاء والإشباع، مع عمق الطابور وعمره واتصالات قاعدة البيانات وذاكرة Redis
شاشة واحدة لدقيقة الذروة: الإشارات الذهبية الأربع أولًا، ثم الموارد التي تنفد.

ضع علامة نشر (deploy marker) على كل رسم بياني. نصف «التراجعات الغامضة» إصدار نزل قبل عشر دقائق.

مراقبة اختبار الحمل

اختبار الحمل أرخص بروفة ستحصل عليها، وتضيع قيمته إن لم تستطع أن ترى ما بداخله. أعد تشغيل مزيج الطلبات الحقيقي لذروة سابقة بدل ضرب رابط واحد. في اختباراتي استخدمت k6 مع حدود إيقاف: توقف إذا تجاوز p95 ثلاث ثوانٍ، أو عند أي خطأ 5xx أو مهلة منتهية. وكان سكربت حارس صغير يوقف التشغيل إذا بلغ المعالج حدوده، حتى لا يتحول الاختبار إلى انقطاع فعلي.

  1. حدّد حدود الإيقاف قبل التشغيل الأول، واكتبها.
  2. شغّل اللوحة التي ستستخدمها يوم الحدث، لا عرضًا خاصًا بالاختبار.
  3. ضع ترويسة على حركة الاختبار لتتمكن من تصفيتها في السجلات.
  4. قارن مقاييسك بمقاييس مزوّد السحابة. في تشغيلاتي اتفقت خلال نسبة مئوية قليلة؛ وإن لم تتفق مقاييسك فأحدهما خاطئ.
  5. اعثر على أول مورد يتشبع، وأصلحه، ثم أعد التشغيل بالمعدل المستهدف.
  6. احتفظ بالنتائج بجوار الكود ليبدأ الحدث التالي من خط أساس.

تحقق من التنبيه المخيف قبل أن تتصرف

تحت الضغط يغري المرء أن يتحرك مع كل ما هو أحمر. تحقق أولًا. بعض الواجهات تسمّي الحاويات تسمية خاطئة، وقد يشير تنبيه «100% CPU» إلى عملية غير التي توشك أن تعيد تشغيلها. انظر إلى قائمة العمليات الفعلية، وقارنها بمصدر ثانٍ، ثم قرّر.

مخطط انسيابي: يُطلق التنبيه؛ إن لم توافقه أي إشارة موجهة للمستخدم فتحقق من العملية الفعلية ومن مصدر ثانٍ؛ وإن وافقته فتراجع عن الإصدار إذا نُشر قبل أقل من 15 دقيقة، وإلا فابحث عن أول مورد متشبع وأصلحه ثم راجع اللوحة
إلى أين يذهب التنبيه الأحمر بعد ذلك: معظم العمل هو الحكم بأنه حقيقي أم لا.

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

لنعد إلى 10:01. مع هذه المنظومة تصل رسالة الدعم ومعها معرّف الطلب. يُظهر بحث واحد أن nginx انتظر PHP مدة 1.31 ثانية، وأن التطبيق سجّل استعلامًا بطيئًا في الطلب نفسه. وتؤيد اللوحة ذلك: p95 في ارتفاع و48 من 60 عاملًا في FPM مشغولون. أما تنبيه المعالج الأحمر الوحيد فيخص حاوية أخرى، فلا يعيد أحد تشغيل شيء. يعرف المسؤول السبب في نحو دقيقتين بدل عشر، ويذهب الإصلاح إلى المكان الصحيح. (وهذا أيضًا توضيحي.)

في الجزء الأخير من هذه السلسلة أتناول النصف الآخر من البقاء على الخط: تأمين الحافة ونشر التغييرات دون أي توقف.

أهم الخلاصات

  • أضف معرّف طلب عند الحافة ومرّره عبر nginx وPHP-FPM وسجلات التطبيق ومهام الطابور. إنه أرخص مكسب كبير.
  • اكتب سجلات JSON منظّمة بمجموعة قصيرة وثابتة من الحقول، وأخفِ البيانات الشخصية، وحدّد مدة الاحتفاظ عن قصد.
  • قِس الإشارات الذهبية الأربع، واستخدم النسب المئوية (percentiles) بدل المتوسطات، وراقب الإشباع: العمّال وعمر الطابور والاتصالات والذاكرة.
  • اعتمد تتبع OpenTelemetry على المسار الحرج فقط، مع أخذ العينات، واربط معرّفات الـ trace بسجلاتك.
  • أيقظ الناس فقط عند أثر على المستخدمين مرتبط بـ SLO، وقلّم التنبيهات الصاخبة بعد كل حدث.
  • تدرّب مع حدود إيقاف، وقارن بمقاييس مزوّدك، وتحقق من أي تنبيه مخيف قبل التصرف بناءً عليه.

Anichur Rahaman مهندس برمجيات معماري ومؤسس StoreConsole، يصمّم أنظمة التجارة وERP للشركات النامية، ويهتم خصوصًا بالبنية القائمة على الأحداث وسلامة البيانات وتشغيل الأنظمة على خوادم الشركة نفسها.

About the Author

Anichur Rahaman

Continue Reading