Сайты не открываются, в логах ошибки: (24)Too many open files

Описание ситуации

Как только на веб-сервер возрастает нагрузка, он перестаёт работать. В /var/log/httpd/error.log есть сообщения вида:

[Mon Sep 07 12:50:44 2009] [error] (24)Too many open files: mod_fcgid: couldn't set child process attributes: /var/lib/httpd/
fcgid/sock/8959.1
[Mon Sep 07 12:50:45 2009] [warn] (24)Too many open files: mod_fcgid: spawn process /var/virtual/www/domain.com/subdomains/
lab/httpdocs/dispatch.fcgi error
Couldn't write to "/var/virtual/www/domain.com/subdomains/lab/httpdocs/log/fcgi_crash.log": starting
  Errno::EACCES: Permission denied - /var/virtual/www/domain.com/subdomains/lab/httpdocs/log/fcgi_crash.log
[Mon Sep 07 13:08:02 2009] [notice] child pid 30185 exit signal Segmentation fault (11)
[Mon Sep 07 13:09:08 2009] [error] [client ::1] (24)Too many open files: file permissions deny server access: /var/www/html/i
ndex.html

в логах сайтов видны ошибки вида:

[Mon Sep 07 13:07:43 2009] [crit] [client xxx.xxx.xxx.xxx] (24)Too many open files: /var/virtual/www/.htaccess pcfg_openfile: u
nable to check htaccess file, ensure it is readable, referer: http://www.domain.com/#1812807
[Mon Sep 07 13:08:23 2009] [error] [client xxx.xxx.xxx.xxx] (24)Too many open files: file permissions deny server access: /home/domain.com/httpdocs/favicon.ico

Возможное решение

Первым делом необходимо убедиться, что в системе установлено необходимое количество открытых файлов:

sysctl -a|grep file
fs.file-max = 800826
fs.file-nr = 9728	0	800826

По этой записи видно, что максимальное число открытых файлов установлено в 800826, а открыто только 9728. Современные дистрибутивы умеют динамически управлять значением fs.file-max и в большинстве случаев вам не нужно будет изменять это значение. Однако, устаревшие версии могут этого не уметь! Если вы увидите, что в fs.file-nr левое и правое значение приблизительно одинаковы, вам необходимо увеличить значение fs.file-max командой:

sysctl fs.file-max=значение

Как видим, теперь всё в порядке - системе разрешено открывать файлов намного больше, чем открыто в текущий момент. Однако, это ещё не всё.

Вторым делом, добавляем в /etc/sysconfig/httpd (а если у вас самосборный apache, то в скрипт запуска apache) строчку:

ulimit -n 65535

Цифра 65535 - это не догма. Надо больше - ставьте больше, надо меньше, ставьте меньше.

Перезапускаем веб-сервер и смотрим. Если проблема осталась, читаем далее

В Linux есть ещё и такая штука как file handles или FD. По странному стечению обстоятельств (вопросы не ко мне, а к разработчикам ядра) эти самые file handles никак не привязаны к fs.file-max. Более того, значение FD жёстко задано в include-файлах и вкомпилировано в ваш веб-сервер и другие программы. Как раз это значение возможно и мешает работать веб-серверу, если он обслуживает множество сайтов и клиентов. Итак, ищем файлы:

# grep "#define.[ \t]*__FD_SETSIZE" /usr/include/*.h /usr/include/*/*.h
/usr/include/bits/typesizes.h:#define	__FD_SETSIZE		1024
/usr/include/linux/posix_types.h:#define __FD_SETSIZE	1024

Вот собственно они! Теперь вам необходимо изменить 1024 на 65535, а затем собрать заново из исходных текстов ваш веб-сервер Apache, а лучше ещё и PHP! Собирать надо именно из исходных текстов, потому что иначе эти новые параметры никак в код не попадут! Разумеется, что собирать можно из исходных текстов пакетов (.src.rpm и др.)