我正在开展一个学校项目,我必须编写一个多线程服务器,现在我通过对它运行一些测试来将它与apache进行比较。我正在使用autobench来帮助解决这个问题,但是在我运行一些测试之后,或者如果我给它提供太高的速率(大约600+)来建立连接,我会收到“太多打开文件”的错误。
完成处理请求后,我总是在套接字上执行close()
。我也尝试过使用shutdown()
函数,但似乎没有任何帮助。有什么方法吗?
答案 0 :(得分:52)
Linux可以对允许打开的文件描述符数量进行限制。
您可以查看以下内容:
cat /proc/sys/fs/file-max
这将为您提供系统范围的文件描述符限制。
在shell级别,这将告诉您个人限制:
ulimit -n
这可以在/etc/security/limits.conf中更改 - 这是nofile参数。
但是,如果你正确地关闭了套接字,除非你打开很多类似的连接,否则你不应该接收它。听起来有些东西阻止你的插座被正确关闭。我会验证它们是否正确处理。
答案 1 :(得分:24)
我有类似的问题。 快速解决方案是:
ulimit -n 4096
解释如下 - 每个服务器连接都是文件描述符。在CentOS,Redhat和Fedora,可能是其他人,文件用户限制是1024 - 不知道为什么。键入时可以很容易地看到: ulimit -n
请注意,这与系统最大文件(/ proc / sys / fs / file-max)没有多大关系。
在我的情况下,这是Redis的问题,所以我做了:
ulimit -n 4096
redis-server -c xxxx
在你的情况下,而不是redis,你需要启动你的服务器。
答案 2 :(得分:14)
TCP具有一个名为“TIME_WAIT”的功能,可确保连接干净地关闭。它需要连接的一端在套接字关闭后保持监听一段时间。
在高性能服务器中,重要的是进入TIME_WAIT的客户端而不是服务器。客户端可以负责打开端口,而繁忙的服务器可以快速耗尽端口或拥有太多开放的FD。
要实现这一点,服务器不应该首先关闭连接 - 它应该总是等待客户端关闭它。
答案 3 :(得分:9)
使用lsof -u `whoami` | wc -l
查找用户拥有的打开文件数
答案 4 :(得分:7)
这意味着同时打开文件的最大数量。
<强>解决:强>
在文件/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;
}
答案 5 :(得分:6)
我也有这个问题。你有一个文件句柄泄漏。您可以通过打印出所有打开文件句柄的列表(在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或者生成时,都会在子进程中克隆所有打开的文件句柄。
关闭网络套接字也很容易 - 例如当远程方断开连接时放弃它们。这会像疯了一样泄漏手柄。
答案 6 :(得分:4)
在关闭的套接字真正释放之前可能需要一些时间
lsof
列出打开的文件
cat /proc/sys/fs/file-max
查看是否存在系统限制
答案 7 :(得分:2)
关于CentOS的另一个信息。 在这种情况下,当使用&#34; systemctl&#34;启动过程。 你必须修改系统文件==&gt; /usr/lib/systemd/system/processName.service 。在文件中有这一行:
Timeline.prototype.onTaskDoubleClick
只需重新加载系统内容:
LimitNOFILE=50000
答案 8 :(得分:1)
当你的程序有比打开文件更多的开放描述符ulimit(ulimit -a会列出这个)时,内核将拒绝再打开任何文件描述符。确保没有任何文件描述符泄漏 - 例如,运行它一段时间,然后停止并查看是否有任何额外的fds在空闲时仍然打开 - 如果它仍然是一个问题,请更改你的nofile ulimit用户在/etc/security/limits.conf
答案 9 :(得分:1)
我遇到了同样的问题,我没有费心去检查close()调用的返回值。当我开始检查返回值时,问题神秘地消失了。
我只能假设编译器的优化故障(在我的情况下为gcc),假设close()调用没有副作用,并且如果不使用它们的返回值则可以省略。
答案 10 :(得分:0)
在MacOS上,显示限制:
launchctl limit maxfiles
结果类似:maxfiles 256 1000
如果数字(软限制和硬限制)太低,则必须设置上限:
sudo launchctl limit maxfiles 65536 200000
答案 11 :(得分:0)
为了将来参考,我遇到了类似的问题。我通过创建太多的文件和套接字创建了太多的文件描述符(FD)(在Unix OS上,所有内容都是FD)。我的解决方案是在运行时使用setrlimit()
增加FD。
首先,我获得了FD限制,并带有以下代码:
// This goes somewhere in your code
struct rlimit rlim;
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
std::cout << "Soft limit: " << rlim.rlim_cur << std::endl;
std::cout << "Hard limit: " << rlim.rlim_max << std::endl;
} else {
std::cout << "Unable to get file descriptor limits" << std::endl;
}
运行getrlimit()
后,我可以确认在我的系统上,软限制为256个FD,硬限制为无限FD(这取决于您的发行版和规格)。由于我在文件和套接字之间创建了300多个FD,因此我的代码崩溃了。
就我而言,我无法减少FD的数量,因此我决定使用以下代码来提高FD软限制:
// This goes somewhere in your code
struct rlimit rlim;
rlim.rlim_cur = NEW_SOFT_LIMIT;
rlim.rlim_max = NEW_HARD_LIMIT;
if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
std::cout << "Unable to set file descriptor limits" << std::endl;
}
请注意,您还可以获取正在使用的FD的数量以及这些FD的来源with this code。
答案 12 :(得分:0)
vSphere上的Ubuntu 18的类似问题。 原因-配置文件nginx.conf包含过多的日志文件和套接字。套接字在Linux中被视为文件。 当nginx -s重新加载或sudo服务nginx启动/重新启动时,error.log中出现“打开文件过多”错误。
NGINX工作进程由NGINX用户启动。 Nginx用户的Ulimit(软和硬)为65536。 ulimit和设置limits.conf无效。
nginx.conf中的rlimit设置也无济于事: worker_rlimit_nofile 65536;
有效的解决方案是:
$ mkdir -p /etc/systemd/system/nginx.service.d
$ nano /etc/systemd/system/nginx.service.d/nginx.conf
[Service]
LimitNOFILE=30000
$ systemctl daemon-reload
$ systemctl restart nginx.service