在处理请求后,我总是对套接字执行
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,而是需要启动你的服务器。
lsof -u `whoami` | wc -l
命令可以查找用户打开了多少个文件。TCP有一个名为“TIME_WAIT”的特性,确保连接被干净地关闭。它要求连接的一端在套接字关闭后要继续保持监听一段时间。
在高性能服务器中,重要的是客户端进入TIME_WAIT状态,而不是服务器。客户端可以承受有一个端口处于打开状态,而繁忙的服务器可能会迅速耗尽端口或打开过多的FD。
为了实现这一点,服务器不应该首先关闭连接,而应始终等待客户端关闭它。
这意味着同时打开的文件数量上限。
解决方案:
在文件/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 配置中,找到适当位置进行设置(例如):
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 << ") ";
}
}
在 MacOS 上,显示限制:
launchctl limit maxfiles
结果如下:maxfiles 256 1000
如果数字(软限制和硬限制)太低,您需要进行上调:
sudo launchctl limit maxfiles 65536 200000
已关闭的套接字需要一些时间才能真正释放。
使用 lsof
列出打开的文件。
使用 cat /proc/sys/fs/file-max
查看系统限制是否存在。
为了以后参考,我遇到了类似的问题;我创建了太多的文件和套接字(在Unix操作系统上,所有东西都是FD),导致创建了太多的文件描述符(FDs)。我的解决方案是使用setrlimit()
在运行时增加FDs。
首先,我使用以下代码获取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;
}
gettrlimit()
和setrlimit()
的更多信息。关于CentOS的另一条信息。 在这种情况下,当使用“systemctl”启动进程时, 你需要修改系统文件 ==> /usr/lib/systemd/system/processName.service 文件中应该有以下行:
LimitNOFILE=50000
只需重新加载您的系统配置:
systemctl daemon-reload