پرسش تقریباً همیشه یکسان است: شب سایت بیست ثانیه طول میکشید تا پاسخ دهد و تا صبح همه چیز خودبهخود درست شد. دیگر چیزی برای دیدن نمانده است — top دربارهٔ ثانیهٔ جاری پاسخ میدهد، در حالی که پرسش دربارهٔ ساعت سه بامداد است. در ادامه: اعداد بار واقعاً چه معنایی دارند، کدامیک باید جفتی خوانده شوند و چرا یک اندازهگیری تکی بیشتر گمراه میکند تا کمک.
Load average: سه عدد و یک بدفهمی رایج
uptime
cat /proc/loadavg
nproc
این سه عدد میانگین یک، پنج و پانزده دقیقه هستند. آنها را نه با صفر، بلکه با تعداد هستههایی که nproc نشان میدهد باید سنجید. مقدار ۸ روی ماشینی با هشت هسته باری کامل اما سالم است: دقیقاً همانقدر کار هست که سرور از پس آن برمیآید. مقدار ۲ روی یک VPS تکهستهای صفی دو برابر ظرفیت است و هر درخواست نوبت خود را میکشد.
نسبت این سه عدد به یکدیگر جهت را نشان میدهد. مقدار یکدقیقهای بهروشنی بالاتر از مقدار پانزدهدقیقهای یعنی بار همین حالا در حال بالا رفتن است. برعکس آن یعنی اوج گذشته است و شما دم آن را میبینید.
و اکنون بدفهمیای که بیش از هر چیز خواندن این اعداد را خراب میکند. load average در لینوکس «میزان استفاده از پردازنده» نیست. برخلاف دیگر سامانههای یونیکسی، لینوکس نه فقط فرایندهای در حال اجرا یا آمادهٔ اجرا، بلکه فرایندهای در وضعیت D — خواب وقفهناپذیر — را هم در آن میشمارد. یعنی آنهایی که منتظر دیسک یا یک سامانهٔ فایل شبکهاند. سرور با بار ۱۲ و پردازندهٔ تقریباً بیکار از همینجا میآید: کار پیش نمیرود، همه در صف ایستادهاند.
پردازنده یا دیسک
جدا کردن این دو حالت نخستین کار ارزشمند است:
vmstat 1 5
iostat -x 1 3
در خروجی vmstat سه ستون اهمیت دارند. r یعنی چند فرایند در صف پردازندهاند، b یعنی چند فرایند در انتظار ورودی و خروجی مسدود شدهاند و wa سهم زمانی است که پردازنده بیکار مانده و منتظر دیسک بوده است. wa پایدار بالای ۱۰ تا ۱۵ درصد با us و sy اندک یعنی سرور به دیسک گیر کرده است: افزودن هسته بیفایده است، هستههای موجود هم آزادند.
اینکه کدام فرایندها منتظرند، نامبهنام قابل فهرست کردن است:
ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'
نمونهای از تجربهٔ خودمان. Suricata با پیکربندی پیشفرض حدود سی نوع رویداد مینویسد و برای آنها هیچ چرخشی تنظیم نمیکند — روی یک سرور فعال این کار در دو شبانهروز ۱۵ گیگابایت گزارش تولید کرد. بار در آن حالت نه به شکل پردازندهٔ مشغول، بلکه دقیقاً به شکل I/O wait دیده میشد: سامانه بیوقفه مینوشت و باقی همه پشت آن در صف بودند. درمانش بستهٔ بزرگتر نیست، بلکه فهرست کوتاهتر رویدادها و چرخش تنظیمشده است.
حالت وارونه، کاملاً پردازندهای و بهمراتب کمتر آشکار. یک صفحهٔ وب فرمان apt را با کاربری اجرا میکرد که PHP-FPM با آن کار میکند. کاربر ریشه یک حافظهٔ نهان دودویی در /var/cache/apt/pkgcache.bin نگه میدارد — روی میزبانی با دهها مخزن این ۷۰ مگابایت است — و آن را رایگان به حافظه نگاشت میکند. کاربر عادی اجازهٔ نوشتن در آن پوشه را ندارد و در هر فراخوانی حافظهٔ نهان را از نو میسازد. اندازهگیری روی یک ماشین واحد: ۰٫۰۱ ثانیه زمان پردازنده با کاربر ریشه در برابر ۴٫۲ ثانیه با کاربر بدون دسترسی. همان فرمان، اختلاف چهارصد برابر، ضرب در هر بار باز شدن صفحه.
نتیجهٔ هر دو حالت یکی است: بار را باید اندازه گرفت، نه حدس زد. زمانگیری جداگانهٔ هر فرمان مشکوک نیم ساعت میبرد و معمولاً جایی را نشان میدهد غیر از آنجا که گمان از آن آغاز شده بود.
حافظه: 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 نیاز است که در یک بازه اندازه میگیرند.
چه زمانی بار به مسئلهٔ امنیتی بدل میشود
۱۰۰ درصد یکنواخت پردازنده در شب، همراه با فرایندی که نامی بیمعنا و پوشهٔ کاری در /tmp یا /dev/shm دارد، تصویر کلاسیک یک ماینر است نه سایتی که رشد کرده است. جهش ترافیک ورودی همراه با افزایش نوشتن در گزارشها یعنی حملهٔ در جریان به گذرواژهها. حجم گزارشی که ناگهان بالا میپرد معمولاً توفان هشدارهای نادرست یکی از پالایههاست.
خود ابزارهای حفاظتی ردهای جداگانهاند. روی یکی از سرورهای ما بار بدون هیچ بازدیدکنندهای حدود سه میماند و در صدر ps بر پایهٔ زمان پردازندهٔ انباشته نه سایت بود و نه پایگاه داده، بلکه CrowdSec و fail2ban و Falco و Suricata. این نه خرابی است و نه دلیلی برای خاموش کردنشان، اما دانستن بهای حفاظت به عدد سودمند است: روی یک VPS کوچک محسوس است.
فایدهٔ پایش
همهٔ آنچه گفته شد به پرسش «هماکنون چه میگذرد» پاسخ میدهد. پرسش صبحگاهی — ساعت سه بامداد چه شد — با این فرمانها پوشش داده نمیشود: از شب گذشته دادهای نیست اگر کسی آن را ثبت نکرده باشد. و برپا کردن Prometheus و Grafana برای یک VPS تنها محل تردید است، چون پشتهٔ ناظر سنگینتر از سرور تحت نظر درمیآید.
یک سطر در پایگاه داده هر پنج دقیقه و یک صفحه که از آن بیست و چهار ساعت اخیر را رسم کند کافی است: load average، میزان استفاده از پردازنده و جداگانه I/O wait، حافظه و swap، خواندن و نوشتن دیسک، پر شدن پارتیشن، آینودها، توصیفگرهای فایل، اتصالها. روی یک محور زمانی واحد، جفتها را با چشم غیرمسلح میتوان خواند: wa بالا با پردازندهٔ آرام، swap ای که هرگز به صفر بازنگشت، توصیفگرهایی که به مرز نزدیک میشوند — خطای آیندهٔ too many open files ساعتها پیش از وقوع دیده میشود. اینکه همهٔ اینها کنار هم چگونه به نظر میرسد را صفحهٔ نمایشی زیر نشان میدهد.