السلسلة: هذا الدرس جزء من برنامج «أساسيات Linux 2026». للحصول على نظرة شاملة، اقرأ الدليل الرئيسي أولاً.
مقدمة
مسؤول النظام الجيّد لا يخمّن. يلاحظ، يصوغ فرضية، يختبر، يستنتج، ويوثّق. هذا الدرس يفصّل منهج تشخيص Linux الذي ينقل المبتدئ المتخبّط إلى مشغّل يعزل السبب في خمس عشرة دقيقة — منهج أثبت جدارته عبر عشرات الآلاف من حوادث الإنتاج. يتركّز في خمس خطوات مرتّبة تطبّقها دون انحراف في كل مرة، لأن الانضباط المنهجي خير ترياق للذُّعر. سنوضّحه على حالة واقعية: موقع يُرجع فجأة أخطاء 502 رغم أنه كان يعمل قبل ساعة.
المتطلبات
- خادم Linux وحساب مع صلاحيات sudo (Ubuntu 24.04/26.04 LTS، Debian 13، AlmaLinux 9، Rocky Linux 9).
- معرفة الأدوات من باقي دروس البرنامج: journalctl، systemctl، ss، ps، top.
- المستوى: متوسط.
- المدة المقدّرة: 90 دقيقة.
الخطوة 1 — عزل النطاق
قبل أي أمر، اطرح السؤال: من المتأثّر، أين، ومنذ متى؟ عطل «كل شيء معطوب» يُحلّ غير عطل «فقط مستخدمو أوروبا» أو «فقط منذ نشر الساعة 14:30». هذه المرحلة الأولى تستغرق دقيقتين وتُسقط نصف المسارات الخاطئة.
# هل الخادم متاح أصلاً؟
ping -c 4 adresse-du-serveur
# هل الخدمة تجيب محلياً وليس من الخارج؟
ssh user@serveur
curl -I http://localhost/
# متى بدأ الحادث؟
last reboot
last -F | head -5
journalctl --since "1 hour ago" | head -50
أربعة أسئلة تُطرح بالترتيب. أولاً: هل يمسّ العطل عنواناً واحداً، خدمة واحدة، آلة واحدة، أم البيئة كلها؟ إذا كانت خدمة واحدة فقط، تكسب 80% من النطاق. ثانياً: هل العطل قابل للتكرار؟ خطأ 502 متقطّع يحكي قصة مختلفة عن 502 منهجي. ثالثاً: ماذا تغيّر مؤخراً؟ نشر، تحديث حزم، مهمة cron نُفّذت، تدوير سجلات. مخرَج journalctl --since "1 hour ago" | grep -i "Started\|Stopped" يسرد أحداث systemd في الساعات الأخيرة. رابعاً: هل يمسّ العطل موارد أخرى غير المفترضة؟ إذا أبطأت قاعدة البيانات في الوقت نفسه مع الموقع، فعلى الأرجح لديك سبب نظامي مشترك (قرص ممتلئ، ذاكرة مشبعة).
الخطوة 2 — قراءة السجلات
في 80% من الحوادث، السبب الدقيق مكتوب في السجل بوضوح، شريطة معرفة أين تنظر. لا تكتب أمر تعديل واحد قبل قراءة السجلات الحديثة — هذا أغلى خطأ زمناً وأكثرها إغراءً تحت الضغط.
# حالة Nginx 502: نبدأ بالخدمة الأكثر تعرّضاً
sudo journalctl -u nginx -n 200 --no-pager
# سجلات أخطاء Nginx (الملف الكلاسيكي)
sudo tail -100 /var/log/nginx/error.log
# والتطبيق خلفه؟
sudo journalctl -u mon-api -n 200 --no-pager
# النظام كاملاً على آخر ساعة، مستوى خطأ أو أعلى
sudo journalctl -p err --since "1 hour ago" --no-pager
اقرأ من الأحدث إلى الأقدم، باحثاً عن علامات: «FATAL»، «ERROR»، «connection refused»، «out of memory»، «no such file». 502 Nginx مع رسالة connect() failed (111: Connection refused) while connecting to upstream في error.log تشخيص كامل: Nginx يحاول بلوغ التطبيق على socket، والتطبيق لا يستمع. يبقى معرفة لماذا — إما تعطّل، أو لم يبدأ أبداً، أو صار يستمع في مكان آخر. ثلاثة أسئلة فرعية تُحفر في الخطوة 4. إن لم يظهر شيء بديهي، وسّع: journalctl --since "30 min ago" بلا مرشّح، قد ترى حدثاً جانبياً (OOM، قرص يشكو، تحديث آلي).
الخطوة 3 — التحقق من الموارد
الانعكاس الثاني، قبل سبر الكود التطبيقي: التحقق من سلامة الموارد الأساسية. عطل تطبيقي نادراً ما يكون نتيجة باغ أُدخل قبل خمس دقائق؛ بل غالباً نتيجة إشباع بطيء ينتهي بسحب كل شيء.
df -h # القرص، كل الأقسام
df -i # inodes — إشباع غير مرئي بـ df -h وحده
free -h # ذاكرة مستخدمة / متاحة
uptime # متوسط الحمل 1/5/15 دقيقة
vmstat 1 5 # CPU وswap في حركة
iostat -xz 1 5 # قرص حسب الجهاز (حزمة sysstat)
أربع عتبات تصلح إنذارات. قرص فوق 90%: Postgres، MariaDB، Nginx يبدؤون بإخفاق كتاباتهم، أحياناً صامتاً. inodes مشبَعة (df -i فوق 95%): استحالة إنشاء ملفات جديدة حتى لو قال df -h إن المساحة متاحة — نمطية لخوادم البريد أو cache سيّئة الإعداد. swap نشط (si/so في vmstat غير صفرية): الآلة تترحّل وتنهار كلما زادت زمن قرص. حمل أكبر من ضعف عدد الأنوية في متوسط 5 دقائق: إشباع CPU أو IO مستدام. إن كان أي إنذار إيجابياً، فلديك السبب النظامي؛ صحّحه قبل لمس الكود.
الخطوة 4 — اختبار الطبقات واحدة واحدة
بعد استبعاد الأسباب النظامية، انزل منهجياً عبر طبقات الخدمة المعطّلة. لحالة Nginx 502، التسلسل النموذجي: Nginx يعمل؟ يستمع على المنفذ الصحيح؟ التطبيق خلفه يعمل؟ يستمع على socket الصحيح؟ الجدار الناري يمرّر؟ الإعداد صالح؟
# خدمة Nginx حية؟
sudo systemctl status nginx
sudo nginx -t # صحة الإعداد
# Nginx يستمع على 80/443؟
sudo ss -tlnp | grep nginx
# التطبيق خلفه حي؟
sudo systemctl status mon-api
sudo ss -tlnp | grep ':3000'
# اختبار طرف لطرف محلي، بقفز Nginx
curl -v http://localhost:3000/
# الجدار الناري؟
sudo ufw status
sudo iptables -L -n
خمس نتائج محتملة، خمسة تصحيحات. إذا قال systemctl status mon-api «failed»، فسبب الإخفاق في journalctl -u mon-api (الخطوة 2 ثانياً). إذا اشتغل التطبيق لكنه لا يستمع على المنفذ المتوقّع، فإعداده ربما تغيّر أو البيئة تبدّلت. إذا أجاب محلياً وليس عبر Nginx، انظر إعداد upstream في Nginx — تغيّر منفذ من جانب التطبيق دون تحديث Nginx يحدث هذا العَرَض حرفياً. إذا حجب الجدار الناري، فالقاعدة ربما أُضيفت خطأ؛ sudo ufw status numbered يدرج القواعد بترتيبها. في كل خطوة، صدِّق بأمر اختبار (curl، ss، systemctl status) قبل الانتقال.
الخطوة 5 — التوثيق أثناء وبعد
الانضباط الذي يحوّل تشخيصاً إلى رأسمال تشغيلي: تمسك ملفاً مع تدفّق الأحداث، لا بعدها. افتح محرّراً موازياً لجلسة SSH وسجّل: الطابع الزمني، الفرضية، الأمر المُشغَّل، النتيجة. خمس دقائق من التدوين أثناء الحادث تختصر ساعة من إعادة البناء إن تكرّر بعد ستة أشهر.
# حادث 2026-05-04 — Nginx 502 على الإنتاج
**ساعة البدء**: 14:32 UTC
**ساعة النهاية**: 14:51 UTC
**الأثر**: 100% من الطلبات بخطأ 502 لمدة 19 دقيقة
## التسلسل الزمني
- 14:32 — تنبيه uptime monitor على https://exemple.com
- 14:34 — اتصال SSH بالخادم، ping/curl OK
- 14:35 — journalctl -u nginx -n 100 ← "connect() failed (111)"
- 14:36 — systemctl status mon-api ← failed (status=137)
- 14:37 — journalctl -u mon-api -n 200 ← "JavaScript heap out of memory"
- 14:38 — journalctl -k -b | grep oom ← OOM Killer قتل PID 1247 (mon-api)
- 14:40 — free -h ← 50 ميغا حرة، swap على 90%
- 14:42 — فرضية: تسرب ذاكرة في نشر 13:00
- 14:45 — تراجع النشر إلى الإيداع السابق
- 14:48 — systemctl restart mon-api ثم restart nginx
- 14:51 — الخدمة عادت OK
## السبب الجذري
انحدار ذاكرة أدخلته PR #4521 المدمجة عند 12:55. التسرّب مؤكَّد بالتنقيب في pre-prod.
## إجراءات تصحيحية
- [x] تراجع في الإنتاج (14:48)
- [ ] إصلاح التسرّب قبل إعادة النشر (PR #4528)
- [ ] إضافة MemoryMax=1G في mon-api.service لتحديد الحوادث المقبلة
- [ ] إنذار على الذاكرة المتاحة < 100 ميغا
هذا التنسيق البسيط — تسلسل زمني، سبب جذري، إجراءات — كافٍ لتسعة حوادث من عشرة. لا تقع في فخّ post-mortem مصقول مكتوب لاحقاً: ذاكرة التفاصيل التشغيلية تتبخّر في ساعات. أمسك الوثيقة أثناء التدخل. للمنظمات الأكثر تنظيماً، نموذج 5 Whys (خمسة لماذا متتالية) أو RCA رسمي ينطبق على هذا الأساس. ملف الحوادث المحفوظ في Git يصير خلال ستة أشهر أفضل تدريب ممكن للقادمين الجدد.
الخطوة 6 — حالات واقعية وأنماط متكرّرة
إلى جانب حالة Nginx 502، تعود بعض الأنماط مراراً في السنة. التعرف عليها في الدقيقة الأولى يكسبك عشرات الساعات على مدى مسيرة. هذه الأكثر تواتراً وتوقيعاتها.
| العرض | التشخيص السريع | السبب النموذجي |
|---|---|---|
| موقع يصبح بطيئاً نهاية الشهر | df -h وjournalctl --disk-usage |
سجلات لم تُدوَّر، قرص على 95% |
| خطأ 502 دقائق بعد كل نشر | journalctl -u app -n 200 |
Healthcheck تطبيقي صارم جداً، التطبيق لا يجد الوقت ليبدأ |
| اتصالات SSH بطيئة (10-30 ث) | ssh -v من العميل |
Reverse DNS يفشل، أضف UseDNS no على الخادم |
| cron صامت لا يُنفَّذ | journalctl -u cron --since today |
زمن الخادم منحرف، NTP مكسور، timedatectl |
| خدمة تتعطل مرة كل يوم بنفس الساعة | اربط بـ journalctl --since "08:00" --until "09:00" |
Backup أو updatedb يشبع IO القرص |
دفتر شخصي للأنماط - الأعراض - الأسباب - التصحيحات هو من أكثر الأدوات مردوديةً التي يمكن للمشغّل بناؤها. بعد سنة، تفتح ملفك، تكتب بضع كلمات مفاتيح، فتقع على حادث مشابه من العام الفائت مع حلّه. هذه الممارسة تستبدل ذاكرة فردية، وهي أسوأ دعامة للمعرفة التشغيلية.
الخطوة 7 — تقليص نصف قطر التأثير للتصحيحات
تحت الضغط، الإغراء قوي لـ«إعادة تشغيل كل شيء لنرى». هذا النهج له عيبان رئيسيان: يخفي السبب الجذري (الذي سيعود)، وقد يفاقم الحادث إذا كان لاعتمادية دقيقة ترتيب محدّد. الانضباط المهني يقتضي تطبيق تصحيحات متناسبة وعكوسة، بالترتيب.
أولاً، فضّل systemctl reload على systemctl restart حين تدعمها الخدمة (Nginx، sshd، postfix، بعض الخدمات التطبيقية). reload لا يقطع الاتصالات الجارية ونادراً ما يكون له أثر جانبي. ثانياً، أعد تشغيل خدمة واحدة في كل مرة، راقب السجل ثلاثين ثانية، ثم انتقل. ثلاث خدمات تُعاد متوازية تتشارك اعتمادية يمكن أن تدخل حلقة. ثالثاً، احتفظ بطريق تراجع صريح: إن عدّلت ملف إعداد، أنشئ نسخة مؤرَّخة (cp file.conf file.conf.bak.20260504-1432) قبل التعديل، ودوّن أمر التراجع كتعليق في سجل الحادث. رابعاً، تجنّب إعادة تشغيل الخادم بأكمله إلا كحلّ أخير: قد يكشف reboot ملفات غير دائمة، نقاط ربط مكسورة، قواعد جدار ناري غير محفوظة، فتحوّل حادثاً من ساعة إلى عطل يوم.
الخطوة 8 — التحقق النهائي
بعد كل تشخيص، صادق صراحةً على أن الخدمة عادت إلى حالتها الاسمية قبل إغلاق الجلسة. خدمة تبدو OK في 14:51 ثم تعود للتعطّل في 14:53 تشخيص فاشل. تسلسل التحقق المعياري يقع في خمسة أوامر.
systemctl status nginx mon-api # نشط ومستقر منذ بضع دقائق
journalctl -u nginx -u mon-api --since "5 min ago" -p err # لا أخطاء حديثة
curl -I https://exemple.com # 200 منتظر
curl -s -o /dev/null -w "%{time_total}s\n" https://exemple.com # كمون معقول
df -h && free -h # موارد سليمة
إن أعادت كل الأوامر حالة سليمة، أغلق الحادث، حدّث سجلّك، وأرسل الملاحظة الختامية لأصحاب الشأن. إن أخفقت إحداها أو أظهرت إشارة ضعيفة، ابق على المرسى خمس عشرة دقيقة إضافية — الانتكاسة أكثر شيوعاً مما يُظن، وفي تلك اللحظة بالذات ينعكس الانضباط الرقابي. هذه الخطوة الأخيرة، يهملها كثيراً المبتدئون، هي ما يحوّل تشخيصاً عادياً إلى تشخيص جيّد.
الأخطاء الشائعة
| الخطأ | السبب | الحل |
|---|---|---|
| «إعادة تشغيل كل شيء» عمياء | ذعر، انعدام منهج | فرض قراءة السجلات قبل أي أمر تعديل |
| تشخيص يقطعه زميل | تواصل موازي غير مُنظَّم | أعلن «أنا في journalctl، أعطي نقطة بعد 5 دقائق» |
| الخلط بين سبب جذري وعَرَض | وقف التشخيص عند أول اكتشاف | اسأل «لماذا؟» ثلاث مرات حتى سبب قابل للتنفيذ |
| تعديل غير موثَّق | ضغط، نسيان | إمسك سجل الحادث بالتوازي مع جلسة SSH |
| التحقق النهائي منسي | ارتياح مبكّر | نفّذ تسلسل الخطوة 8 قبل إغلاق الجلسة |
دروس ذات صلة
- journalctl: قراءة واستغلال السجلات
- عمليات Linux: ps، top، htop، kill، إشارات
- العودة إلى الدليل الرئيسي: أساسيات Linux 2026
الأسئلة الشائعة
كم من الوقت أخصّص للتشخيص قبل استدعاء زميل؟
القاعدة العملية: خمس عشرة إلى ثلاثين دقيقة وحدك، ثم اطلب المساعدة. أبعد من ذلك، التعب الإدراكي يجلب الأخطاء والنظرة الطازجة لزميل تسرّع الحلّ. للحوادث الحرجة ذات الأثر على المستخدم، لا تنتظر — زميل من الدقيقة الثالثة يقاسمك الضغط ويضاعف احتمال رؤية الخيط الذهبي في السجلات.
هل نوثّق حتى الحوادث الصغيرة؟
نعم، خاصة هي. الحوادث الكبيرة دائماً تنال post-mortem؛ الصغيرة هي التي تُنسى وتعود. خمسة أسطر في ملف incidents.md بتاريخ، عَرَض، سبب، تصحيح كافية — الأهم الاستيفاء لا الشكلانية. بعد ستة أشهر، البحث في هذا الملف يصبح الأداة الأسرع في صندوقك.
كيف نتدرّب على التشخيص دون كسر الإنتاج؟
ثلاث ممارسات. أولاً، قراءة post-mortems العامة للبنى الكبرى (Cloudflare، GitHub، Vercel، Discord ينشرون باستمرار) — أكثر دروس الأستاذة المتاحة. ثانياً، تنظيم game days على بيئة اختبار: زميل يُدخل عطلاً عمداً، وأنت تشخّصه مع الساعة. ثالثاً، تدوين كل الحوادث التي تحلّها، حتى مصادفة؛ في ثلاثة أشهر، لديك كتالوغك الشخصي.
أي إشارات ضعيفة نراقب لتوقّع الحوادث؟
أربع مقاييس تستحق وزنها: نمو القرص (قرص ينمو خطياً وسيُملأ خلال X يوماً)، كمون p99 لـ API (مضاعفة تدريجية تنبئ بمختنق قادم)، معدل أخطاء 5xx (انجراف بطيء أكثر إنذاراً من قمّة معزولة)، ومتوسط الحمل 15 دقيقة في ساعة الذروة (منحناه على ستة أشهر يكشف إن كانت الآلة تعيش شهورها الأخيرة). لوحة قيادة بسيطة بهذه المنحنيات الأربع تنقلك من تشخيص رد فعل إلى توقّع.
كيف ندير حادثاً خارج ساعات العمل؟
ثلاثة مبادئ. أولاً، اعرف إن كان الحادث يستوجب تدخلاً فورياً: فقدان رقم الأعمال أو البيانات يبرّر إيقاظك، تباطؤ أداة داخلية ينتظر الصباح. ثانياً، احتفظ بـ runbook محدَّث يسمح لمشغّل وردية، حتى قليل الإلمام، باتّخاذ الحركات الصحيحة (إعادة تشغيل خدمة، تصعيد، تواصل مع المستخدمين). ثالثاً، بعد كل صحوة ليلية، اسأل: لماذا لم يُتجنَّب هذا الحادث، وكيف نتفادى تكراره؟
متى نتخلّى وندعو دعم المضيف؟
حين لا تكشف أوامرك على الخادم شيئاً شاذاً لكن الاتصال أو الأداء متدهور. MTR يُظهر فقد حزم على القفزات الأولى (تلك في مركز البيانات)، إدخال/إخراج قرص بطيء شاذ دون حمل تطبيقي، أو كمون نحو خوادم أخرى للمضيف نفسه: إشارات حادث على البنية التحتية. فتح تذكرة بقياسات دقيقة (timestamps، traceroute، iperf3) يسرّع كثيراً الحلّ لدى الدعم.