套接字接受-“打开的文件太多”


72

我正在一个学校项目中工作,我必须编写一个多线程服务器,现在我通过对它进行一些测试来将它与apache进行比较。我正在使用Autobench来解决此问题,但是在运行了几次测试之后,或者如果我给它很高的速率(大约600+)以建立连接,我会收到“打开的文件太多”的错误消息。

处理close()完请求后,我总是在套接字上做一个。我也尝试过使用该shutdown()函数,但似乎无济于事。可以解决吗?

Answers:


72

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

您可以检查以下内容:

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

在外壳程序级别,这将告诉您您的个人限制:

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

但是,如果您正确地关闭了套接字,那么除非您打开大量同时连接,否则不应收到此消息。听起来好像有些东西在阻止您的插座正确关闭。我会验证它们是否已正确处理。


用户名hard nofile 20000
linjunhalida 2011年

36

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

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

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

就我而言,Redis存在问题,所以我这样做了:

在这种情况下,您需要启动服务器而不是Redis。


6
内存泄漏的答案是……购买更多的内存?无法修复文件泄漏。
拉斐尔·巴普蒂斯塔

5
似乎您不理解问题(或您将注释放在错误的答案下?。这与文件描述符限制有关,与内存或内存泄漏无关。)
Nick

1
文件限制为1024,因为否则会遇到的根本问题select()
蓬松的

2
@RafaelBaptista在某些情况下,例如高性能聊天服务器,实际上需要大量并发连接。这不必与泄漏FD有关。
Antwan van Houdt

@RafaelBaptista:如果您的服务器可以处理512个以上的并行连接,则需要更多打开文件。现代服务器可以处理数百万个并行连接,因此将其限制为低至1024确实没有任何意义。临时用户的默认限制可能是可以的,但处理并行客户端连接的服务器软件则不能。
Mikko Rantalainen

17

TCP具有称为“ TIME_WAIT”的功能,可确保干净地关闭连接。关闭插槽后,它需要连接的一端保持侦听一段时间。

在高性能服务器中,重要的是进入TIME_WAIT的是客户端,而不是服务器。客户端可以负担得起开放端口的费用,而繁忙的服务器可能会迅速用尽端口或开放的FD过多。

为此,服务器永远不要先关闭连接-它应始终等待客户端关闭连接。


2
否。TCPTIME_WAIT将使套接字在操作系统级别保持打开状态,并最终导致服务器拒绝传入的连接。当关闭文件句柄时,其关闭。stackoverflow.com/questions/1803566/…–
拉斐尔·巴普蒂斯塔

的确,文件句柄立即关闭,我弄错了。但是我的主要观点仍然是,因为即使释放了FD,TCP端口仍在TIME_WAIT期间分配,并且繁忙的服务器可能会耗尽TCP端口,或者花费过多的内核内存来跟踪它们。
Ed4 2015年


10

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

解决了:

在文件末尾,/etc/security/limits.conf您需要添加以下行:

在当前控制台中从根目录(sudo不起作用)执行以下操作:

尽管这是可选的,但可以重新启动服务器。

/etc/nginx/nginx.conf文件中注册worker_connections等于值的新16384worker_processes

如果没有执行此操作ulimit -n 16384,则需要重新启动,然后问题将消失。

PS:

如果修复后在日志中可见error accept() failed (24: Too many open files)

在nginx配置中,propevia(例如):


6

我也有这个问题。您有文件句柄泄漏。您可以通过打印出所有打开的文件句柄的列表(在POSIX系统上)来进行调试:

通过转储所有打开的文件,您将快速找出文件句柄泄漏的位置。

如果服务器产生子进程。例如,如果这是一个“ fork”风格的服务器,或者您正在生成其他进程(例如,通过cgi),则必须确保使用“ cloexec”创建文件句柄-既用于真实文件,也用于套接字。

如果没有cloexec,则每次您分叉或生成时,所有打开的文件句柄都会在子进程中克隆。

无法关闭网络插座也很容易-例如,当远程方断开连接时,仅将其丢弃。这会像疯了一样泄漏手柄。


4

可能需要一段时间才能真正释放封闭的插槽

lsof 列出打开的文件

cat /proc/sys/fs/file-max 看看是否有系统限制


2

只是有关CentOS的其他信息。在这种情况下,使用“ systemctl”启动过程。您必须修改系统文件==> /usr/lib/systemd/system/processName.service。在文件中的这一行:

只需重新加载系统conf即可:


1

当您的程序具有比打开文件ulimit更大的打开描述符(ulimit -a将列出此文件)时,内核将拒绝打开更多文件描述符。确保您没有任何文件描述符泄漏-例如,运行一会儿,然后停止并查看空闲状态下是否还有其他fds处于打开状态-如果仍然存在问题,请更改nofile ulimit /etc/security/limits.conf中的用户


1

我遇到了同样的问题,我没有费心检查close()调用的返回值。当我开始检查返回值时,问题神秘地消失了。

我只能假设编译器有一个优化故障(在我的情况下为gcc),假设close()调用没有副作用,如果不使用返回值,则可以忽略。


3
对不起,这根本没有道理。如果代码中的非常微小的更改使错误“消失了”,则您的代码中很可能存在一个严重的错误,该错误被隐藏了。使用valgrind或其他此类工具进行跟踪。优化close调用的编译器将是灾难性的。

我同意。但是,从任何系统调用中检查返回值都很重要,因为您可能会遇到EGAIN很多情况,如果您忽略这种情况,那么所有赌注都将失效。
Mikko Rantalainen

0

在MacOS上,显示限制:

结果如下: maxfiles 256 1000

如果数字(软限制和硬限制)太低,则必须设置上限:


0

为了将来参考,我遇到了类似的问题。我通过创建太多文件和套接字来创建太多文件描述符(FD)(在Unix OS上,所有内容都是FD)。我的解决方案是在运行时使用来增加FD setrlimit()

首先,我获得了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的来源。

您也可以找到更多的信息gettrlimit(),并setrlimit() 在这里这里


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;

有效的解决方案是:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.