Очень часто при работе на высоконагруженных Linux серверах могут возникать ошибки “too many open files”. Это означает, что процесс открыл слишком много файлов (читай файловых дескрипторов) и не может открыть новые. В Linux ограничения “max open file limit“ установлены по умолчанию для каждого процесса и пользователя, и они не слишком высокие.
В данной статье мы рассмотрим, как проверить текущие ограничения на количество открытых файлов в Linux, как изменить этот параметр для всего сервера, для отдельных сервисов и для сеанса. Статья применима для большинства современных дистрибутивов Linux (Debian, Ubuntu, CentOS, RHEL, Oracle Linux, Rocky и т.д.)
Содержание:
- Ошибка: Too many open files и лимиты на количество открытых файлов в Linux
- Глобальные ограничения на количество открытых файлов в Linux
- Увеличить лимит открытых файловых дескрипторов для отдельного сервиса
- Увеличить количество открытых файлов для Nginx и Apache
- Лимиты file-max для текущей сессии
Ошибка: Too many open files и лимиты на количество открытых файлов в Linux
Чаще всего ошибку “too many open files“. Чаще всего эта ошибка встречается на серверах с установленным веб-сервером NGINX/httpd, сервером БД (MySQL/MariaDB/PostgreSQL), при чтении большого количества логов. Например, когда веб-серверу Nginx не хватает лимита для открытия файлов, вы получите ошибку:
socket () failed (24: Too many open files) while connecting to upstream
Или:
HTTP: Accept error: accept tcp [::]:<port_number>: accept4: too many open files.
В Python:
OSError: [Errno 24] Too many open files.
Максимально количество файловых дескрипторов, которые могут быть открыты в вашей файловой системе всеми процессами можно узнать так:
# cat /proc/sys/fs/file-max
Чтобы узнать, сколько файлов открыто сейчас, выполните:
$ cat /proc/sys/fs/file-nr
7744 521 92233720
- 7744 — суммарное количество открытых файлов
- 521– число открытых файлов, но которые сейчас не используются
- 92233720– максимальное количество файлов, которое разрешено открывать
В Linux ограничение на максимальное количество открытых файлов можно натсроить на нескольких уровнях:
- Ядра ОС
- Сервиса
- Пользователя
Чтобы вывести текущее ограничение на количество открытых файлов в ядре Linux, выполните:
# sysctl fs.file-max
fs.file-max = 92233720
Выведем ограничение на количество открытых файлов для одного процесса текущего пользователя:
# ulimit -n
По умолчанию количество файлов для одного процесса этого ограничено числом 1024.
Выведем максимальное количество для одного пользователя (max user processes):
# ulimit –u
5041
Умножаем 1024 * 5041 дает нам 5161984 – это максимально количество открытых файлов всеми процессами пользователя.
В Linux есть два типа ограничений на количество открытых файлов: Hard и Soft. Soft ограничения носят рекомендательный характер, при превышении значения пользователь будет получать предупреждения. Если количество открытых файлов превысило hard лимит, пользователь не сможет открыть новые файлы пока не будет закрыты ранее открытые.
Для просмотра текущих лимитов используется команда ulimit с опцией
-S
(soft) или
-H
(hard) и параметром
-n
(the maximum number of open file descriptors).
Для вывода Soft-ограничения:
# ulimit -Sn
Для вывода Hard-ограничения:
# ulimit -Hn
Глобальные ограничения на количество открытых файлов в Linux
Чтобы разрешить всем сервисам открывать большее количество файлов, можно изменить лимиты на уровне всей ОС Linux. Чтобы новые настройки работали постоянно и не сбрасывались при перезапуске сервера или сессии, нужно поправить файл /etc/security/limits.conf. Строки с разрешениями выглядит так:
Имя_пользователя тип_огрничение название_ограничения значение
Например:
apache hard nofile 978160 apache soft nofile 978160
Вместо имени пользователя можно указать
*
. Это означает, что это ограничение будет применяться для всех пользователей Linux:
* hard nofile 97816 * soft nofile 97816
Например, вы получили ошибку too many open files для nginx. Проверьте, сколько файлов разрешено открывать процессу этому пользователю:
$ sudo -u nginx bash -c 'ulimit -n'
1024
Для нагруженного сервера этого недостаточно. Добавьте в /etc/security/limits.conf строки
nginx hard nofile 50000 nginx soft nofile 50000
В старых ядрах Linux значение fs.file-max может быть равно 10000. Поэтому проверьте это значение и увеличьте его, чтобы оно было больше чем ограничение в limits.conf:
# sysctl -w fs.file-max=500000
Это временно увеличит лимит. Чтобы новые настройки стали постоянными, нужно добавить в файл /etc/sysctl.conf строку:
fs.file-max = 500000
Проверьте, что в файле /etc/pam.d/common-session (Debian/Ubuntu или /etc/pam.d/login для CentOS/RedHat/Fedora) есть строчка:
session required pam_limits.so
Если нет, добавьте ее в конец. Она нужна, чтобы ограничения загружались при авторизации пользователя.
После изменений, перезапустите терминал и проверьте значение лимита max_open_files:
# ulimit -n
97816
Увеличить лимит открытых файловых дескрипторов для отдельного сервиса
Вы можете изменить лимит на количество открытых файловых дескрипторов для конкретного сервиса, а не для всей системы. Рассмотрим на примере apache. Чтобы изменить значения, откройте настройки службы через systemctl:
# systemctl edit httpd.service
Добавьте необходимые лимиты, например:
[Service] LimitNOFILE=16000 LimitNOFILESoft=16000
После изменения, нужно обновить конфигурацию сервиса и перезапустить его:
# systemctl daemon-reload
# systemctl restart httpd.service
Чтобы проверить, изменились ли значения, нужно получить PID сервиса:
# systemctl status httpd.service
Например, вы определил PID сервиса 32724:
# cat /proc/32724/limits | grep "Max open files”
Значение должно быть 16000.
Так вы изменили значения Max open files для конкретного сервиса.
Увеличить количество открытых файлов для Nginx и Apache
После того, как вы увеличил ограничения на количество открытых файлов для сервера, нужно также поправить конфигурационный файл службы. Например, для веб-сервера Nginx в файле конфигурации /etc/nginx/nginx.conf нужно задать значение в директиве:
worker_rlimit_nofile 16000
Директива worker_rlimit_nofile задает ограничение на количество файлов, открытых в рабочем процессе (
RLIMIT_NOFILE
). В Nginx файловые дескрипторы нужны для возврата статического файла из кэша для каждого подключения клиента. Чем больше пользователей использует ваш сервер и чем больше статических файлов отдает nginx, тем большее количество дескрипторов используется. Сверху максимальное количество дескрипторов ограничивается на уровне ОС и/или сервиса. При превышении количеств открытых файлов nginx появится ошибка
socket() failed (24: Too many open files) while connecting to upstream
.
При настройке Nginx на высоконагруженном 8-ядерном сервере с worker_connections 8192 нужно в worker_rlimit_nofile указать 8192*2*8 (vCPU) = 131072.
После чего выполнить рестарт Nginx:
# nginx -t && service nginx -s reload
Чтобы увидеть чисто открытых файлов для процессов пользователя nginx:
# su nginx
# ulimit –Hn
# for pid in `pidof nginx`; do echo "$(< /proc/$pid/cmdline)"; egrep 'files|Limit' /proc/$pid/limits; echo "Currently open files: $(ls -1 /proc/$pid/fd | wc -l)"; echo; done
Для apache, нужно создать директорию:
# mkdir /lib/systemd/system/httpd.service.d/
После этого создайте файл limit_nofile.conf:
# nano /lib/systemd/system/httpd.service.d/limit_nofile.conf
И добавьте в него:
[Service] LimitNOFILE=16000
Не забудьте перезапустить сервис httpd.
Лимиты file-max для текущей сессии
Чтобы изменить лимиты на открытые файлы в рамках текущей сессии пользователя, выполните команду:
# ulimit -n 3000
Если указать здесь значение большее, чем заданное в hard limit, появится ошибка:
-bash: ulimit: open files: cannot modify limit: Operation not permitted
Когда вы завершите текущую сессию терминала и откроете новую, лимиты вернутся к начальным значениям, указанным в файле /etc/security/limits.conf.
В данной статье мы разобрались, как решить проблему с недостаточным лимитом для открытых файловых дескрипторов в Linux и рассмотрели несколько вариантов изменения лимитов на сервере.
17 Nov 2016 | Автор: dd |
Стал тут у меня один из свежеустановленных веб-серверов под NGINX вываливаться в 500 ошибку. В логах обнаружилась следующая запись: socket () failed (24: Too many open files) while connecting to upstream …
Это означает что мы уперлись в лимиты открытых файлов для нашего веб-сервера. Оценить количество открытых файлов для процесса можно с помощью выражения:
# for pid in `pidof nginx`; do echo "$(< /proc/$pid/cmdline)"; egrep 'files|Limit' /proc/$pid/limits; echo "Currently open files: $(ls -1 /proc/$pid/fd | wc -l)"; echo; done
как видим при лимите в 1024 файлов, открыто почти в притык. Лимиты системы мы можем просмотреть в выводе команды:
# ulimit -a
или же собственно лимиты открытых файлов
# ulimit -n
Чтобы увеличить лимит открытых файлов в системе, выполняем команду
# ulimit -n 16384
и ребутим машину.
После чего идем править конфиг nginx: /etc/nginx/nginx.conf и в самом начале файла, в разделе # Server globals добавляем значение worker_rlimit_nofile 16384 и меняем в # Worker config значение worker_connections на число полученное делением worker_rlimit_nofile на worker_processes
#### /etc/nginx/nginx.conf
# Server globals
user nginx;
worker_processes 2;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
worker_rlimit_nofile 16384;
# Worker config
events {
worker_connections 8129;
use epoll;
}
#########
где worker_connections – максимальное число соединений, доступное для открытия процессом
worker_rlimit_nofile – максимальное чилсо открытых файлов для рабочих процессов
worker_processes – соответствует числу ядер процессора, которые можно посмотреть командой
# lscpu | grep '^CPU(s)'
после этих манипуляций рестартим NGINX
# service nginx restart
Rating: 3.6/10 (62 votes cast)
Rating: -4 (from 12 votes)
Исчерпание ресурсов веб-сервера NGINX, 3.6 out of 10 based on 62 ratings
Теги: nginx, настройка системы, сайты
Описание проблемы
Во процессе обслуживания высокого количества соединений (высокая нагрузка), в логе ошибок Вашего сервера могут появляться записи 24: Too Many Open Files. Происходит это потому что сервер nginx пытается открыть больше файловых дескрипторов чем ему позволено. Ограничение может быть наложено конфигурацией nginx сервера или конфигурацией операционной системы. На каждое соединение nginx открывает как минимум два дескриптора, один для соединения, второй для передаваемого файла.
Диагностика
Для выяснение причин проведем короткую диагностику. Прежде всего посмотрим конфигурационный файл nginx, обычно он расположен в
/etc/nginx/nginx.conf
Нас интерисуют следующие строки
user [xxx]; worker_processes [x]; worker_rlimit_nofile [xxx]; events { worker_connections [xxxx]; }
user — от имени какого пользователя nginx работает в системе, нам необходимо будет проверить лимиты для данного пользователя.
worker_processes — кол-во процессов nginx работающих при запуске демона, так как лимит операционной системы общий для всех процессов, соответственно нам надо будет устанавливать лимиты исходя из кол-ва процессов.worker_rlimit_nofile — максимальное кол-во файловых дескрипторов на один процесс.
worker_connections (может присутствовать только в контексте events) — максимальное кол-во соединений на один процесс.
Далее выясним лимиты установленные операционной системой, для этого перейдем под пользователя nginx
su nginx
Если получаем от OS сообщение вида
This account is currently not available.
Значит в файле /etc/passwd для нашего пользователя указана оболочка запрещающая вход в систему и работу с консолью, например /sbin/nologin
Отредактируем файл /etc/passwd, заменим строку
nginx:x:500:500:nginx user:/var/cache/nginx:/sbin/nologin
на строку
nginx:x:500:500:nginx user:/var/cache/nginx:/bin/bash
и вновь выполним su nginx.
Теперь посмотрим лимиты:
ulimit -Hn ulimit -Sn
-Hn — жесткий лимит максимального кол-ва открытых файловых дискрипторов
-Sn — мягкий лимит максимального кол-ва открытых файловых дискрипторов
Отличие между жестким и мягким лимитами в том, что жесткий может быть установлен только root пользователем, а мягкий может быть установлен пользователем на которого наложен лимит, но не больше чем жесткий лимит.
Теперь мы знаем текущие ограничения OS наложенные на пользователя nginx, можно выйти из под su
exit
Посмотрим глобальное ограничение на количество дескрипторов, для этого выполним команду
sysctl fs.file-max
Итак мы значем все ограничения, теперь попробуем сделать так чтобы наш nginx получил возможность открывать столько дескрипторов, сколько ему нужно.
Решение проблемы
Посчитаем сколько нам нужно дескрипторов для nginx
(worker_connections * 4 * worker_processes) + 100 = примерно нужное кол-во дескрипторов
Соответственно для будущего расширения это значение можно умножить еще на два и задавать лимиты.
Например, (1024 * 4 * 2) + 100 = 8292
Значение не большое, можно его свободно увеличить до 25000
Устанавливаем глобальные лимиты операционной системы, в файле /etc/sysctl.conf прописываем или изменяем строку:
fs.file-max = 203463
Устанавливаем лимиты на пользователя, в файле /etc/security/limits.conf прописываем или изменяем строки:
nginx soft nofile 25000 nginx hard nofile 50000
Применяем установленные лимиты к системе
sysctl -p
Проверяем что все применилось
sysctl fs.file-max su nginx ulimit -Hn ulimit -Sn exit
Устанавливаем лимиты для nginx
worker_rlimit_nofile 12500
Перезагружаем конфигурацию nginx
nginx -s reload
Ошибка более не должна повторяться.
Возвращаем shell для nginx в файле /etc/passwd в исходное состояние
nginx:x:500:500:nginx user:/var/cache/nginx:/sbin/nologin
На одном из серверов в логе ошибок веб-сервера Nginx появились сообщения вида
2017/11/22 08:21:02 [crit] 29098#29098: *174583882 open() "/var/www/public/blackfriday/img/tabs/img4.png" failed (24: Too many open files), client: 176.113.144.142, server: example.com, request: "GET /blackfriday/img/tabs/img4.png HTTP/2.0", host: "example.com"
Давайте разберемся как исправить данную ошибку в операционной системе Centos 7!
Смотрим текущие soft
/hard
лимиты файловых дескрипторов и открытых файлов для основного (master) процесса Nginx:
cat /proc/$(cat /var/run/nginx.pid)/limits|grep open.files
Max open files 1024 4096 files
и для дочерних (worker) процессов:
ps --ppid $(cat /var/run/nginx.pid) -o %p|sed '1d'|xargs -I{} cat /proc/{}/limits|grep open.files
Max open files 1024 4096 files
Max open files 1024 4096 files
Max open files 1024 4096 files
Открываем на редактирование конфигурационный файл /etc/security/limits.conf
и вставляем в него следующие строки:
...
nginx soft nofile 10000
nginx hard nofile 30000
В конфигурациооный файл nginx.conf
добавляем следующую строку:
...
worker_rlimit_nofile 30000;
...
Проверим конфигурацию веб-сервера на предмет ошибок и перечитаем конфиг:
nginx -t && nginx -s reload
Проверим новые лимиты, установленные для дочерних процессов веб-сервера Nginx:
ps --ppid $(cat /var/run/nginx.pid) -o %p|sed '1d'|xargs -I{} cat /proc/{}/limits|grep open.files
Max open files 10000 30000 files
Max open files 10000 30000 files
Max open files 10000 30000 files
Новые лимиты могут примениться не ко всем дочерним процессам веб-сервера, в таком случае необходимо перезапустить nginx
с помощью команды:
service nginx restart
[I posted this on the Nginx forums, but had no responses a week later, so trying here]
I am a Linux and Nginx novice, but have learnt enough to get it installed and running and working as a simple reverse proxy for two internal webservers. This has been running fine for months, but I recently started getting 500 errors.
Here is the recent output of /var/log/nginx/error.log
(I have replaced our company name with «companyname.com» and replaced our public WAN IP address with
2020/02/10 15:17:49 [alert] 1069#1069: *1011 socket() failed (24: Too many open files) while connecting to upstream, client: 10.10.10.1, server: web1.companyname.com, request: "GET / HTTP/1.0", upstream: "https://<WANIP>:443/", host: "web1.companyname.com"
2020/02/10 15:21:41 [alert] 1069#1069: *2022 socket() failed (24: Too many open files) while connecting to upstream, client: 10.10.10.1, server: web2.companyname.com, request: "GET / HTTP/1.0", upstream: "https://<WANIP>:443/", host: "web2.companyname.com"
2020/02/10 15:33:28 [alert] 1084#1084: *19987 socket() failed (24: Too many open files) while connecting to upstream, client: 10.10.10.1, server: web2.companyname.com, request: "GET / HTTP/1.0", upstream: "https://<WANIP>:443/", host: "web2.companyname.com"
2020/02/10 15:34:16 [alert] 1084#1084: *39974 socket() failed (24: Too many open files) while connecting to upstream, client: 10.10.10.1, server: web1.companyname.com, request: "GET / HTTP/1.0", upstream: "https://<WANIP>:443/", host: "web1.companyname.com"
2020/02/10 15:50:30 [error] 1086#1086: *1 client intended to send too large body: 4294967295 bytes, client: 176.58.124.134, server: london.companyname.com, request: "GET /msdn.cpp HTTP/1.1", host: "<WANIP>"
2020/02/10 16:32:56 [alert] 1086#1086: *19989 socket() failed (24: Too many open files) while connecting to upstream, client: 10.10.10.1, server: web1.companyname.com, request: "GET / HTTP/1.0", upstream: "https://<WANIP>:443/", host: "web1.companyname.com"
I have added the following to the end of /etc/security/limits.conf
nginx soft nofile 10000
nginx hard nofile 30000
I have added the following to /etc/sysctl.conf
fs.file-max=70000
…And rebooted. However, I’m getting the same problem immediately after a reboot.
Interestingly the IP address that appears in the log «176.58.124.134
» I don’t recognise and a quick google search suggests this is an abusive IP address. I can block at the firewall, but I’m not sure that’s the problem.
Any tips, suggestions are grealy appreciated. Thanks.