رفع مشکل

مصرف CPU سرور به سقف رسیده؛ پیدا کردن عامل و رفع قدم‌به‌قدم

تهیه: کلودیفای (نگارش با کمک هوش مصنوعی) · انتشار: · زمان مطالعه: ۷ دقیقه

RAMCPUCPUرفع مشکلمصرف CPU سرور بهسقف رسیده؛ پیدا کردنعامل و رفع قدم‌به‌قدممجلهٔ کلودیفایclodify.net/blog
پاسخ کوتاه

وقتی CPU سرور مدام پر است، ابتدا با top یا htop فرایند پرمصرف را پیدا کنید و با ps و pidstat بفهمید متعلق به کدام برنامه و کاربر است. علت‌های رایج: کوئری‌های سنگین دیتابیس، تعداد زیاد درخواست به PHP-FPM یا برنامه، ربات‌ها و خزنده‌ها، حلقهٔ معیوب در کد، کار زمان‌بندی‌شدهٔ سنگین و گاهی ماینر رمزارز پس از نفوذ. اگر CPU پر است ولی هیچ فرایندی مقصر نیست، مقدار steal را بررسی کنید.

CPU بالا همیشه مشکل نیست

پیش از هر اقدامی، یک نکته را در نظر بگیرید: CPU برای کار کردن ساخته شده است. اگر هنگام ساخت ایمیج داکر، فشرده‌سازی بکاپ یا اجرای یک پردازش سنگین، مصرف CPU برای مدتی به سقف می‌رسد، اتفاق عجیبی نیست. مشکل وقتی است که مصرف بالا پایدار باشد، سرور یا سایت کند شده باشد، یا مصرف بدون دلیل روشنی بالا رفته باشد.

نشانه‌های اینکه CPU واقعاً گلوگاه است: کند شدن پاسخ سایت یا API، تأخیر در تایپ داخل نشست SSH، load average پایدار بالاتر از تعداد هسته‌ها و خطاهای timeout در لاگ وب‌سرور. برای خواندن درست این اعداد، ابتدا راهنمای بررسی مصرف CPU و رم با top و htop را مرور کنید.

روند عیب‌یابی CPU بالا
  1. پیدا کردن فرایند

    top، htop و ps با مرتب‌سازی بر اساس CPU.

  2. نوع مصرف

    us، sy، wa یا st؛ هرکدام گلوگاه متفاوتی را نشان می‌دهد.

  3. علت برنامه‌ای

    کوئری‌ها، workerها، لاگ دسترسی و کارهای زمان‌بندی‌شده.

  4. بررسی نفوذ

    فرایند ناشناس، مسیر /tmp و cron مشکوک.

  5. اقدام

    رفع فوری با renice یا CPUQuota و رفع بلندمدت با کش و بهینه‌سازی.

شکل ۱ اول عامل را پیدا کنید؛ ارتقای سخت‌افزار آخرین قدم است.

گام ۱: کدام فرایند CPU را مصرف می‌کند؟

top -o %CPU
# یا
htop

در top کلید P مرتب‌سازی بر اساس CPU و کلید c نمایش دستور کامل هر فرایند است. دستور کامل مهم است؛ مثلاً «python3» به‌تنهایی نمی‌گوید کدام اسکریپت است. برای یک تصویر ثابت و قابل‌کپی:

ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -n 15

ستون etime نشان می‌دهد فرایند چه مدت است اجرا می‌شود. فرایندی که هفته‌ها اجرا شده و حالا ناگهان پرمصرف است، با فرایندی که چند دقیقه پیش ساخته شده، داستان متفاوتی دارد.

برای دیدن روند مصرف هر فرایند در چند ثانیه (نه فقط یک لحظه)، ابزار pidstat از بستهٔ sysstat مفید است:

sudo apt install -y sysstat
pidstat -u 2 5

گام ۲: نوع مصرف را تشخیص دهید

در سطر %Cpu(s) ابزار top، تفکیک مصرف سرنخ مهمی است:

  • us بالا: برنامه‌های کاربر مصرف می‌کنند؛ رایج‌ترین حالت. سراغ گام ۳ بروید.
  • sy بالا: زمان زیادی در هستهٔ سیستم‌عامل صرف می‌شود؛ معمولاً به‌خاطر تعداد بسیار زیاد اتصال شبکه، فرایندهایی که مدام ساخته و بسته می‌شوند یا ورودی‌وخروجی سنگین.
  • wa بالا: CPU منتظر دیسک است. در این حالت ارتقای CPU کمکی نمی‌کند و باید دیسک و کوئری‌ها را بررسی کرد.
  • st بالا: CPU Steal؛ یعنی ماشین مجازی شما منتظر سخت‌افزار فیزیکی میزبان است. اگر هیچ فرایندی در top پرمصرف نیست ولی سرور کند است، این ستون را ببینید.

گام ۳: مقصران رایج و راه‌حل هرکدام

دیتابیس (mysqld، mariadbd، postgres)

اگر دیتابیس در صدر top است، کوئری‌های در حال اجرا را ببینید:

# MySQL / MariaDB
sudo mysql -e "SHOW FULL PROCESSLIST;"
# PostgreSQL
sudo -u postgres psql -c "SELECT pid, now()-query_start AS t, query FROM pg_stat_activity WHERE state='active' ORDER BY t DESC;"

کوئری‌هایی که مدت طولانی اجرا می‌شوند معمولاً ایندکس مناسب ندارند. فعال کردن Slow Query Log و افزودن ایندکس روی ستون‌هایی که در شرط WHERE و JOIN می‌آیند، بیشترین اثر را دارد. افزایش سخت‌افزار بدون رفع کوئری بد، فقط مشکل را عقب می‌اندازد.

PHP-FPM، Gunicorn یا Node.js

اگر ده‌ها فرایند PHP-FPM یا worker برنامه CPU را پر کرده‌اند، یا بازدید واقعاً زیاد شده یا صفحه‌هایی بدون کش هر بار پردازش سنگین انجام می‌دهند. لاگ دسترسی وب‌سرور را بررسی کنید تا ببینید کدام آدرس‌ها و کدام آی‌پی‌ها بیشترین درخواست را دارند:

sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

ربات‌ها، خزنده‌ها و حمله

اگر چند آی‌پی سهم بزرگی از درخواست‌ها را دارند، احتمالاً با خزندهٔ پرسرعت، اسکرپر یا حملهٔ لایهٔ کاربرد روبه‌رو هستید. محدودسازی نرخ در Nginx (limit_req)، مسدود کردن آی‌پی‌های متخلف و قرار دادن سایت پشت CDN که درخواست‌های تکراری را از کش پاسخ می‌دهد، بار سرور اصلی را کم می‌کند. برای حملات به SSH هم Fail2ban راه‌حل استاندارد است.

کارهای زمان‌بندی‌شده

اگر مصرف بالا در ساعت‌های مشخصی رخ می‌دهد، crontab همهٔ کاربران و تایمرهای systemd را بررسی کنید (crontab -l، ls /etc/cron.d و systemctl list-timers). بکاپ، ساخت نقشهٔ سایت یا پردازش‌های شبانه را به ساعت‌های کم‌بازدید منتقل کنید و با nice اولویتشان را پایین بیاورید.

root@server: ~
$ ps -eo pid,user,%cpu,etime,cmd --sort=-%cpu | head -n 4  PID USER     %CPU     ELAPSED CMD 1234 mysql     ...    ...      /usr/sbin/mysqld 2345 www-data  ...    ...      php-fpm: pool www$ mysql -e 'SHOW FULL PROCESSLIST' | head -n 3Id  User  Host       db    Command  Time  State  Info$ 
شکل ۲ دیتابیس در صدر است؛ قدم بعدی دیدن کوئری‌های طولانی در processlist است.

گام ۴: احتمال نفوذ و ماینر را جدی بگیرید

یکی از علت‌های جدی CPU پایدار و بالا، ماینر رمزارز است که پس از نفوذ روی سرور نصب می‌شود. نشانه‌ها:

  • فرایندی با نام عجیب یا شبیه فرایندهای سیستمی (مثلاً kworkerds یا نام‌های تصادفی) که CPU را پر کرده است؛
  • اجرا از مسیرهایی مثل /tmp، /var/tmp یا /dev/shm؛
  • کار cron ناشناخته‌ای که فرایند را پس از kill کردن دوباره اجرا می‌کند؛
  • اتصال‌های خروجی دائمی به آی‌پی‌ها و پورت‌های ناشناس.
ls -l /proc/<PID>/exe
sudo ss -tnp | grep <PID>
sudo crontab -l; ls -la /etc/cron.d /var/spool/cron/crontabs

اگر شواهد نفوذ پیدا کردید، فقط kill کردن فرایند کافی نیست؛ مهاجم احتمالاً راه بازگشت دارد. داده‌های مهم را بکاپ بگیرید، سرور تازه بسازید و پس از امن‌سازی، داده‌های سالم را منتقل کنید. اقدامات پیشگیرانه را در چک‌لیست امنیت سرور جدید دنبال کنید.

گام ۵: CPU Steal و محدودیت سرور مجازی

اگر مقدار st در top یا vmstat مداوم بالاست، سرور شما برای گرفتن زمان CPU با ماشین‌های مجازی دیگر روی همان میزبان رقابت می‌کند. این مشکل از داخل سرور قابل رفع نیست. با پشتیبانی ارائه‌دهنده در میان بگذارید، لوکیشن یا پلن دیگری امتحان کنید یا اگر کار شما CPU سنگین و پیوسته دارد، پلن با هسته‌های اختصاصی را در نظر بگیرید. با ابزارهای بنچمارک سرور می‌توانید کارایی CPU را قبل و بعد از تغییر بسنجید.

راه‌حل‌های فوری و بلندمدت

فوری (برای بازگرداندن سرویس):

  • کاهش اولویت فرایند غیرضروری: sudo renice +10 -p <PID>
  • محدود کردن موقت با systemd: sudo systemctl set-property myapp.service CPUQuota=50%
  • مسدود کردن آی‌پی‌های متخلف در فایروال
  • ری‌استارت سرویسی که در حلقهٔ معیوب گیر کرده است

بلندمدت:

  • بهینه‌سازی کوئری‌ها و افزودن کش (Redis، کش صفحه، کش CDN)؛
  • تنظیم تعداد workerها متناسب با تعداد هسته‌ها؛
  • جدا کردن دیتابیس یا پردازش‌های سنگین روی سرور جداگانه؛
  • ارتقای پلن وقتی مصرف واقعی و بهینه همچنان بالاتر از توان سرور است.
کاهش بار CPU با کش
همهٔ درخواست‌هاکش‌نشده‌هاکوئریبازدیدکنندهدرخواست صفحهCDNپاسخ از کش لبهوب‌سرورفقط درخواست‌های جدیددیتابیسکوئری‌های کمترهمهٔ درخواست‌هاکش‌نشده‌هاکوئریبازدیدکنندهدرخواست صفحهCDNپاسخ از کش لبهوب‌سرورفقط درخواست‌های جدیددیتابیسکوئری‌های کمتر
شکل ۳ هر درخواستی که از کش پاسخ داده شود، یک بار پردازش کمتر برای CPU سرور اصلی است.

پیشگیری: هشدار پیش از بحران

بهترین زمان برای پیدا کردن علت مصرف بالای CPU، پیش از آن است که کاربران شکایت کنند. چند اقدام ساده کمک می‌کند مشکل را در مراحل اولیه ببینید:

  • ابزاری نصب کنید که مصرف را در طول زمان ثبت کند، مثل sysstat یا Netdata، تا بتوانید بعداً ببینید مصرف از چه ساعتی و همراه با کدام رویداد بالا رفته است.
  • برای load average یا مصرف CPU آستانهٔ هشدار تعریف کنید و پیام را به ایمیل یا تلگرام بفرستید. یک اسکریپت کوچک در cron که خروجی uptime را بررسی کند، برای شروع کافی است.
  • پس از هر تغییر بزرگ، مثل نصب افزونهٔ جدید وردپرس، انتشار نسخهٔ جدید برنامه یا افزودن کار زمان‌بندی‌شده، چند ساعت مصرف را زیر نظر بگیرید.

به این ترتیب، به‌جای اینکه در لحظهٔ بحران دنبال سرنخ بگردید، تاریخچه‌ای دارید که دقیقاً نشان می‌دهد چه چیزی و از چه زمانی تغییر کرده است.

کی ارتقا بدهیم؟

اگر علت را پیدا و رفع کرده‌اید، کش را فعال کرده‌اید، ولی در ساعت‌های عادی همچنان CPU پر است، وقت ارتقاست. در سرورهای ساعتی کلودیفای می‌توانید پلن بزرگ‌تر را چند ساعت در ساعت اوج امتحان کنید و اثرش را با اعداد واقعی ببینید، بدون تعهد ماهانه؛ پلن‌ها در سرور مجازی ایران آمده‌اند. اگر هم‌زمان رم هم کم است، کمبود رم و خطای Out of Memory را بخوانید؛ چون کمبود رم با فعال کردن Swap می‌تواند به شکل مصرف بالای CPU و دیسک هم خودش را نشان دهد.

سؤالات متداول

چرا top مصرف CPU را بیش از صد نشان می‌دهد؟

در top هر هسته صد واحد حساب می‌شود. روی سرور چهارهسته‌ای، فرایندی که از چند هسته هم‌زمان استفاده می‌کند می‌تواند تا چهارصد نمایش داده شود. با کلید 1 مصرف هر هسته را جداگانه ببینید.

CPU پر است ولی هیچ فرایندی در top مصرف بالا ندارد؛ چرا؟

ستون st یا steal را بررسی کنید؛ ممکن است میزبان فیزیکی شلوغ باشد. همچنین فرایندهای بسیار کوتاه‌عمر که مدام ساخته و بسته می‌شوند در top دیده نمی‌شوند؛ ابزارهایی مثل pidstat یا execsnoop آن‌ها را آشکار می‌کنند.

آیا kill کردن ماینر کافی است؟

خیر. ماینر نشانهٔ نفوذ است و مهاجم معمولاً با cron یا سرویس مخفی آن را دوباره اجرا می‌کند. سرور را آلوده فرض کنید، داده‌ها را بکاپ بگیرید و روی سرور تازه و امن‌شده بازسازی کنید.

ارتقای CPU همیشه مشکل را حل می‌کند؟

نه. اگر علت کوئری بدون ایندکس، حمله یا حلقهٔ معیوب در کد باشد، CPU بیشتر هم پر می‌شود. ابتدا علت را پیدا کنید و فقط وقتی مصرف بهینه‌شده هم زیاد است ارتقا دهید.

آماده‌اید؟ سرورتان را بسازید.

از ۱٬۲۰۰ تومان در ساعت · پرداخت ریالی

سرورتان را همین حالا بسازید.

ساعتی بپردازید. هر وقت خواستید حذف کنید.