ساعت دو بامداد است. روی سرور free -h میزنید و این را میبینید:
total used free shared buff/cache available
Mem: 15Gi 14Gi 312Mi 180Mi 890Mi 620Mi
Swap: 2.0Gi 1.4Gi 600Mi
ستون free تقریباً صفر است، swap هم نصفه پر شده. اولین واکنش این است که سرور کم آورده و باید رم اضافه کرد. در بیشتر موارد این نتیجهگیری غلط است، ولی نه همیشه. تفاوت این دو حالت همان چیزی است که تعیین میکند باید پول خرج کنید یا یک تنظیم را عوض کنید.
ستون free دروغ میگوید، ستون available را بخوانید
کرنل لینوکس حافظه بیکار را دوست ندارد. هر فایلی که خوانده میشود، هر بلاکی که از دیسک میآید، در buff/cache نگه داشته میشود تا دفعه بعد از دیسک نخواند. این حافظه «مصرفشده» نیست؛ قابل آزادسازی است. لحظهای که یک پروسه به آن نیاز داشته باشد، کرنل همان کسری از ثانیه آن را پس میگیرد.
ستون available دقیقاً همین را حساب میکند: چقدر حافظه بدون رفتن سراغ swap میتواند به یک پروسه جدید برسد. در خروجی بالا، free میگوید ۳۱۲ مگابایت، ولی available میگوید ۶۲۰ مگابایت. عدد دوم است که اهمیت دارد.
پس قاعده اول: اگر available بالای ۱۰ تا ۱۵ درصد کل رم است و swap در حال تبادل مداوم نیست، سرور شما مشکل حافظه ندارد. آن ۱۴ گیگابایت used عمدتاً کش است و کارش همین است.
چه زمانی واقعاً کمبود داریم
سه نشانه که با هم یعنی مشکل واقعی است:
- ستون
availableزیر ۵ درصد کل رم و در حال کاهش در چند نمونه متوالی. - خروجی
vmstat 1 5در ستونsiوsoعدد پایدار و غیرصفر نشان میدهد. یعنی سیستم دارد مدام بین رم و swap جابهجا میکند. - در
dmesg -T | grep -i oomخطی مثلOut of memory: Killed process 2841 (php-fpm)دیده میشود.
اگر هر سه را دارید، بحث تمام است. اگر فقط اولی را دارید و swap دستنخورده است، احتمالاً دارید به یک عدد بیمعنی نگاه میکنید.
اینجا اشتباه میکنند: ریستارت کردن سرویس بهجای پیدا کردن مصرفکننده
الگویی که واقعاً زیاد دیدهام: مدیر سایت میبیند available پایین است، MySQL را ریستارت میکند، عدد برای دو ساعت خوب میشود و بعد برمیگردد. سرویس هیچ مشکلی نداشته؛ شما فقط کش را دور ریختهاید و سیستم را مجبور کردهاید همهچیز را از دیسک دوباره بخواند. آن دو ساعت هم دقیقاً همان زمانی است که کش در حال پر شدن مجدد بوده.
علامتش این است که مصرف رم بعد از هر ریستارت با شیب تقریباً یکسان بالا میرود و در یک سقف مشخص ثابت میماند. مصرفکننده واقعی را با ps aux --sort=-rss | head -15 پیدا کنید، نه با ریستارت. اگر پروسهای مثل php-fpm یا یک افزونه وردپرس در صدر لیست است و مدام رشد میکند، آنجا نشتی حافظه دارید و باید همان را درست کنید.
buff/cache را دستی خالی نکنید
دستور sync; echo 3 > /proc/sys/vm/drop_caches کار میکند و وسوسهکننده است. روی سرور تولیدی این کار را نکنید. نتیجهاش این است که هر خواندن بعدی از دیسک، از NVMe یا از سرویس ذخیرهسازی شبکهای، مستقیم میرود روی I/O و TTFB سایت بالا میرود. اگر واقعاً برای تست به آن نیاز دارید، فقط echo 1 بزنید که فقط page cache را آزاد میکند و بعد از تست، خودش دوباره پر میشود.
تنظیم مفیدتر، vm.swappiness است. مقدار پیشفرض روی بسیاری از توزیعها ۶۰ است که برای سرور وب محافظهکارانه نیست. روی سروری با ۱۶ گیگابایت رم، مقدار ۱۰ تا ۲۰ منطقیتر است: کرنل تا جای ممکن swap را نگه میدارد و فقط وقتی واقعاً لازم شد سراغش میرود. این را در /etc/sysctl.d/99-swap.conf بگذارید تا بعد از ریبوت هم بماند:
vm.swappiness = 10
vm.vfs_cache_pressure = 50
مقدار vfs_cache_pressure پایینتر باعث میشود کرنل inode و dentry cache را دیرتر آزاد کند. روی سروری که هزاران فایل کوچک دارد، این تفاوت محسوسی در بار I/O ایجاد میکند.
کدام ابزار را برای مصرف رم لینوکس برداریم
سه ابزار رایج، سه کار متفاوت:
| ابزار | چه میگوید | کِی به کار میآید |
|---|---|---|
free -h | تصویر لحظهای، با تفکیک buff/cache و available | نگاه اول، تشخیص سریع |
vmstat 1 | نرخ تبادل swap و صف I/O در بازه زمانی | وقتی میخواهید بدانید مشکل حاد است یا نه |
smem -rs rss | سهم واقعی هر پروسه با در نظر گرفتن حافظه مشترک | وقتی php-fpm و MySQL حافظه مشترک دارند و ps گمراهتان میکند |
اگر smem نصب نیست، ps_mem جایگزین خوبی است. تفاوتشان با top این است که حافظه مشترک بین پروسهها را چند بار نمیشمارند. روی سروری با ۲۰ ورکر php-fpm، این تفاوت میتواند چند گیگابایت خطا ایجاد کند.
سقف واقعی، نه سقف خیالی
یک نکته که کمتر گفته میشود: روی ماشین مجازی، عدد total در free همیشه همان چیزی نیست که به شما فروخته شده. اگر سرور ۱۶ گیگابایت رم دارد ولی کرنل با پارامتر mem=14G بالا آمده یا balloon driver هایپروایزر بخشی را قرض گرفته، total کمتر نشان میدهد. قبل از هر تصمیمی، dmidecode -t memory | grep -i size را با خروجی free مقایسه کنید. اگر این دو نمیخوانند، مشکل تنظیمات است نه ظرفیت.
و اگر بعد از همه این بررسیها به این نتیجه رسیدید که واقعاً ظرفیت کم است، راهحل درست ارتقای رم است نه دستکاری swappiness. برای سایتهای وردپرسی که روی هاست لینوکس اجرا میشوند، معمولاً همین نقطهای است که باید تصمیم بگیرید.
پرسشهای پرتکرار
چرا free میگوید حافظه پر است ولی سایت کند نیست؟
چون آن حافظه در واقع buff/cache است، نه مصرف واقعی پروسهها. کرنل لینوکس فایلها و بلاکهای دیسک را در رم نگه میدارد تا خواندن بعدی سریعتر شود، و این حافظه هر لحظه که لازم شود آزاد میشود. ستون available را ببینید؛ اگر بالای ۱۰ درصد کل رم است، سرور شما سالم است.
تفاوت used و available در خروجی free چیست؟
ستون used حافظهای است که پروسهها و کرنل اشغال کردهاند و بهسادگی آزاد نمیشود. ستون available برآورد کرنل از حافظهای است که میتواند بدون رفتن سراغ swap به یک پروسه جدید برسد، و شامل بخش قابلآزادسازی buff/cache هم میشود. برای تصمیمگیری، همیشه available را مبنا بگیرید.
چطور بفهمم OOM Killer پروسه من را کشته است؟
دستور dmesg -T | grep -i "out of memory" را بزنید. اگر خطی با نام پروسه و PID دیدید، یعنی کرنل بهخاطر کمبود واقعی حافظه آن را kill کرده. این نشانه قطعی کمبود رم است و با buff/cache اشتباه نمیشود. در این حالت لاگ /var/log/syslog یا journalctl -k هم همان رکورد را دارد.
آیا خالی کردن buff/cache روی سرور تولیدی امن است؟
امن است ولی توصیه نمیشود. دستور echo 3 > /proc/sys/vm/drop_caches چیزی را خراب نمیکند، اما کش را دور میریزد و بار I/O دیسک را موقتاً بالا میبرد که مستقیم روی زمان پاسخ سایت اثر میگذارد. اگر فقط برای تست لازم دارید، echo 1 کافی است و سیستم خودش کش را دوباره پر میکند.
قدم بعدی مشخص است: یک بار free -h و vmstat 1 5 را کنار هم بگذارید و ببینید si و so صفر است یا نه. اگر صفر بود، آن عدد قرمز free را نادیده بگیرید و بروید سراغ چیز دیگری که سایت را کند کرده. اگر صفر نبود، مصرفکننده واقعی را با ps aux --sort=-rss پیدا کنید و از همانجا شروع کنید.
دیدگاهها ۰
هنوز دیدگاهی ثبت نشده؛ اولین نفر باشید!