返回

直面 CLOSE_WAIT 过多:你需要调整的内核参数

后端

当你发现服务器突然变得异常卡顿,执行某些操作却总是显示「Too many open files」,这时你就要注意了,你的系统可能正在饱受 CLOSE_WAIT 过多的困扰。

CLOSE_WAIT 过多意味着大量连接处于等待关闭的状态,这不仅会消耗系统资源,还会影响新连接的建立,严重时甚至可能导致系统崩溃。

问题分析

1.1 分析方法

命令行深入探查

利用命令行工具 lsof,列出所有打开的文件及其相关信息:

lsof - list open files

ulimit 一览打开文件数

通过 ulimit -a 命令,你可以查看系统对打开文件数的限制:

ulimit -a

系统会返回类似如下的信息:

open files (-n) 1024

其中,1024 表示系统允许同时打开的最大文件数。

netstat 捕捉网络状况

借助 netstat 命令,你可以捕捉网络连接的状态,重点关注 CLOSE_WAIT 连接:

netstat -an | grep CLOSE_WAIT

输出结果中,你会看到类似如下的一行:

tcp 0 0 127.0.0.1:80 127.0.0.1:56348 CLOSE_WAIT

这一行了一个处于 CLOSE_WAIT 状态的连接,其中 127.0.0.1:80 是服务器地址和端口,127.0.0.1:56348 是客户端地址和端口。

1.2 CLOSE_WAIT 过多的原因

了解了分析方法,现在我们来分析 CLOSE_WAIT 过多的原因。

程序未及时关闭文件

应用程序在使用完文件后,应该及时关闭文件,释放资源。否则,就会导致文件一直处于打开状态,累积成 CLOSE_WAIT 过多的问题。

内核参数设置不当

TCP/IP 内核参数的设置也会影响 CLOSE_WAIT 的数量。例如,如果 tcp_max_syn_backlog 设置过小,会导致 SYN_RECEIVED 状态的连接过多,从而间接导致 CLOSE_WAIT 过多。

解决思路

2.1 修改打开文件数的上限值

通过修改 ulimit 命令来提高允许同时打开的最大文件数:

ulimit -n 65535

这个命令将允许同时打开的最大文件数设置为 65535。

2.2 调整 TCP/IP 的参数

调整 TCP/IP 内核参数,以优化网络连接的处理。

tcp_tw_recycle

该参数控制是否允许重用处于 TIME_WAIT 状态的连接。将该参数设置为 1 可以提高连接的利用率,减少 CLOSE_WAIT 的数量。

tcp_tw_reuse

该参数控制是否允许重用处于 CLOSE_WAIT 状态的连接。将该参数设置为 1 可以进一步提高连接的利用率,减少 CLOSE_WAIT 的数量。

tcp_max_syn_backlog

该参数控制 SYN_RECEIVED 状态的连接队列长度。将该参数设置得更大可以减少 SYN_RECEIVED 状态的连接数量,从而间接减少 CLOSE_WAIT 的数量。

tcp_max_orphans

该参数控制孤儿连接的数量。孤儿连接是指客户端已经关闭连接,但服务器端尚未关闭连接的连接。将该参数设置得更大可以减少孤儿连接的数量,从而减少 CLOSE_WAIT 的数量。

2.3 代码层面及时主动关闭 I/O

在代码层面,应该及时主动关闭 I/O,释放资源。可以使用以下方法:

显式关闭 I/O

在使用完文件或网络连接后,显式地关闭它们。例如,在 Java 中,可以使用以下代码来关闭文件:

file.close();

在 C++ 中,可以使用以下代码来关闭网络连接:

close(sockfd);

使用自动资源管理

在 Java 中,可以使用 try-with-resources 语句来自动关闭资源。例如:

try (FileInputStream fileInputStream = new FileInputStream("file.txt")) {
    // 使用 fileInputStream
} catch (IOException e) {
    // 处理异常
}

在 C++ 中,可以使用 RAII(Resource Acquisition Is Initialization)技术来自动关闭资源。例如:

class File {
public:
    File(const std::string& filename) {
        file_ = fopen(filename.c_str(), "r");
    }

    ~File() {
        fclose(file_);
    }

private:
    FILE* file_;
};

int main() {
    {
        File file("file.txt");
        // 使用 file
    }

    return 0;
}

总结

通过调整系统参数和优化代码,可以有效减少 CLOSE_WAIT 过多的问题。这不仅可以提高系统的稳定性,还可以提高系统的性能。