سایت باز نمیشود یا کند شده، تیکت زدهاید و در پاسخ نوشتهاند «مصرف منابع هاست شما از حد مجاز عبور کرده است». حالا یک نمودار جلوی شماست با چند خط رنگی و عددهایی که هیچکدام معنی روشنی ندارند. این متن برای همین لحظه است: خواندن آن نمودار و رسیدن از عدد به خط کد.
اول یک نکته که خیلیها را از مسیر خارج میکند: در هاست اشتراکی، CPU به شما «اختصاص» داده نمیشود. شما سهمی از یک پردازنده مشترک دارید و میزبان با دو مکانیزم کنترل میکند؛ یکی سقف مصرف لحظهای (که معمولاً بر حسب درصد CPU و در بازههای کوتاه اندازهگیری میشود) و دیگری سقف تعداد پردازشهای همزمان یا همان entry process. عدد اول میگوید چقدر سریع میدوید، عدد دوم میگوید چند نفر همزمان میتوانند وارد شوند. این دو را با هم اشتباه نگیرید، چون درمانشان کاملاً متفاوت است.
نمودار CPU را چطور بخوانیم که گمراه نشویم
به قله نگاه نکنید، به شکل نمودار نگاه کنید. سه الگو را در عمل میبینم:
- قلههای باریک و پرتکرار: یک اسکریپت مشخص در بازههای منظم اجرا میشود. تقریباً همیشه یک cron است یا یک درخواست AJAX که مرورگر هر چند ثانیه میفرستد.
- سطح بالا و صاف برای ساعتها: ترافیک واقعی نیست، یک حلقه است. اسکریپتی که در خودش گیر کرده و مدام دیتابیس را میکوبد.
- پلهای و همزمان با ساعتهای مشخص: ترافیک انسانی. اگر ساعت ۱۰ تا ۱۲ هر روز بالا میرود، مشکل ظرفیت است نه باگ.
یک عدد واقعی که زیاد میبینم: سایتی با ۴۰۰ بازدید روزانه که نمودار CPU آن هر شب ساعت ۳ بامداد به ۹۰ درصد میرسد و ۲۰ دقیقه همانجا میماند. نه بازدیدکنندهای هست، نه حملهای. یک بکاپگیری از دیتابیس ۱.۲ گیگابایتی روی همان هاست، بدون --single-transaction، که جدولها را قفل میکند و تا تمام نشود همهچیز را زمینگیر میکند.
تفاوت CPU و entry process در عمل
اگر entry process پر شده باشد، کاربر خطای 508 Resource Limit Is Reached میبیند یا صفحه سفید میشود، ولی CPU ممکن است پایین باشد. این حالت یعنی درخواستها روی هم تلنبار شدهاند و هر کدام منتظر چیزی هستند؛ معمولاً یک درخواست خارجی کند (API یک درگاه پرداخت، یک وبسرویس ارسال پیامک) یا یک کوئری سنگین که پاسخش ۳۰ ثانیه طول میکشد. برعکسش هم پیش میآید: CPU روی ۱۰۰ درصد قفل است ولی سایت باز میشود، چون فقط یک پردازش دیوانهوار مشغول است.
پیدا کردن اسکریپت پرمصرف با ابزارهایی که همین حالا در دسترساند
قبل از هر چیز، از پنل هاست دنبال فایل access log بروید. اگر دسترسی SSH دارید، این دو دستور سریعترین راه رسیدن به مقصر است:
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -20
این خط میگوید کدام مسیرها بیشترین درخواست را گرفتهاند. اگر wp-cron.php یا admin-ajax.php بالای لیست بود، مشکل ترافیک نیست، خودِ سایت است. دستور دوم مصرف را به بازه زمانی گره میزند:
grep "admin-ajax.php" access.log | awk '{print $4}' | cut -d: -f2 | sort | uniq -c
خروجی این دستور توزیع ساعتی را نشان میدهد. اگر همه درخواستها در یک دقیقه متمرکز باشند، یک حلقه در جاوااسکریپت یا یک کرون معیوب دارید.
برای کوئریها، اگر MySQL در دسترس است، SHOW FULL PROCESSLIST; را دو بار با فاصله چند ثانیه اجرا کنید. کوئریای که در هر دو خروجی هست، همان گلوگاه است. در وردپرس، افزونهای که کوئریها را لاگ میکند معمولاً خودش مصرف ایجاد میکند؛ فقط چند دقیقه روشنش کنید و بعد خاموش.
برای بررسی اینکه مشکل از شبکه یا DNS نیست و کندی از سمت سرور است، بررسی DNS و شبکه نقطه شروع خوبی است؛ اگر TTFB بالا باشد ولی DNS سریع resolve شود، بحث کاملاً داخلی است.
کرونها را جدی بگیرید
نیمی از مواردی که به من ارجاع میشود، یک کرون است که کسی یادش رفته. با crontab -l لیست را ببینید و برای هر خط بپرسید آخرین بار کِی لازم بود. اگر نحو پنج فیلد را دقیق به خاطر ندارید، مرجع کامل نحو کرون را باز کنید؛ یک * اشتباه در فیلد دقیقه، یک اسکریپت سنگین را هر دقیقه اجرا میکند و شما فکر میکنید هک شدهاید.
اینجا اشتباه میکنند: کاربر نمودار را میبیند، سریع یک افزونه کش نصب میکند و میگوید حل شد. دو روز بعد همان قله برمیگردد، این بار بدتر. کش فقط تعداد اجراهای PHP را کم میکند؛ اگر اسکریپت مقصر یک کرون یا یک فرایند پسزمینه باشد، کش هیچ اثری روی آن ندارد و فقط مشکل را پنهان میکند تا وقتی که دوباره سقف را رد کنید. نشانهاش این است: مصرف CPU بعد از نصب کش کمی پایین میآید ولی قلههای شبانه سر جای خودشان میمانند.
کدام راهحل را انتخاب کنیم
سه مسیر واقعی وجود دارد و انتخاب بینشان به این بستگی دارد که مقصر را پیدا کردهاید یا نه.
| وضعیت | اقدام درست | هزینهای که میپردازید |
|---|---|---|
| مقصر مشخص است (کرون، افزونه، کوئری) | رفع ریشهای: غیرفعالسازی، بهینهسازی کوئری، ایندکس | زمان توسعهدهنده |
| مقصر مشخص نیست، ترافیک واقعی است | ارتقا به منابع بیشتر یا مهاجرت به سرور اختصاصی | هزینه ماهانه بالاتر و مسئولیت مدیریت سرور |
| مقصر مشخص نیست، ترافیک هم کم است | پاکسازی و بازسازی: حذف افزونههای بیاستفاده، بازنویسی اسکریپت | وقت، و ریسک خرابی موقت سایت |
اگر از من بپرسید، در ۸۰ درصد موارد ردیف اول جواب است و ارتقای پلن فقط صورتمسئله را عوض میکند. اما یک شرط دارم: اگر بعد از رفع مقصر، مصرف پایه سایت (بدون ترافیک) هنوز بالای ۳۰ درصد سهم شماست، دیگر بهینهسازی فایده ندارد و باید منابع را بالا ببرید. آن ۳۰ درصد عدد دلبخواهی نیست؛ فاصلهای است که برای قلههای ترافیکی و بکاپ شبانه لازم دارید.
یک تله دیگر: بعضیها برای فرار از محدودیت، دیتابیس را به سرور دیگری منتقل میکنند. اگر شبکه بین دو سرور تأخیر داشته باشد، هر کوئری چند میلیثانیه کندتر میشود و در صفحهای با ۲۰۰ کوئری، این یعنی چند ثانیه. نتیجه این است که CPU پایین میآید ولی entry process پر میشود، چون هر پردازش مدت بیشتری باز میماند.
کارهای عملی که همین امروز انجام میدهید
- لاگ دسترسی را برای ۲۴ ساعت قبل دانلود کنید و دو دستور بالا را اجرا کنید.
- لیست کرونها را با
crontab -lو از داخل پنل بگیرید و هر خطی که توضیحش را نمیدانید غیرفعال کنید. - افزونهها را یکییکی غیرفعال کنید و بعد از هر کدام ۱۰ دقیقه نمودار را ببینید. این کار خستهکننده است ولی قطعیترین روش است.
- اگر خطای دیتابیس میگیرید و فایل SQL سنگینی دارید، روش ایمپورت SQL بزرگ بدون تایماوت را جایگزین ایمپورت ساده کنید؛ ایمپورت ناقص یکی از دلایل رایج مصرف بالای مداوم است.
- برای قواعد سرور و ریدایرکتها، مرجع دستورات htaccess را ببینید؛ یک ریدایرکت حلقهای میتواند تا بینهایت درخواست تولید کند.
اگر سایت روی وردپرس است و افزونههای زیادی دارید، قبل از هر چیز فهرست افزونههای PHP نصبشده را بررسی کنید؛ گاهی یک افزونه بهخاطر نبود یک ماژول، مسیر کندتری را انتخاب میکند. فهرست افزونههای PHP و روش تست آنها این را روشن میکند.
و اگر تازه میخواهید سایت را از صفر روی یک بستر پایدار بگذارید، هاست لینوکس با دسترسی کامل به لاگها و کرون، همین کارهایی که در این متن گفتیم را ممکن میکند؛ بدون لاگ، تشخیص مقصر حدسوگمان است.
پرسشهای پرتکرار
چرا مصرف CPU هاست من شبها بالا میرود در حالی که بازدیدکنندهای نیست؟
تقریباً همیشه یک کرون یا فرایند بکاپ است. کرونها را با crontab -l و از پنل هاست چک کنید و ببینید کدامشان در آن ساعت اجرا میشود. بکاپ دیتابیس بدون قفلنشدن جدولها و بهینهسازی خودکار وردپرس دو مقصر رایج شبانه هستند.
خطای 508 Resource Limit Is Reached یعنی CPU تمام شده یا چیز دیگری؟
این خطا معمولاً مربوط به سقف entry process است، نه CPU. یعنی تعداد پردازشهای همزمان شما پر شده و درخواست جدید جایی برای نشستن ندارد. نشانهاش این است که سایت برای بعضی کاربران باز میشود و برای بعضی نه، در حالی که نمودار CPU پایین است.
نصب افزونه کش مشکل مصرف منابع هاست را حل میکند؟
فقط اگر مقصر، اجرای مکرر PHP برای بازدیدکنندههای تکراری باشد. اگر مقصر یک کرون، یک کوئری سنگین یا یک درخواست خارجی کند باشد، کش هیچ اثری روی آن ندارد و فقط قلهها را به تأخیر میاندازد. اول مقصر را پیدا کنید، بعد کش بگذارید.
از کجا بفهمم باید پلن را ارتقا بدهم یا فقط کد را بهینه کنم؟
مصرف پایه سایت را در ساعتی که ترافیک صفر است اندازه بگیرید. اگر بعد از حذف کرونها و افزونههای اضافی هنوز بالای ۳۰ درصد سهم شماست، بهینهسازی بیشتر جواب نمیدهد و وقت ارتقا است. اگر پایینتر است، مشکل کد است نه ظرفیت.