Socket accept - " слишком много открытых файлов"
Я работаю над школьным проектом, где мне пришлось написать многопоточный сервер, и теперь я сравниваю его с apache, проводя некоторые тесты против него. Я использую autobench, чтобы помочь с этим, но после того, как я выполняю несколько тестов, или если я даю ему слишком высокую скорость (около 600+), Чтобы сделать соединения, я получаю ошибку "слишком много открытых файлов".
После того, как я закончил работу с запросом, я всегда делаю close() на сокете. Я также пытался использовать функцию shutdown(), но ничего не получается. помощь. Как-нибудь обойти это?
10 ответов:
Есть несколько мест, где Linux может иметь ограничения на количество файловых дескрипторов, которые вы можете открыть.
Вы можете проверить следующее:
cat /proc/sys/fs/file-maxЭто даст вам системные ограничения файловых дескрипторов.
На уровне оболочки это покажет вам ваш личный предел:
ulimit -nЭто можно изменить в файле/etc/security / limits.conf-это nofile param.
Однако, если вы закрываете свои сокеты правильно, вы не должны получать это если только вы не открываете множество симуляторных соединений. Похоже, что-то мешает вашим розеткам быть закрытыми надлежащим образом. Я бы проверил, что с ними обращаются должным образом.
У меня была похожая проблема. Быстрое решение:
ulimit -n 4096Объяснение заключается в следующем - каждое подключение к серверу представляет собой файловый дескриптор. В CentOS, Redhat и Fedora, вероятно, других, ограничение пользователя файла составляет 1024 - не знаю почему. Это можно легко увидеть, когда вы печатаете: ulimit-n
Обратите внимание, что это не имеет большого отношения к system max files (/proc/sys/fs/file-max).
В моем случае это была проблема с Redis, поэтому я сделал:
ulimit -n 4096 redis-server -c xxxxВ вашем случае вместо redis вам нужно начать сервер.
TCP имеет функцию под названием "TIME_WAIT", которая гарантирует, что соединения будут закрыты чисто. Это требует, чтобы один конец соединения оставался слушающим некоторое время после того, как сокет был закрыт.
На высокопроизводительном сервере важно, чтобы в TIME_WAIT входили клиенты, а не сервер. Клиенты могут позволить себе иметь открытый порт, в то время как занятый сервер может быстро исчерпать порты или иметь слишком много открытых FDs.
Для этого сервер никогда не должен закрывать сначала соединение - оно всегда должно ждать, пока клиент его закроет.
Это означает, что одновременно открыто максимальное количество файлов.
Решено:
В конце файла
/etc/security/limits.confнужно добавить следующие строки:* soft nofile 16384 * hard nofile 16384В текущей консоли от root (sudo не работает) сделать:
ulimit -n 16384Хотя это необязательно, если есть возможность перезапустить сервер.
В файле
/etc/nginx/nginx.confзарегистрировать новое значениеworker_connectionsравное16384разделить на значениеworker_processes.Если не сделал
ulimit -n 16384, Нужно перезагрузиться, тогда проблема отступит.PS:
Если после ремонта видно в логах
error accept() failed (24: Too many open files):В конфигурации nginx, propevia (например):
worker_processes 2; worker_rlimit_nofile 16384; events { worker_connections 8192; }
У меня тоже была эта проблема. У вас утечка дескриптора файла. Вы можете отладить это, распечатав список всех дескрипторов открытых файлов (в системах POSIX):
void showFDInfo() { s32 numHandles = getdtablesize(); for ( s32 i = 0; i < numHandles; i++ ) { s32 fd_flags = fcntl( i, F_GETFD ); if ( fd_flags == -1 ) continue; showFDInfo( i ); } } void showFDInfo( s32 fd ) { char buf[256]; s32 fd_flags = fcntl( fd, F_GETFD ); if ( fd_flags == -1 ) return; s32 fl_flags = fcntl( fd, F_GETFL ); if ( fl_flags == -1 ) return; char path[256]; sprintf( path, "/proc/self/fd/%d", fd ); memset( &buf[0], 0, 256 ); ssize_t s = readlink( path, &buf[0], 256 ); if ( s == -1 ) { cerr << " (" << path << "): " << "not available"; return; } cerr << fd << " (" << buf << "): "; if ( fd_flags & FD_CLOEXEC ) cerr << "cloexec "; // file status if ( fl_flags & O_APPEND ) cerr << "append "; if ( fl_flags & O_NONBLOCK ) cerr << "nonblock "; // acc mode if ( fl_flags & O_RDONLY ) cerr << "read-only "; if ( fl_flags & O_RDWR ) cerr << "read-write "; if ( fl_flags & O_WRONLY ) cerr << "write-only "; if ( fl_flags & O_DSYNC ) cerr << "dsync "; if ( fl_flags & O_RSYNC ) cerr << "rsync "; if ( fl_flags & O_SYNC ) cerr << "sync "; struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = 0; fl.l_start = 0; fl.l_len = 0; fcntl( fd, F_GETLK, &fl ); if ( fl.l_type != F_UNLCK ) { if ( fl.l_type == F_WRLCK ) cerr << "write-locked"; else cerr << "read-locked"; cerr << "(pid:" << fl.l_pid << ") "; } }Выбросив все открытые файлы, вы быстро выясните, где находится утечка дескриптора файла.
Если ваш сервер порождает подпроцессы. Например, если это сервер в стиле' fork', или если вы создаете другие процессы ( например, через cgi ), вы должны убедиться, что создаете свои дескрипторы файлов с помощью "cloexec" - как для реальных файлов, так и для и розетки тоже.
Без cloexec каждый раз, когда вы разветвляете или порождаете, все открытые дескрипторы файлов клонируются в дочернем процессе.
Также очень легко не закрыть сетевые сокеты - например, просто отказаться от них, когда удаленная сторона отключается. Это будет протекать ручки, как сумасшедший.
Может пройти некоторое время, прежде чем закрытый сокет действительно освободится
lsofсписок открытых файлов
cat /proc/sys/fs/file-maxчтобы увидеть, есть ли предел системы
Просто еще одна информация о CentOS. В данном случае, при использовании "systemctl" для запуска процесса. Вы должны изменить системный файл ==> /usr / lib / systemd/system / processName.обслуживание .Была такая строка в файле:
LimitNOFILE=50000И просто перезагрузите вашу систему conf:
systemctl daemon-reload
Когда ваша программа имеет больше открытых дескрипторов, чем открытые файлы ulimit (ulimit-a перечислит это), ядро откажется открывать больше файловых дескрипторов. Убедитесь, что у вас нет утечек дескрипторов файлов - например, запустив его на некоторое время, а затем остановив и посмотрев, открыты ли какие - либо дополнительные fds, когда он простаивает-и если это все еще проблема, измените nofile ulimit для вашего пользователя в /etc/security/limits.conf
У меня была та же проблема, и я не потрудился проверить возвращаемые значения вызовов close (). Когда я начал проверять возвращаемое значение, проблема таинственным образом исчезла.
Я могу только предположить, что ошибка оптимизации компилятора (gcc в моем случае) предполагает, что вызовы close() не имеют побочных эффектов и могут быть опущены, если их возвращаемые значения не используются.
Comments