Socket accept - " слишком много открытых файлов"



Я работаю над школьным проектом, где мне пришлось написать многопоточный сервер, и теперь я сравниваю его с apache, проводя некоторые тесты против него. Я использую autobench, чтобы помочь с этим, но после того, как я выполняю несколько тестов, или если я даю ему слишком высокую скорость (около 600+), Чтобы сделать соединения, я получаю ошибку "слишком много открытых файлов".



После того, как я закончил работу с запросом, я всегда делаю close() на сокете. Я также пытался использовать функцию shutdown(), но ничего не получается. помощь. Как-нибудь обойти это?

630   10  

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.

Для этого сервер никогда не должен закрывать сначала соединение - оно всегда должно ждать, пока клиент его закроет.

Используйте lsof -u `whoami` | wc -l, чтобы узнать, сколько открытых файлов у пользователя

Это означает, что одновременно открыто максимальное количество файлов.

Решено:

В конце файла /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

    Ничего не найдено.