swap لینوکس: چه زمانی کمک می‌کند و چه زمانی فقط کندی را پنهان می‌کند

اگر سرور با OOM Killer پروسه‌ها را می‌کشد یا لود بالا می‌رود، اول باید بفهمید swap لینوکس مشکل را حل می‌کند یا فقط آن را عقب می‌اندازد.

۶ دقیقه به‌روزرسانی ۲۹ مهر ۱۴۰۵

سرور جواب نمی‌دهد، SSH با تأخیر چند ثانیه‌ای باز می‌شود و در dmesg خطی مثل Out of memory: Killed process 21834 (mysqld) نشسته است. یا برعکس: free -h را می‌زنید و می‌بینید swap کاملاً پر است ولی CPU بیکار است و همه‌چیز کند. این دو حالت مشکل یکسانی دارند ولی راه‌حلشان یکی نیست. تصمیم درست این است که اول بفهمید کدام‌یک را دارید.

اول ببینید واقعاً کمبود حافظه دارید یا نه

قبل از هر تغییری، عدد بگیرید. این سه دستور تصویر کامل را می‌دهند:

free -m
vmstat 1 5
cat /proc/meminfo | grep -E 'MemAvailable|SwapTotal|SwapFree'

در خروجی vmstat دو ستون مهم است: si و so (swap in/out بر حسب کیلوبایت بر ثانیه). اگر این دو عدد پایدار بالای صفر می‌مانند، سیستم در حال تاخت‌وتاز بین RAM و دیسک است و هر عملیات دیسکی چند برابر کندتر تمام می‌شود. اگر si و so صفرند و فقط SwapUsed بالاست، آن swap مرده است؛ صفحاتی که یک‌بار بیرون رانده شده‌اند و کسی سراغشان نمی‌رود. این حالت مشکلی نیست.

نکته‌ای که خیلی‌ها از دست می‌دهند: free قدیمی ستون buff/cache را جدا نشان می‌دهد و آدم فکر می‌کند RAM پر است. معیار درست MemAvailable است، نه MemFree. کرنل کش دیسک را هر وقت لازم شود آزاد می‌کند.

اضافه کردن فایل swap؛ روشی که روی VPS جواب می‌دهد

روی ماشین‌هایی که پارتیشن swap از قبل ندارند (اکثر VPS ها)، فایل swap سریع‌ترین راه است. برای یک سرور ۲ گیگابایتی، یک فایل ۲ گیگابایتی نقطه شروع معقولی است:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

خط fstab را فراموش نکنید؛ وگرنه بعد از ریبوت همه‌چیز به حالت قبل برمی‌گردد و شما فکر می‌کنید تنظیمات کار نکرده. برای بررسی: swapon --show و free -h.

یک هشدار عملی: روی برخی فایل‌سیستم‌ها (مثل XFS قدیمی یا overlayfs در کانتینرها) fallocate فایلی می‌سازد که swap نمی‌شود. اگر swapon خطای swapon failed: Invalid argument داد، با dd بسازید:

dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress

اگر روی زیرساخت ابری کار می‌کنید و دیسک سیستم از نوع شبکه‌ای است، swap روی همان دیسک تقریباً بی‌فایده است چون IOPS اش اشتراکی و کم است. در این حالت یا باید از سرور ابری با دیسک محلی NVMe استفاده کنید، یا سراغ سرورهایی بروید که دیسک اختصاصی دارند.

swappiness؛ عددی که همه اشتباه تنظیم می‌کنند

مقدار پیش‌فرض vm.swappiness در کرنل‌های امروزی ۶۰ است. این عدد درصد نیست؛ یک وزن است که می‌گوید کرنل چقدر مایل است صفحات بی‌استفاده را بیرون براند در مقابل آزاد کردن کش فایل. مقدار صفر یعنی «تا جای ممکن swap نکن» و نه «هرگز swap نکن».

sysctl vm.swappiness=10
echo 'vm.swappiness=10' >> /etc/sysctl.d/99-swap.conf

روی سرور دیتابیس، ۱۰ منطقی است. روی سرور وب با ترافیک متغیر، ۲۰ تا ۳۰ بهتر جواب می‌دهد چون اجازه می‌دهد کش فایل زنده بماند. عدد صفر را فقط وقتی بگذارید که واقعاً می‌دانید چه می‌کنید؛ نتیجه‌اش این است که وقتی RAM تمام شود، کرنل به‌جای swap کردن، مستقیم سراغ OOM Killer می‌رود.

یک پارامتر دیگر هم هست که کمتر کسی سراغش می‌رود: vm.vfs_cache_pressure. اگر slabtop نشان می‌دهد dentry و inode_cache حجم زیادی از RAM را گرفته‌اند، کاهش این مقدار به ۵۰ کمک می‌کند کرنل این کش‌ها را دیرتر آزاد کند.

این‌جا اشتباه می‌کنند

رایج‌ترین اشتباهی که می‌بینم این است: سرور کند شده، ادمین یک فایل swap هشت گیگابایتی می‌سازد، free سبز می‌شود و مشکل «حل» می‌شود. دو هفته بعد همان سرور با لود ۴۰ و تأخیر پاسخ چند ثانیه‌ای برمی‌گردد، ولی این بار هیچ خطای OOM در لاگ نیست.

علامتش دقیقاً این است: iostat -x 1 نشان می‌دهد %util دیسک نزدیک ۱۰۰ است، si و so در vmstat مدام بالا و پایین می‌روند، و زمان پاسخ دیتابیس دو رقمی شده. swap اینجا هیچ‌چیز را حل نکرده؛ فقط یک لایه کند دیسک بین برنامه و حافظه گذاشته تا مشکل دیرتر منفجر شود. اگر مصرف حافظه‌تان به‌طور پیوسته رشد می‌کند، مشکل یک نشتی حافظه در برنامه است، نه کمبود RAM.

اشتباه دوم: گذاشتن swap روی همان دیسکی که دیتابیس روی آن است. هر صفحه‌ای که swap شود، یک I/O رقابتی با کوئری‌های دیتابیس ایجاد می‌کند. اگر مجبورید، swap را روی دیسک جدا بگذارید.

swap چقدر باید باشد

حالتاندازه پیشنهادیدلیل
سرور وب با RAM کم (۱ تا ۲ گیگ)برابر RAM یا دو برابرجلوگیری از OOM در پیک ترافیک
سرور دیتابیس اختصاصی۱ تا ۲ گیگ، ثابتفقط برای صفحات سرد؛ بیشتر از این خطرناک است
ماشین با RAM زیاد (۳۲ گیگ به بالا)۲ تا ۴ گیگswap بزرگ روی این ماشین‌ها فقط توهم امنیت می‌دهد
کانتینر یا VPS اشتراکیطبق محدودیت ارائه‌دهندهswap اضافه می‌تواند سهمیه دیسک را پر کند

قاعده قدیمی «دو برابر RAM» از دوران RAM های ۵۱۲ مگابایتی می‌آید و امروز غلط است. روی ماشین ۶۴ گیگابایتی، swap ۱۲۸ گیگابایتی هیچ فایده‌ای ندارد و فقط فضای دیسک را می‌خورد.

وقتی swap جواب نمی‌دهد

اگر بعد از همه این تنظیمات هنوز si/so بالا می‌ماند، مشکل ظرفیت است نه تنظیمات. سه راه پیش رو دارید: افزایش RAM، کاهش مصرف (مثلاً محدود کردن innodb_buffer_pool_size یا pm.max_children در PHP-FPM)، یا انتقال بار به ماشین دیگر. قبل از هر کدام، خروجی ps aux --sort=-rss | head -20 را ببینید تا بدانید کدام پروسه واقعاً حافظه می‌خورد.

اگر لود بالا دارید ولی مطمئن نیستید منشأش حافظه است یا I/O یا CPU، راهنمای تشخیص علت لود بالای سرور ترتیب درست بررسی را نشان می‌دهد. برای سرورهایی که بار سنگین و پایدار دارند، سرور اختصاصی با RAM کافی معمولاً از هر ترفند swap ای ارزان‌تر تمام می‌شود.

یک نکته آخر درباره پایداری: اگر روی سرورتان swap را فعال می‌کنید، مطمئن شوید سرویس‌های حیاتی مثل MySQL و Redis طوری تنظیم شده‌اند که در شرایط فشار حافظه زودتر از همه قربانی نشوند. تنظیم OOMScoreAdjust در فایل systemd واحد سرویس، یا oom_score_adj در /proc/<pid>/ این کنترل را می‌دهد. بدون این، کرنل ممکن است دیتابیس شما را بکشد و وب‌سرور را زنده نگه دارد؛ دقیقاً برعکس آنچه می‌خواهید.

پرسش‌های پرتکرار

آیا فعال بودن swap سرور را کند می‌کند؟

خود swap کند نیست؛ استفاده فعال از آن کند است. اگر vmstat نشان می‌دهد si و so نزدیک صفرند، swap فقط صفحات بی‌استفاده را نگه داشته و هیچ تأثیری روی کارایی ندارد. مشکل وقتی شروع می‌شود که سیستم مدام بین RAM و دیسک جابه‌جایی انجام دهد.

مقدار مناسب vm.swappiness برای سرور دیتابیس چقدر است؟

برای MySQL یا PostgreSQL معمولاً ۱۰ مقدار خوبی است. اگر مقدار صفر بگذارید، کرنل به‌جای swap کردن مستقیم سراغ OOM Killer می‌رود و ممکن است پروسه دیتابیس را از دست بدهید. مقدار پیش‌فرض ۶۰ هم روی سرور دیتابیس معمولاً بیش از حد تهاجمی است.

چطور بفهمم swap دارم یا نه؟

دستور swapon --show لیست فایل‌ها و پارتیشن‌های swap فعال را نشان می‌دهد. اگر خروجی خالی بود، swap ندارید. دستور free -h هم در خط Swap مقدار کل و مصرف‌شده را می‌آورد.

آیا می‌توانم swap را بدون ریبوت حذف کنم؟

بله. اول swapoff /swapfile را بزنید، بعد خط مربوطه را از /etc/fstab حذف کنید و فایل را پاک کنید. فقط حواستان باشد اگر مصرف حافظه نزدیک سقف RAM است، swapoff می‌تواند باعث OOM فوری شود. قبلش با free -m مطمئن شوید فضای کافی دارید.

آیا این مطلب برایتان مفید بود؟