套接字接受 – “打开文件太多”
我在一个学校项目上工作,我不得不编写一个multithreading服务器,现在我通过运行一些testing来比较它到Apache。 我正在使用autobench来帮助解决这个问题,但是在我运行一些testing之后,或者如果我给它一个太高的速度(大约600+)来build立连接,我会得到一个“太多打开文件”的错误。
在处理完请求之后,我总是在socket上做一个close()
。 我试图使用shutdown()
函数,但似乎没有任何帮助。 有什么办法呢?
Linux有多个地方可以限制您允许打开的文件描述符的数量。
您可以检查以下内容:
cat /proc/sys/fs/file-max
这将给你的文件描述符的系统范围的限制。
在shell级别上,这会告诉你你的个人限制:
ulimit -n
这可以在/etc/security/limits.conf中改变 – 这是nofile参数。
但是,如果你正确地closures你的套接字,除非你打开大量的同步连接,否则你不应该接收这个套接字。 这听起来像是有什么东西阻止你的sockets被适当closures。 我会validation他们正在处理正确。
我有类似的问题。 快速解决scheme是:
ulimit -n 4096
解释如下 – 每个服务器连接都是一个文件描述符。 在CentOS中,Redhat和Fedora,可能是其他的,文件用户限制是1024 – 不知道为什么。 当你input:ulimit -n时可以很容易的看到
请注意,这与系统最大文件(/ proc / sys / fs / file-max)没有多大关系。
在我的情况下,这是Redis的问题,所以我做了:
ulimit -n 4096 redis-server -c xxxx
在你的情况而不是redis,你需要启动你的服务器。
TCP有一个名为“TIME_WAIT”的function,确保连接完全closures。 它要求连接的一端在套接字closures后保持监听一段时间。
在高性能服务器中,重要的是进入TIME_WAIT的客户端,而不是服务器。 客户端可以承担打开端口,而繁忙的服务器可以快速耗尽端口或打开FD太多。
要做到这一点,服务器不应该首先closures连接 – 它应该始终等待客户端closures它。
我也有这个问题。 你有一个文件句柄泄漏。 您可以通过打印出所有打开文件句柄(在POSIX系统上)的列表来进行debugging:
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 << ") "; } }
通过倾销所有打开的文件,您将快速找出您的文件处理泄漏的位置。
如果你的服务器产生subprocess。 例如,如果这是一个“fork”风格的服务器,或者你正在产生其他进程(例如通过cgi),你必须确保使用“cloexec”创build文件句柄 – 无论是真实文件还是套接字。
如果没有cloexec,每次fork或产卵时,所有打开的文件句柄都被克隆到subprocess中。
closuresnetworking套接字也很容易,比如在远程方断开连接时丢弃它们。 这会像疯了似的泄漏处理。
使用lsof -u `whoami` | wc -l
lsof -u `whoami` | wc -l
find用户有多less个打开的文件
在封闭的套接字真正被释放之前,可能需要一些时间
lsof
列出打开的文件
cat /proc/sys/fs/file-max
来查看是否有系统限制
这意味着同时打开文件的最大数量。
解决了:
在文件/etc/security/limits.conf
的结尾处,您需要添加以下行:
* soft nofile 16384 * hard nofile 16384
在当前控制台从根(sudo不起作用)来做:
ulimit -n 16384
尽pipe这是可选的,但如果可以重新启动服务器。
在/etc/nginx/nginx.conf
文件中注册新的值worker_connections
等于16384
除以值worker_processes
。
如果没有做了ulimit -n 16384
,需要重启,那么问题就会消失。
PS:
如果在日志中可见修复后error accept() failed (24: Too many open files)
:
在nginxconfiguration中,propevia(例如):
worker_processes 2; worker_rlimit_nofile 16384; events { worker_connections 8192; }
当你的程序有更多的开放描述符比打开的文件ulimit(ulimit -a会列出这个),内核将拒绝打开更多的文件描述符。 确保没有任何文件描述符泄漏 – 例如,运行一段时间,然后停止并查看是否有任何额外的fds在闲置时仍然打开 – 如果仍存在问题,请更改您的nofile ulimit用户在/etc/security/limits.conf中
我有同样的问题,我不打扰检查close()调用的返回值。 当我开始检查返回值时,这个问题神秘地消失了。
我只能假设编译器的优化故障(在我的情况下是gcc),假设close()调用没有副作用,如果不使用它们的返回值,可以省略。
只是关于CentOS的另一个信息。 在这种情况下,使用“systemctl”启动进程。 您必须修改系统文件==> /usr/lib/systemd/system/processName.service。在文件中添加以下行:
LimitNOFILE=50000
只需重新加载你的系统conf:
systemctl daemon-reload