TIME_WAIT 过多的原因以及解决方案

#nodejs

目录

1. TIME_WAIT 过多的原因

1.1. 短连接过多

// 不良示例:频繁创建短连接
const http = require('http');

setInterval(() => {
    http.get('http://example.com', (res) => {
        // 处理完立即关闭
        res.on('end', () => {
            // 连接关闭,进入 TIME_WAIT
        });
    });
}, 100);

1.2. 客户端主动关闭连接

// 不良示例:客户端频繁主动关闭连接
const net = require('net');
const client = new net.Socket();

client.connect(3000, '127.0.0.1', () => {
    client.end(); // 客户端主动关闭,将产生 TIME_WAIT
});

1.3. 高并发下的连接复用不足

2. 解决方案

2.1. 启用 TCP keepalive 保持长连接

// 服务端启用 keepalive
const server = net.createServer((socket) => {
    socket.setKeepAlive(true, 60000); // 60秒
});

// 或在 HTTP 服务中
const server = http.createServer((req, res) => {
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('Keep-Alive', 'timeout=5'); // 5秒超时
});

2.2. 使用==连接池==

// 使用连接池示例
const generic_pool = require('generic-pool');

const factory = {
    create: async () => {
        const client = new net.Socket();
        await new Promise((resolve) => {
            client.connect(3000, '127.0.0.1', resolve);
        });
        return client;
    },
    destroy: (client) => {
        return new Promise((resolve) => {
            client.end();
            client.on('close', resolve);
        });
    }
};

const pool = generic_pool.createPool(factory, {
    max: 10, // 最大连接数
    min: 2   // 最小连接数
});

2.3. 系统层面优化

# 修改 TIME_WAIT 超时时间
sysctl -w net.ipv4.tcp_fin_timeout=30

# 允许 TIME_WAIT 状态的 socket 重用
sysctl -w net.ipv4.tcp_tw_reuse=1

# 快速回收 TIME_WAIT 连接
sysctl -w net.ipv4.tcp_tw_recycle=1  # 注意:在 Linux 4.12+ 已被移除

2.4. 负载均衡 → 使用 Node.js cluster 模块做负载均衡

// 使用 Node.js cluster 模块做负载均衡
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // 启动多个工作进程
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
} else {
    // 工作进程创建服务器
    http.createServer((req, res) => {
        res.writeHead(200);
        res.end('hello world\n');
    }).listen(8000);
}

3. 最佳实践建议

3.1. 服务端设计

  • 尽量使用==长连接==
  • 实现连接池机制
  • 合理配置 keepalive 参数

3.2. 客户端设计

  • 使用连接池
  • 避免频繁创建短连接
  • 适当使用长连接

3.3. 系统配置

  • 适当调整系统参数
  • 配置负载均衡
  • 监控 TIME_WAIT 状态

3.4. 架构优化

  • 使用反向代理
  • 实现服务端负载均衡
  • 合理设置超时时间