Если ваш сайт работает под нагрузкой, рано или поздно вы столкнетесь с ошибкой 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. Если не будет хватать, увеличьте еще в два раза.

И вступайте в число моих подписчиков через старую добрую электронную почту - заполните форму ниже.