当前位置:  开发笔记 > 后端 > 正文

套接字接受 - "打开文件过多"

如何解决《套接字接受-"打开文件过多"》经验,为你挑选了6个好方法。

我正在开展一个学校项目,我必须编写一个多线程服务器,现在我通过对它运行一些测试来将它与apache进行比较.我正在使用autobench来帮助解决这个问题,但是在我运行一些测试之后,或者如果我给它提供太高的速率(大约600+)来建立连接,我会收到"太多打开文件"的错误.

完成处理请求后,我总是close()在套接字上做一个.我也试过使用这个shutdown()功能,但似乎没有任何帮助.有什么方法吗?



1> Reed Copsey..:

有许多地方Linux可以限制您允许打开的文件描述符的数量.

您可以查看以下内容:

cat /proc/sys/fs/file-max

这将为您提供系统范围的文件描述符限制.

在shell级别,这将告诉您个人限制:

ulimit -n

这可以在/etc/security/limits.conf中更改 - 它是nofile参数.

但是,如果你正确关闭套接字,除非你打开很多同时连接,否则你不应该接收它.听起来有些东西阻止你的插座被正确关闭.我会验证他们是否得到妥善处理.



2> Nick..:

我有类似的问题.快速解决方案是:

ulimit -n 4096

解释如下 - 每个服务器连接是一个文件描述符.在CentOS,Redhat和Fedora,可能是其他人,文件用户限制是1024 - 不知道为什么.键入时可以很容易地看到:ulimit -n

请注意,这与系统最大文件(/ proc/sys/fs/file-max)没有多大关系.

在我的情况下,这是Redis的问题,所以我做了:

ulimit -n 4096
redis-server -c xxxx

在您的情况下,而不是redis,您需要启动您的服务器.


内存泄漏的答案是......购买更多内存?没有修复文件泄漏.
好像你不明白这个问题(或者你把评论置于错误的答案之下?.它与文件描述符限制有关,与内存或内存泄漏无关.
@RafaelBaptista在某些情况下,例如高性能聊天服务器,实际上需要大量并发连接。这不必与泄漏FD有关。

3> Ed4..:

TCP具有一个名为"TIME_WAIT"的功能,可确保连接干净地关闭.它需要连接的一端在套接字关闭后保持监听一段时间.

在高性能服务器中,重要的是它是进入TIME_WAIT的客户端,而不是服务器.客户端可以负责打开端口,而繁忙的服务器可以快速耗尽端口或拥有太多开放的FD.

要实现这一点,服务器不应该首先关闭连接 - 它应该总是等待客户端关闭它.


否.TCP TIME_WAIT将在操作系统级别保持套接字打开,并最终导致服务器拒绝传入连接.当您关闭文件句柄时,它会关闭.http://stackoverflow.com/questions/1803566/what-is-the-cost-of-many-time-wait-on-the-server-side

4> Edson Medina..:

使用lsof -u `whoami` | wc -l查找用户有多少打开的文件有


这如何解决问题?

5> shilovk..:

这意味着同时打开文件的最大数量.

解决了:

在文件的末尾,/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;
}



6> Rafael Bapti..:

我也有这个问题.你有一个文件句柄泄漏.您可以通过打印出所有打开文件句柄的列表(在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,每次fork或spawn时,都会在子进程中克隆所有打开的文件句柄.

关闭网络套接字也很容易 - 例如,当远程方断开连接时放弃它们.这会像疯了一样泄漏手柄.

推荐阅读
周扒pi
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有