我正在开展一个学校项目,我必须编写一个多线程服务器,现在我通过对它运行一些测试来将它与apache进行比较.我正在使用autobench来帮助解决这个问题,但是在我运行一些测试之后,或者如果我给它提供太高的速率(大约600+)来建立连接,我会收到"太多打开文件"的错误.
完成处理请求后,我总是close()
在套接字上做一个.我也试过使用这个shutdown()
功能,但似乎没有任何帮助.有什么方法吗?
有许多地方Linux可以限制您允许打开的文件描述符的数量.
您可以查看以下内容:
cat /proc/sys/fs/file-max
这将为您提供系统范围的文件描述符限制.
在shell级别,这将告诉您个人限制:
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
在当前的控制台从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,每次fork或spawn时,都会在子进程中克隆所有打开的文件句柄.
关闭网络套接字也很容易 - 例如,当远程方断开连接时放弃它们.这会像疯了一样泄漏手柄.