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

Load average: ثلاثة أرقام وسوء فهم شائع

uptime
cat /proc/loadavg
nproc

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

العلاقة بين الأرقام الثلاثة تعطي الاتجاه. قيمة الدقيقة الواحدة أعلى بوضوح من قيمة خمس عشرة دقيقة تعني أن الحمل يتصاعد الآن. والعكس يعني أن الذروة مضت وأن ما تراه هو ذيلها.

والآن سوء الفهم الذي يفسد قراءة هذه الأرقام أكثر من أي شيء آخر. إن load average في لينكس ليس «استخدام المعالج». فخلافًا لأنظمة يونكس الأخرى، يحسب لينكس فيه لا العمليات التي تعمل أو الجاهزة للعمل فحسب، بل أيضًا تلك التي في الحالة D — النوم غير القابل للمقاطعة. أي انتظار القرص أو نظام ملفات عبر الشبكة. من هنا يأتي الخادم الذي يبلغ حمله 12 بينما معالجه شبه خامل: العمل لا يتقدم، والجميع في الطابور.

المعالج أم القرص

الفصل بين هاتين الحالتين أول ما يستحق العمل:

vmstat 1 5
iostat -x 1 3

في مخرجات vmstat تهم ثلاثة أعمدة. العمود r هو عدد العمليات المنتظرة في طابور المعالج، وb عدد المحجوبة بانتظار الإدخال والإخراج، وwa نسبة الوقت الذي قضاه المعالج خاملًا في انتظار القرص. استقرار wa فوق 10–15 % مع قيم متواضعة في us وsy يعني أن القرص هو ما يقيّد الخادم: إضافة أنوية بلا فائدة، فالموجود منها فارغ أصلًا.

ويمكن سرد العمليات المنتظرة بالاسم:

ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'

مثال من ممارستنا الخاصة. تكتب Suricata بالإعداد الافتراضي نحو ثلاثين نوعًا من الأحداث ولا تضبط لها أي تدوير — على خادم عامل أعطى ذلك 15 غيغابايت من السجلات في يومين. ولم يظهر الحمل حينها في صورة معالج مشغول بل في صورة I/O wait تحديدًا: كان النظام يكتب بلا توقف، وكل ما عداه ينتظر خلفه في الطابور. والعلاج ليس باقة أكبر، بل قائمة أقصر من أنواع الأحداث وتدوير مضبوط.

الحالة المعاكسة، معالجية بحتة وأقل وضوحًا بكثير. كانت صفحة ويب تستدعي apt باسم المستخدم الذي يعمل به PHP-FPM. يحتفظ الجذر بذاكرة مخبّأة ثنائية في /var/cache/apt/pkgcache.bin — وعلى مضيف فيه عشرات المستودعات تبلغ 70 ميغابايت — ويربطها بالذاكرة بلا كلفة. أما المستخدم العادي فلا يستطيع الكتابة في ذلك الدليل ويعيد بناء المخبأ عند كل استدعاء. القياس على الجهاز نفسه: 0,01 ثانية من زمن المعالج بصلاحية الجذر مقابل 4,2 ثانية بمستخدم بلا صلاحيات. الأمر ذاته، وفارق أربعمائة ضعف، مضروبًا في كل فتح للصفحة.

الخلاصة من الحالتين واحدة: الحمل يُقاس ولا يُخمَّن. قياس زمن كل أمر مشبوه على حدة يستغرق نصف ساعة ويشير عادة إلى غير ما بدأ منه الشك.

الذاكرة: free لا يعرض ما يبدو أنه يعرضه

free -h

العمود used وحده لا يقول شيئًا يُذكر، والعمود free مضلل صراحةً: يمنح لينكس الذاكرة غير المستخدمة لمخبأ الصفحات ويعيدها إلى التطبيقات عند أول طلب. العمود الذي يُقرأ هو available — أي كم يمكن شغله دون الذهاب إلى swap. أما buff/cache الكبير فليس مشكلة بل علامة على نظام يعمل كما ينبغي.

في swap لا تهم القيمة الحالية بل الشكل. ارتفع وعاد إلى الصفر: كانت ذروة قصيرة. ارتفع مرة وبقي: الذروة حدثت بالفعل، وأُزيحت صفحات ولا أحد يعيدها — يبدو الخادم هادئًا رغم أن الذاكرة لم تكفه في لحظة ما. وهل يجري التبديل الآن؟ يظهر ذلك في عمودي si وso في vmstat؛ والقيم غير الصفرية هناك هي صورة البطء التي يلحظها المستخدمون أكثر من غيرها.

وإذا اختفت عملية ببساطة أثناء الانهيار الليلي، فالتفسير عادةً هنا:

journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"

سطر مثل Out of memory: Killed process 1234 (mysqld) يحسم المسألة أفضل من أي رسم بياني: قاعدة البيانات لم «تسقط من تلقاء نفسها»، بل أوقفتها النواة لأن الذاكرة نفدت.

من الذي يفعل ذلك

ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10

تحفّظ واحد: قيمة %CPU في ps متوسط على عمر العملية كله، فتضيع الومضة القصيرة في تلك القائمة. ولها يلزم top أو pidstat 1 5 اللذان يقيسان على فترة.

متى يصبح الحمل مسألة أمنية

استهلاك ثابت للمعالج بنسبة 100 % ليلًا، مع عملية اسمها بلا معنى ودليل عملها في /tmp أو /dev/shm، صورة كلاسيكية لمُعدِّن لا لموقع نما. وارتفاع حاد في حركة الوارد مع تزايد الكتابة في السجلات هجوم كلمات مرور جارٍ. أما حجم السجلات الذي يقفز فجأة فهو عادةً عاصفة من الإنذارات الكاذبة لأحد المرشِّحات.

وأدوات الحماية نفسها فئة قائمة بذاتها. على أحد خوادمنا ظل الحمل عند ثلاثة تقريبًا دون أي زائر، وفي صدارة ps بحسب زمن المعالج المتراكم لم يكن الموقع ولا قاعدة البيانات، بل CrowdSec و fail2ban و Falco و Suricata. ليس هذا عطلًا ولا سببًا لإيقافها، لكن معرفة ثمن الحماية بالأرقام مفيدة: على خادم افتراضي صغير يكون ملموسًا.

الغاية من المراقبة

كل ما سبق يجيب عن سؤال «ماذا يحدث الآن». أما سؤال الصباح — ماذا جرى في الثالثة فجرًا — فلا تغطيه هذه الأوامر: لا توجد بيانات عن الليلة الماضية إن لم يسجلها أحد. وإقامة Prometheus مع Grafana من أجل خادم افتراضي واحد أمر مشكوك فيه، لأن المنظومة المراقِبة تخرج أثقل من الخادم المراقَب.

يكفي سطر في قاعدة بيانات كل خمس دقائق وصفحة واحدة ترسم منه آخر أربع وعشرين ساعة: load average واستخدام المعالج و I/O wait منفصلًا، والذاكرة و swap، والقراءة والكتابة على القرص، وامتلاء القسم، وعُقد الملفات، ومعرِّفات الملفات، والاتصالات. على محور زمني واحد تُقرأ الأزواج بالعين المجردة: wa مرتفع مع معالج هادئ، و swap لم يعد إلى الصفر قط، ومعرِّفات تقترب من الحد — فيصبح خطأ too many open files القادم مرئيًا قبل ساعات من وقوعه. وكيف يبدو ذلك مجتمعًا تعرضه صفحة العرض التوضيحي أدناه.