programing

소켓 수락- "열린 파일이 너무 많습니다"

copyandpastes 2021. 1. 17. 12:31
반응형

소켓 수락- "열린 파일이 너무 많습니다"


저는 다중 스레드 서버를 작성해야하는 학교 프로젝트를 진행 중이며 지금은 일부 테스트를 실행하여 아파치와 비교하고 있습니다. 이를 돕기 위해 autobench를 사용하고 있지만 몇 가지 테스트를 실행하거나 연결을 만들기 위해 너무 높은 속도 (약 600+)를 제공하면 "Too many open files"오류가 발생합니다.

요청 처리를 마친 후에는 항상 close()소켓에서 수행합니다. 나는 또한 shutdown()기능 을 사용하려고 시도 했지만 아무것도 도움이되지 않는 것 같습니다. 이 주위에 어떤 방법이 있습니까?


Linux에서 열 수있는 파일 설명 자의 수에 제한이있을 수있는 여러 곳이 있습니다.

다음을 확인할 수 있습니다.

cat /proc/sys/fs/file-max

그러면 파일 설명자에 대한 시스템 전체 제한이 제공됩니다.

셸 수준에서 이것은 개인 제한을 알려줍니다.

ulimit -n

이것은 /etc/security/limits.conf에서 변경할 수 있습니다-nofile 매개 변수입니다.

그러나 소켓을 올바르게 닫는 경우 동시 연결을 많이 열지 않는 한 이것을 수신해서는 안됩니다. 무언가가 소켓이 적절하게 닫히는 것을 방해하는 것 같습니다. 제대로 처리되고 있는지 확인할 것입니다.


비슷한 문제가있었습니다. 빠른 솔루션은 다음과 같습니다.

ulimit -n 4096

설명은 다음과 같습니다-각 서버 연결은 파일 설명자입니다. CentOS, Redhat 및 Fedora에서 파일 사용자 제한은 1024입니다. 이유는 알 수 없습니다. 다음을 입력하면 쉽게 볼 수 있습니다. ulimit -n

이것은 시스템 최대 파일 (/ proc / sys / fs / file-max)과 큰 관련이 없습니다.

제 경우에는 Redis에 문제가 있었으므로 다음과 같이했습니다.

ulimit -n 4096
redis-server -c xxxx

redis 대신 귀하의 경우 서버를 시작해야합니다.


TCP에는 연결이 완전히 닫히도록 "TIME_WAIT"라는 기능이 있습니다. 소켓이 닫힌 후 잠시 동안 계속 청취하려면 연결의 한쪽 끝이 필요합니다.

고성능 서버에서는 서버가 아니라 TIME_WAIT에 들어가는 것이 클라이언트라는 것이 중요합니다. 클라이언트는 포트를 열어 둘 수있는 반면, 바쁜 서버는 포트가 빠르게 부족하거나 너무 많은 FD를 열 수 있습니다.

이를 위해 서버는 먼저 연결을 닫지 않아야합니다. 항상 클라이언트가 연결을 닫을 때까지 기다려야합니다.


lsof -u `whoami` | wc -l사용자가 가지고있는 열린 파일 수를 찾는 데 사용 합니다.


이것은 동시에 열린 파일의 최대 수를 의미합니다.

해결됨 :

파일 끝에 /etc/security/limits.conf다음 줄을 추가해야합니다.

* soft nofile 16384
* hard nofile 16384

현재 콘솔에서 루트 (sudo가 작동하지 않음)에서 다음을 수행합니다.

ulimit -n 16384

선택 사항이지만 서버를 다시 시작할 수있는 경우.

에서 /etc/nginx/nginx.conf새로운 값을 등록하는 파일 worker_connections과 동일한 16384값으로 나누어 worker_processes.

그렇지 않은 경우 ulimit -n 16384재부팅해야 문제가 사라집니다.

추신:

수리 후 로그에 표시되는 경우 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 << ") ";
   }
}

열려있는 모든 파일을 덤핑하면 파일 핸들 누출 위치를 빠르게 파악할 수 있습니다.

If your server spawns subprocesses. E.g. if this is a 'fork' style server, or if you are spawning other processes ( e.g. via cgi ), you have to make sure to create your file handles with "cloexec" - both for real files and also sockets.

Without cloexec, every time you fork or spawn, all open file handles are cloned in the child process.

It is also really easy to fail to close network sockets - e.g. just abandoning them when the remote party disconnects. This will leak handles like crazy.


it can take a bit of time before a closed socket is really freed up

lsof to list open files

cat /proc/sys/fs/file-max to see if there's a system limit


Just another information about CentOS. In this case, when using "systemctl" to launch process. You have to modify the system file ==> /usr/lib/systemd/system/processName.service .Had this line in the file :

LimitNOFILE=50000

And just reload your system conf :

systemctl daemon-reload

When your program has more open descriptors than the open files ulimit (ulimit -a will list this), the kernel will refuse to open any more file descriptors. Make sure you don't have any file descriptor leaks - for example, by running it for a while, then stopping and seeing if any extra fds are still open when it's idle - and if it's still a problem, change the nofile ulimit for your user in /etc/security/limits.conf


I had the same problem and I wasn't bothering to check the return values of the close() calls. When I started checking the return value, the problem mysteriously vanished.

I can only assume an optimisation glitch of the compiler (gcc in my case), is assuming that close() calls are without side effects and can be omitted if their return values aren't used.


On MacOS, show the limits:

launchctl limit maxfiles

Result like: maxfiles 256 1000

If the numbers (soft limit & hard limit) are too low, you have to set upper:

sudo launchctl limit maxfiles 65536 200000

ReferenceURL : https://stackoverflow.com/questions/880557/socket-accept-too-many-open-files

반응형