وبلاگ نت‌آرامآموزش، تجربه و راهکارهای زیرساخت

خطای Too many open files در لینوکس؛ کدام برنامه به محدودیت رسیده است؟

تشخیص محدودیت فایل‌های باز هر پردازش و کل سرور، بررسی نشت اتصال و تغییر کنترل‌شده LimitNOFILE در سرویس systemd.

انتشار:
توسط تیم فنی نت‌آرام
۸ دقیقه زمان مطالعه
۰ دیدگاه
محتوای تخصصی، ساده و کاربردی
هماهنگ با هویت حرفه‌ای نت‌آرام
بازگشت به لیست مقالات
تصویر شاخص مقاله خطای Too many open files در لینوکس؛ کدام برنامه به محدودیت رسیده است؟ در وبلاگ نت‌آرام
محتوای آموزشی وبلاگ نت‌آرام
سایت یا برنامه مدتی خوب کار می‌کند، بعد در گزارش خطا عبارت Too many open files ظاهر می‌شود. شاید برنامه دیگر نتواند فایلی باز کند یا اتصال تازه‌ای بپذیرد. این پیام الزاماً نمی‌گوید فضای دیسک پر شده است: لینوکس برای کارهایی مثل باز نگه‌داشتن فایل و سوکت شبکه از شناسه‌هایی به نام file descriptor استفاده می‌کند و تعداد آن‌ها محدود است.
گاهی یک پردازش به سقف خودش رسیده، گاهی تعداد فایل‌های باز کل سیستم مسئله است و گاهی برنامه اتصال‌ها را پس از پایان کار نمی‌بندد. در این آموزش ابتدا نوع خطا و پردازش واقعی را پیدا می‌کنیم؛ بعد اگر لازم بود، محدودیت همان سرویس را با برنامه بازگشت تغییر می‌دهیم.

پیش‌نیاز و یک تفاوت مهم

این راهنما برای لینوکس دارای systemd نوشته شده است. دستورها را پس از اتصال SSH در ترمینال سرور خودتان اجرا کنید. برای خواندن گزارش بعضی سرویس‌ها یا دیدن اطلاعات پردازش‌های دیگر ممکن است sudo لازم باشد. روی هاست اشتراکی معمولاً به تنظیم سرویس اصلی دسترسی ندارید؛ در آن حالت زمان خطا و نام سایت را نگه دارید و از مدیر هاست بخواهید محدودیت و علت را بررسی کند.
در سرور تولیدی، قبل از راه‌اندازی مجدد هر سرویس، زمان کم‌ترافیک و امکان دسترسی جایگزین را آماده کنید. راه‌اندازی مجدد وب‌سرور یا برنامه می‌تواند اتصال کاربران را برای مدت کوتاهی قطع کند. اگر داده مهمی در حافظه برنامه است، از روش خاموش‌کردن و بازیابی همان برنامه مطمئن شوید.
در پیام‌های فنی دو وضعیت نزدیک وجود دارد: خطای EMFILE معمولاً به محدودیت فایل‌های باز یک پردازش مربوط است و ENFILE به محدودیت سراسری سیستم اشاره می‌کند. پیام ساده انگلیسی به‌تنهایی همیشه نوع دقیق را نشان نمی‌دهد؛ نام خطا و زمینه گزارش را بخوانید. راهنمای خطاهای لینوکس تفاوت این دو را توضیح می‌دهد.

قدم اول: نام سرویس و زمان وقوع خطا را پیدا کنید

اگر نام سرویس را می‌دانید، در دستور زیر example.service را با نام واقعی آن جایگزین کنید؛ مثلاً ممکن است سرویس شما نام دیگری برای وب‌سرور یا برنامه داشته باشد:
کد / دستورsudo journalctl -u example.service -n 100 --no-pager
این فرمان صد خط آخر گزارش همان واحد systemd را نشان می‌دهد و چیزی را تغییر نمی‌دهد. به زمان خطا، نام برنامه و شناسه پردازش در گزارش توجه کنید. اگر خطا مربوط به سرویس دیگری است، بررسی را برای همان سرویس تکرار کنید. گزارش ممکن است مسیر فایل یا اطلاعات خصوصی داشته باشد؛ پیش از اشتراک‌گذاری آن‌ها را حذف کنید.
اگر سرویس تحت systemd نیست یا داخل کانتینر اجرا می‌شود، باید پردازش و محدودیت را از محیط اجرای خودش پیدا کنید؛ دستورهای تغییر واحد systemd در ادامه را نمی‌توان بدون تطبیق برای هر کانتینر یا پنل استفاده کرد. اگر خطا را در گزارش برنامه می‌بینید ولی نام پردازش روشن نیست، مدیر برنامه می‌تواند از همان زمان و متن خطا برای پیدا کردن پردازش مسئول کمک بگیرد.

قدم دوم: محدودیت واقعی همان پردازش را ببینید

برای دیدن شناسه پردازش اصلی یک سرویس systemd، نام واقعی سرویس را جایگزین کنید:
کد / دستورsystemctl show example.service -p MainPID --value
خروجی عددی مانند 1234 است. عدد 0 معمولاً نشان می‌دهد در آن لحظه پردازش اصلی فعالی معرفی نشده است؛ در این صورت ابتدا وضعیت سرویس را با systemctl status example.service ببینید. برای ادامه، به‌جای عدد نمونه زیر، شناسه واقعی را قرار دهید:
کد / دستورTARGET_PID=1234 cat /proc/$TARGET_PID/limits
در خروجی، سطر Max open files را پیدا کنید. ستون‌های Soft Limit و Hard Limit محدودیت نرم و سخت همان پردازش را نشان می‌دهند. محدودیت نرم سقفی است که اکنون برای پردازش اعمال می‌شود؛ برنامه در چارچوب محدودیت سخت و مجوزهایش می‌تواند آن را تغییر دهد.
نکته مهم: سرویس‌هایی مانند وب‌سرور ممکن است چند پردازش کارگر داشته باشند. پردازش اصلی الزاماً همان پردازشی نیست که خطا را تولید کرده است. اگر گزارش، شناسه پردازش کارگر را نشان می‌دهد، همین بررسی را برای آن شناسه هم انجام دهید. اگر پردازش بین دو دستور پایان یافته و شناسه‌اش دوباره استفاده شده باشد، نتیجه ممکن است مربوط به برنامه دیگری باشد؛ نام و زمان پردازش را دوباره تطبیق دهید.

قدم سوم: تعداد فایل‌های باز و نوع آن‌ها را مقایسه کنید

پس از قرار دادن شناسه واقعی در TARGET_PID، این فرمان تعداد ورودی‌های پوشه فایل‌های باز آن پردازش را می‌شمارد:
کد / دستورsudo ls -1 /proc/$TARGET_PID/fd | wc -l
اگر مثلاً محدودیت نرم ۱۰۲۴ و تعداد مشاهده‌شده نزدیک به همان عدد است، رسیدن پردازش به سقف محتمل است. این عدد یک عکس لحظه‌ای است؛ ممکن است در زمان اوج بیشتر بوده و اکنون پایین آمده باشد. پردازش ممکن است هم‌زمان فایل باز و بسته کند، پس به جای نتیجه یک‌بار، در چند زمان و همراه گزارش خطا مقایسه کنید. اگر Permission denied یا نبودن مسیر دیدید، مجوز و زنده بودن شناسه پردازش را بررسی کنید.
برای دیدن نوع برخی ورودی‌ها می‌توانید دستور زیر را اجرا کنید:
کد / دستورsudo ls -l /proc/$TARGET_PID/fd | head -n 30
خروجی ممکن است مسیر فایل‌ها یا عباراتی مانند socket:[...] و pipe:[...] داشته باشد. فقط ۳۰ سطر اول نمایش داده می‌شود؛ بنابراین برای قضاوت درباره کل پردازش کافی نیست. مسیرهای خصوصی ممکن است در خروجی باشند. اگر تعداد سوکت‌ها یا فایل‌های یک نوع دائماً زیاد می‌شود و پس از پایان درخواست‌ها پایین نمی‌آید، احتمال بازماندن اتصال‌ها یا خطای برنامه را با توسعه‌دهنده بررسی کنید. به‌روزرسانی یا اصلاح همان برنامه می‌تواند علت را برطرف کند؛ صرف افزایش سقف ممکن است فقط زمان بروز خطا را عقب بیندازد.

اگر خطا سراسری است، چه چیزی را ببینیم؟

اگر گزارش صراحتاً ENFILE یا پیام رسیدن فایل‌های باز کل سیستم به سقف را نشان می‌دهد، این فایل آمار سراسری را بخوانید:
کد / دستورcat /proc/sys/fs/file-nr
سه عدد مربوط به شمار تخصیص‌یافته، شمار استفاده‌نشده و سقف سراسری هستند؛ معنای دقیق آن‌ها با نسخه کرنل ارتباط دارد. شمار سراسری «توصیف فایل باز» دقیقاً با جمع ساده شناسه‌های همه پردازش‌ها یکسان نیست، چون بعضی ارجاع‌ها می‌توانند مشترک باشند. مقایسه نزدیک‌شدن عدد مصرفی به سقف همراه گزارش کرنل یک سرنخ است، نه مجوز تغییر فوری تنظیمات. مستندات فایل‌های تنظیمات کرنل این مقادیر را شرح می‌دهد.
اگر مصرف سراسری به علت برنامه‌ای در حال رشد است، ابتدا همان برنامه یا اتصال‌هایش را پیدا کنید. افزایش بی‌حساب سقف سراسری می‌تواند مصرف منابع را بیشتر کند و مشکل اصلی را پنهان کند. بررسی آن در سرورهای مهم بهتر است با مدیر سیستم و متناسب با حافظه و ظرفیت واقعی انجام شود.

اگر سقف خود سرویس کم است، تغییر کنترل‌شده بدهید

این مرحله فقط برای سرویس systemd است و باید پس از شناسایی پردازش و بررسی سازگاری خود برنامه انجام شود. بعضی برنامه‌های قدیمی از سازوکاری استفاده می‌کنند که با شناسه‌های فایل بالاتر از ۱۰۲۳ مشکل دارد؛ بالابردن محدودیت بدون تأیید سازگاری می‌تواند خطای تازه بسازد. مستندات systemd درباره LimitNOFILE این نکته را توضیح می‌دهد.
اگر سازنده برنامه و مدیر سرور افزایش سقف را مناسب می‌دانند، نام واقعی سرویس را در فرمان زیر قرار دهید:
کد / دستورsudo systemctl edit example.service
ویرایشگر یک فایل تنظیم تکمیلی برای همان سرویس باز می‌کند. مثال زیر فقط برای حالتی است که محدودیت قبلی پردازش نرم ۱۰۲۴ و سخت ۵۲۴۲۸۸ بوده و سازگاری برنامه با سقف نرم ۸۱۹۲ تأیید شده است. عدد دوم را از محدودیت سخت فعلی همان سرویس و برنامه تغییر خودتان تعیین کنید تا ناخواسته سقف سخت را پایین نیاورید؛ مقدار مناسب به برنامه و ظرفیت سرور بستگی دارد:
کد / دستور[Service] LimitNOFILE=8192:524288
فایل را ذخیره کنید و از ویرایشگر خارج شوید. systemd معمولاً پس از ذخیره تغییر واحد را بازخوانی می‌کند، اما پردازش در حال اجرا محدودیت جدید را خودکار نمی‌گیرد. پیش از راه‌اندازی مجدد، تنظیم ثبت‌شده را با فرمان زیر ببینید:
کد / دستورsystemctl show example.service -p LimitNOFILE -p LimitNOFILESoft
اگر قرار است سرویس از نو راه‌اندازی شود، از زمان و اثر آن روی کاربران مطمئن شوید، سپس نام واقعی را جایگزین کنید:
کد / دستورsudo systemctl restart example.service
پس از آن، systemctl status example.service را بخوانید و شناسه جدید پردازش را دوباره به دست آورید. سپس با /proc/TARGET_PID/limits برای همان شناسه جدید، مقدار واقعی Max open files را کنترل کنید. در این مسیر، TARGET_PID فقط جای نمونه شناسه است؛ مسیر واقعی برای مثال /proc/1234/limits خواهد بود. وضعیت فعال سرویس به‌تنهایی کافی نیست: سایت یا برنامه و ثبت درخواست واقعی را نیز آزمایش کنید.
اگر رفتار بدتر شد، همان فایل تکمیلی را با systemctl edit example.service باز کنید و فقط خطی را که در این تغییر افزوده‌اید بردارید؛ سایر تنظیمات قبلی را حفظ کنید. پس از ذخیره، در زمان مناسب سرویس را دوباره راه‌اندازی و مقدار واقعی را کنترل کنید. دستور کلی برای پاک‌کردن همه تنظیمات سفارشی سرویس اجرا نکنید.

چرا تغییر ulimit در SSH کافی نیست؟

فرمان ulimit -n محدودیت پوسته فعلی را نشان می‌دهد. اگر در نشست SSH آن را تغییر دهید، معمولاً سرویس مستقلی که systemd پیش‌تر اجرا کرده محدودیت تازه را از این نشست نمی‌گیرد. بنابراین نتیجه داخل ترمینال را با محدودیت پردازش سرویس در /proc اشتباه نگیرید.
پس از رفع مشکل، برای مدتی تعداد فایل‌های باز و خطاهای همان سرویس را زیر نظر داشته باشید. اگر شمار فایل‌ها دوباره پیوسته افزایش می‌یابد، علت برنامه یا بار غیرعادی هنوز باقی است. برای شناخت گزینه‌های منابع و مدیریت مستقل، مشخصات سرور مجازی ایران نت‌آرام را ببینید؛ تغییر سرویس میزبانی به‌تنهایی جای اصلاح نشت فایل یا اتصال را نمی‌گیرد.
اشتراک‌گذاری:
لینکدینتلگرامایکس

دیدگاه‌ها (۰)

دیدگاه‌های تاییدشده و پاسخ‌های تیم نت‌آرام