ULimit для Nginx
Если ваш сайт работает под нагрузкой, рано или поздно вы столкнетесь с ошибкой Too many open files
в логах nginx
:
2020/05/11 15:10:09 [crit] 11930#0: accept4() failed (24: Too many open files)
2020/05/11 15:10:09 [crit] 11930#0: *1683144371 open() "/www/irk.ru/static/news/img/i-subject.png" failed (24: Too many open files), client: 109.163.217.157, server: static.irk.ru, request: "GET /static/news/img/i-subject.png?v=5a8e34c7 HTTP/1.1", host: "static.irk.ru", referrer: "https://static.irk.ru/static/css/compiled/compile/apps/news.c.css?v=5eb52151"
Если вбить ошибку в гугле, то появится много статей, большинство из которых скопировано друг с друга. Все они советуют проверить ulimit
:
$ ulimit -n
65536
Что в случае nginx
не имеет никакого смысла, потому что этот лимит задается для вашего сеанса работы с bash в системе.
А как проверить лимиты для работающего демона со множеством процессов?
Вот отличная команда:
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
вывод:
nginx: worker process
Limit Soft Limit Hard Limit Units
Max open files 4000 4000 files
Currently open files: 784
nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
Limit Soft Limit Hard Limit Units
Max open files 1024 4096 files
Currently open files: 12
Видите значения Soft Limit и Hard Limit? Это и есть лимиты. Насколько я понимаю, ориентироваться нужно на хардлимит.
Проведем небольшой эксперимент
У нас есть nginx
вот с таким конфигом:
worker_processes 1;
worker_rlimit_nofile 4000;
events {
worker_connections 768;
}
worker_rlimit_nofile
как раз отвечает за значения лимита
Где-то писали, что nginx
открывает по два файла на каждое соединение. Проверим, так ли это. Сейчас у меня на сервере около 750 соединеней. Я поставлю лимит чуть выше, например, на 800. И мы вместе посмотрим, что будет.
Перезапускаем nginx и смотрим.
При 750 активных соединениях, лимит в 800 открытых файлов не достигнут. Поэтому совершенно точно nginx
не открывает два файла на каждое соединение.
Скорее всего, он открывает один сокет (файловый хэндлер) для соединения с клинтом и один для файла, который будет читать. Когда файл прочитан, он закрывается. Но поскольку одномоментно у нас не так много чтений, и большая часто соединений просто висит в ожидании (http Keep-Alive) и занимает только один хэндл, то лимит не переполняется.
Поставим лимит 750
- близко к максимальному числу открытых соединений. Немного подождем. Через какое-то время воркер достигает лимита:
Limit Soft Limit Hard Limit Units
Max open files 750 750 files
Currently open files: 750
В соседнем окне консоли замельтешили ошибки. Значит, лимит должен быть не меньше, чем worker_connections
. Хотя это и так очевидно.
Проведя еще одни эксперимент, я выяснил, что значение задается для каждого воркера отдельно. Если у меня лимит в тысячу открытых файлов, то я могу держать хоть десять воркеров, лишь бы каждый из них не превысил пороговое значение.
Делаем выводы
Так какое же в итоге выставить значение worker_rlimit_nofile
для nginx
?
Я советую поставить worker_connections*2
. Если не будет хватать, увеличьте еще в два раза.
И вступайте в число моих подписчиков через старую добрую электронную почту - заполните форму ниже.