اگر Nginx، Node.js، Redis، دیتابیس، Docker یا یک سرویس لینوکسی با خطای Too Many Open Files متوقف میشود، مشکل معمولاً از تمامشدن File Descriptorهای مجاز برای یک Process یا رسیدن سیستم به سقف فایلهای باز است. بالا بردن تصادفی ulimit همیشه راهحل کامل نیست؛ ابتدا باید مشخص کنید کدام Limit پر شده و آیا برنامه واقعاً تعداد غیرعادی فایل یا Socket باز نگه میدارد.
مسیر سریع عیبیابی: با ulimit -n Limit شل فعلی را ببینید، با /proc/PID/limits Limit واقعی Process مشکلدار را بررسی کنید، تعداد File Descriptorهای باز همان Process را بشمارید و فقط اگر به سقف نزدیک است Limit مناسب را افزایش دهید. برای سرویسهای systemd معمولاً تنظیم درست LimitNOFILE= است، نه تغییر ساده ulimit در SSH.
Too Many Open Files یعنی چه؟
Linux برای فایلها، Socketهای شبکه، Pipeها، Deviceها و بسیاری از منابع دیگر از File Descriptor استفاده میکند. هر Process تعداد مشخصی File Descriptor میتواند همزمان باز داشته باشد.
اگر Process از Limit خودش عبور کند، معمولاً خطای EMFILE دریافت میکند. این همان حالتی است که اغلب با پیام Too many open files دیده میشود.
اما یک حالت دیگر نیز وجود دارد:
🔹 EMFILE: Process به Limit خودش رسیده است.
🔹 ENFILE: کل سیستم به سقف File Handle رسیده است.
File Descriptor فقط فایل معمولی نیست
نام خطا ممکن است این تصور را ایجاد کند که فقط فایلهای روی دیسک حساب میشوند، اما File Descriptor میتواند برای منابع مختلف مصرف شود:
🔹 فایلهای باز روی دیسک
🔹 TCP و UDP Socketها
🔹 Pipeها
🔹 Log Fileها
🔹 فایلهای دیتابیس
🔹 Connectionهای باز Web Server
به همین دلیل یک Web Server پرترافیک ممکن است بدون بازکردن هزاران فایل واقعی روی دیسک، تعداد زیادی File Descriptor برای Socketهای شبکه مصرف کند.
مرحله ۱: Limit فعلی Shell را بررسی کنید
این فرمان را در SSH اجرا کنید:
ulimit -n
این عدد Soft Limit مربوط به Shell فعلی را نشان میدهد.
برای دیدن Soft Limit و Hard Limit:
ulimit -Sn
ulimit -Hn
Soft Limit مقداری است که در حال حاضر روی Process اعمال میشود. Hard Limit سقفی است که کاربر معمولی نمیتواند Soft Limit را بالاتر از آن ببرد.
مرحله ۲: Limit واقعی Process مشکلدار را بررسی کنید
یکی از اشتباههای رایج این است که فقط ulimit -n در SSH بررسی شود؛ در حالی که Nginx، Docker، Redis یا برنامه شما ممکن است توسط systemd با Limit متفاوتی اجرا شده باشد.
ابتدا PID را پیدا کنید. برای مثال:
pidof nginx
برای یک Process مشخص، Limitها را ببینید:
cat /proc/PID/limits
بهجای PID شماره Process واقعی را قرار دهید.
در خروجی دنبال این خط بگردید:
Max open files
مرحله ۳: تعداد File Descriptorهای باز را بشمارید
برای Process موردنظر:
sudo ls /proc/PID/fd | wc -l
اگر Process مثلاً Limit برابر 1024 دارد و عدد File Descriptorهای باز مرتب به حدود همان مقدار میرسد، علت خطا تقریباً مشخص شده است.
برای دیدن Descriptorها:
sudo ls -l /proc/PID/fd
مرحله ۴: با lsof Process پرمصرف را بررسی کنید
اگر lsof روی سرور نصب است:
sudo lsof -p PID
برای شمردن تقریبی خروجی:
sudo lsof -p PID | wc -l
اگر تعداد Descriptorها مدام رشد میکند و پس از پایان Connectionها کاهش پیدا نمیکند، احتمال File Descriptor Leak یا Connection Leak وجود دارد.
مرحله ۵: کدام Process بیشترین فایل باز را دارد؟
برای بررسی عمومی میتوانید تعداد FDهای Processها را از /proc مقایسه کنید:
for pid in /proc/[0-9]*; do
count=$(ls "$pid/fd" 2>/dev/null | wc -l)
cmd=$(tr '\0' ' ' < "$pid/cmdline" 2>/dev/null | cut -c1-60)
echo "$count ${pid##*/} $cmd"
done | sort -nr | head -n 20
خروجی، Processهایی را که بیشترین File Descriptor باز دارند در بالای فهرست قرار میدهد.
مرحله ۶: Limit سرویس systemd را بررسی کنید
برای سرویسهایی که توسط systemd اجرا میشوند، این فرمان بسیار مهم است:
systemctl show SERVICE_NAME -p LimitNOFILE
بهجای SERVICE_NAME نام واقعی سرویس، مثلاً nginx یا redis-server را قرار دهید.
اگر Limit پایین است و مصرف واقعی سرویس آن را توجیه میکند، Override مخصوص systemd ایجاد کنید.
مرحله ۷: افزایش دائمی LimitNOFILE در systemd
بهجای ویرایش مستقیم Unit File اصلی، از Override استفاده کنید:
sudo systemctl edit SERVICE_NAME
در Editor این بخش را وارد کنید:
[Service]
LimitNOFILE=65536
عدد 65536 فقط یک نمونه رایج است. Limit باید بر اساس رفتار واقعی سرویس انتخاب شود، نه صرفاً برای حذف پیام خطا.
بعد از ذخیره:
sudo systemctl daemon-reload
sudo systemctl restart SERVICE_NAME
سپس مقدار جدید را بررسی کنید:
systemctl show SERVICE_NAME -p LimitNOFILE
برای اطمینان بیشتر PID جدید سرویس را پیدا کنید و /proc/PID/limits را نیز بررسی کنید.
سرویس پرترافیک روی VPS اجرا میکنید؟
در Web Server، Proxy، دیتابیس و سرویسهایی با Connection زیاد، تعداد File Descriptorهای همزمان میتواند بالا باشد. هنگام انتخاب سرور علاوه بر CPU و RAM، معماری برنامه و تعداد Connectionهای همزمان را نیز در نظر بگیرید.
تماس با پشتیبانی ایرانیکاسرور: 021-91302467
مرحله ۸: تغییر Limit برای Login Session و برنامههای دستی
اگر برنامه از Shell کاربر اجرا میشود و systemd Service نیست، تنظیمات PAM Limits میتواند مرتبط باشد.
بهتر است بهجای ویرایش مستقیم فایل اصلی، فایل جداگانه بسازید:
sudo nano /etc/security/limits.d/99-open-files.conf
برای User نمونه myapp:
myapp soft nofile 65536
myapp hard nofile 65536
بعد از ذخیره، Session قبلی الزاماً Limit جدید را دریافت نمیکند. از Session خارج شوید و Login جدید انجام دهید، سپس:
ulimit -Sn
ulimit -Hn
⚠️ تغییر limits.conf معمولاً روی سرویس systemd موجود همان اثری را ندارد که روی Login Session دارد. برای سرویسهای systemd از LimitNOFILE= استفاده کنید.
مرحله ۹: سقف nr_open را بررسی کنید
Linux یک سقف دیگر نیز دارد که مشخص میکند RLIMIT_NOFILE حداکثر تا چه عددی میتواند افزایش پیدا کند:
cat /proc/sys/fs/nr_open
در بسیاری از Linuxهای امروزی مقدار پیشفرض این سقف 1048576 است.
اگر میخواهید Hard Limit یک Process را بالاتر از این مقدار ببرید، ابتدا باید fs.nr_open را نیز بررسی کنید.
⚠️ برای اکثر سرویسها نیازی نیست این سقف را تغییر دهید. اگر برنامه به صدها هزار یا میلیونها Descriptor نیاز دارد، معماری، Connection Pool، Leak احتمالی و مصرف Kernel Memory باید قبل از بالا بردن این مقدار بررسی شوند.
مرحله ۱۰: محدودیت سراسری fs.file-max را بررسی کنید
این مقدار سقف سراسری File Handleهای سیستم را کنترل میکند:
sysctl fs.file-max
برای مشاهده تعداد File Handleهای تخصیصیافته و سقف سیستم:
cat /proc/sys/fs/file-nr
اگر تعداد File Handleهای تخصیصیافته به سقف سراسری نزدیک نیست، افزایش fs.file-max احتمالاً مشکل شما را حل نمیکند.
مرحله ۱۱: افزایش fs.file-max در صورت نیاز واقعی
اگر شواهد نشان میدهند واقعاً سقف سراسری سیستم پر شده است، میتوانید مقدار را موقتاً تغییر دهید. مثال:
sudo sysctl -w fs.file-max=1048576
عدد بالا فقط نمونه است و ممکن است سیستم شما از قبل مقدار دیگری داشته باشد. ابتدا مقدار فعلی را بخوانید و بدون دلیل آن را کاهش ندهید.
برای تنظیم دائمی، فایل جداگانه بسازید:
sudo nano /etc/sysctl.d/99-open-files.conf
مقدار موردنیاز:
fs.file-max=1048576
سپس:
sudo sysctl --system
مرحله ۱۲: اگر Limit بالا است ولی خطا ادامه دارد چه کنیم؟
اگر Process Limit مثلاً 65536 دارد ولی تعداد FDهای باز دائماً تا همین سقف رشد میکند، افزایش دوباره Limit احتمالاً فقط خطا را به تعویق میاندازد.
در این شرایط احتمالهای زیر را بررسی کنید:
🔹 Connection Leak در برنامه
🔹 فایلهایی که پس از استفاده Close نمیشوند
🔹 Connection Pool بدون سقف مناسب
🔹 تعداد بسیار زیاد Socketهای همزمان
🔹 Log Handler یا Watcherهای ایجادشده و آزادنشده
🔹 تنظیم اشتباه Worker یا Threadها
نمونه: رفع Too Many Open Files در Nginx
ابتدا Limit سرویس را ببینید:
systemctl show nginx -p LimitNOFILE
Override بسازید:
sudo systemctl edit nginx
مثال:
[Service]
LimitNOFILE=65536
سپس:
sudo systemctl daemon-reload
sudo nginx -t
sudo systemctl restart nginx
اگر تعداد Connectionهای واقعی Nginx بسیار زیاد است، تنظیمات Worker و Connectionها نیز باید با Limit جدید هماهنگ باشند؛ بالا بردن NOFILE بهتنهایی ظرفیت واقعی سرویس را تضمین نمیکند.
جدول تشخیص سریع Too Many Open Files
| نشانه | بررسی مناسب |
|---|---|
| یک سرویس خاص خطا میدهد | /proc/PID/limits و LimitNOFILE |
| برنامه دستی در SSH خطا میدهد | ulimit -Sn و ulimit -Hn |
| FDهای Process به Limit نزدیکاند | افزایش منطقی Limit و بررسی Leak |
| کل سیستم ENFILE میدهد | fs.file-max و file-nr |
| Limit بالاتر از یک مقدار نمیرود | fs.nr_open |
آیا بالا بردن ulimit همیشه درست است؟
خیر. اگر برنامه File Descriptor Leak داشته باشد، بالا بردن Limit فقط باعث میشود برنامه مدت بیشتری قبل از Crash کار کند و منابع بیشتری مصرف کند.
روش درست این ترتیب است:
🔹 Limit واقعی Process را پیدا کنید.
🔹 تعداد FDهای باز را اندازه بگیرید.
🔹 بررسی کنید عدد با بار واقعی سرویس منطقی است یا نه.
🔹 اگر Leak وجود ندارد، Limit را متناسب افزایش دهید.
🔹 پس از Restart دوباره Limit و تعداد FD را بررسی کنید.
پرسشهای متداول
خطای Too Many Open Files دقیقاً به چه معناست؟
معمولاً یعنی Process نتوانسته File Descriptor جدید باز کند، چون به RLIMIT_NOFILE خود رسیده است. اگر کل سیستم به سقف فایلهای باز برسد، خطای ENFILE رخ میدهد.
تفاوت ulimit -n با fs.file-max چیست؟
ulimit -n Limit مربوط به Process یا Shell را نشان میدهد، در حالی که fs.file-max سقف File Handleهای سراسری سیستم است.
برای systemd باید limits.conf را تغییر دهیم؟
برای یک سرویس systemd معمولاً روش مستقیمتر استفاده از LimitNOFILE= در Override همان سرویس است. limits.conf بیشتر برای Login Sessionهای PAM کاربرد دارد.
آیا LimitNOFILE=65536 برای همه مناسب است؟
خیر. 65536 فقط یک مقدار نمونه رایج است. مقدار مناسب باید بر اساس تعداد Connectionها، فایلها و رفتار واقعی برنامه انتخاب شود.
چرا بعد از تغییر ulimit سرویس هنوز همان Limit قبلی را دارد؟
زیرا سرویس ممکن است توسط systemd اجرا شده باشد و Limit آن از Shell فعلی شما به ارث نرسیده باشد. مقدار واقعی Process و LimitNOFILE سرویس را بررسی کنید.
چرا تعداد فایلهای باز برنامه مدام بیشتر میشود؟
ممکن است برنامه File Descriptor Leak یا Connection Leak داشته باشد. در این حالت باید منابعی که باز میشوند ولی بسته نمیشوند شناسایی شوند.
آیا برای اعمال Limit جدید باید سرور Reboot شود؟
معمولاً خیر. برای سرویس systemd کافی است Unit را Reload و سرویس را Restart کنید. برای Login Limit نیز یک Session جدید معمولاً کافی است.
منابع رسمی
🔹 Linux man-pages؛ RLIMIT_NOFILE و Resource Limitها
🔹 Linux man-pages؛ تفاوت EMFILE و ENFILE
🔹 Linux man-pages؛ fs.file-max، fs.nr_open و file-nr
جمعبندی
برای رفع Too Many Open Files ابتدا مشخص کنید مشکل در Limit همان Process است یا سقف سراسری سیستم. Limit واقعی سرویس را از /proc و systemd بررسی کنید و تعداد File Descriptorهای باز را اندازه بگیرید. اگر مصرف طبیعی سرویس از Limit بیشتر است، LimitNOFILE را متناسب افزایش دهید؛ اما اگر تعداد Descriptorها بدون کنترل رشد میکند، ابتدا File Descriptor Leak یا Connection Leak برنامه را برطرف کنید.
خطای Too Many Open Files هنوز برطرف نشده است؟
اگر سرویس شما بعد از افزایش Limit دوباره به سقف File Descriptor میرسد، میتوانید برای بررسی Processها، systemd، Connectionها و تنظیمات Kernel درخواست فنی ثبت کنید.
تماس با پشتیبانی ایرانیکاسرور: 021-91302467






دیدگاهها (۰)