You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何带负载均衡的WebSocket在高流量下仍随机断开连接?

高并发WebSocket连接下的性能优化方案

问题背景

基于Node.js + Socket.IO搭建的WebSocket服务器,低负载时运行正常,但当并发客户端数量突破10000+时,出现随机断连、消息延迟、服务器崩溃等问题,使用NGINX作为反向代理。

现有配置

NGINX配置

server {
    listen 80;
    server_name mydomain.com;

    location /socket.io/ {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
}

Node.js Socket.IO服务器代码

const io = require("socket.io")(3000, {
    cors: {
        origin: "*",
    },
});

io.on("connection", (socket) => {
    console.log(`User connected: ${socket.id}`);

    socket.on("message", (data) => {
        console.log(`Received: ${data}`);
        socket.emit("response", "Message received!");
    });

    socket.on("disconnect", () => {
        console.log(`User disconnected: ${socket.id}`);
    });
});

出现的问题

  • 客户端随机断开连接(高负载时尤为明显)
  • 部分消息丢失(违背WebSocket可靠性预期)
  • 数千连接时CPU使用率飙升至100%
  • NGINX日志显示"Connection reset by peer"错误

已尝试的优化

  • 增大WebSocket ping间隔:略有改善,但断连仍存在
  • 优化NGINX WebSocket配置:无明显效果
  • 使用Redis Socket.IO适配器扩容:有一定帮助,但随机断连未解决
  • 增加Node.js进程内存:无法避免高负载CPU占用
  • 尝试WebSocket服务器集群:客户端重连仍超时

针对性优化方案

1. 调整NGINX核心参数,解决连接限制与超时

默认NGINX的worker进程数、连接数上限不足以支撑10000+并发,补充以下配置:

# 全局配置段
worker_processes auto;
worker_connections 10240;
multi_accept on;

# HTTP配置段
http {
    keepalive_timeout 65;
    keepalive_requests 10000;

    # WebSocket专属超时与缓冲配置
    proxy_connect_timeout 7d;
    proxy_send_timeout 7d;
    proxy_read_timeout 7d;
    proxy_buffer_size 64k;
    proxy_buffers 4 64k;
    proxy_busy_buffers_size 128k;

    # 负载均衡节点(配合Node.js集群)
    upstream socket_nodes {
        least_conn; # 按最少连接数分配请求
        server localhost:3001;
        server localhost:3002;
        server localhost:3003;
        server localhost:3004;
        # 按服务器CPU核数添加对应端口
    }

    server {
        listen 80;
        server_name mydomain.com;

        location /socket.io/ {
            proxy_pass http://socket_nodes;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            # 传递真实客户端IP
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

worker_connections设为10240确保单worker能处理足够连接,proxy_read_timeout设为7d避免NGINX主动断开长连接,缓冲参数减少IO阻塞。

2. Node.js Socket.IO优化,降低CPU占用与断连

关闭高频日志输出

当前代码中每个连接、消息都打印日志,10000+并发时日志IO会占用大量CPU,注释或移除冗余日志:

io.on("connection", (socket) => {
    // console.log(`User connected: ${socket.id}`);

    socket.on("message", (data) => {
        // console.log(`Received: ${data}`);
        socket.emit("response", "Message received!");
    });

    socket.on("disconnect", () => {
        // console.log(`User disconnected: ${socket.id}`);
    });
});

调整心跳与传输参数

默认心跳间隔过于频繁,强制使用WebSocket传输避免轮询开销:

const io = require("socket.io")(3000 + cluster.worker.id, {
    cors: {
        origin: "*",
    },
    pingInterval: 30000, // 30秒发一次ping
    pingTimeout: 60000,   // 60秒没收到pong再断开
    transports: ["websocket"], // 禁用HTTP轮询
});

启用Node.js集群模式,利用多核CPU

单Node.js进程只能占用单核,用cluster模块启动多进程绑定不同端口:

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
const { createServer } = require('http');
const { Server } = require('socket.io');

if (cluster.isPrimary) {
    console.log(`Primary ${process.pid} is running`);
    // 启动与CPU核数一致的工作进程
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
    // 自动重启崩溃的进程
    cluster.on('exit', (worker) => {
        console.log(`worker ${worker.process.pid} died, restarting...`);
        cluster.fork();
    });
} else {
    const httpServer = createServer();
    const io = new Server(httpServer, {
        cors: { origin: "*" },
        pingInterval: 30000,
        pingTimeout: 60000,
        transports: ["websocket"]
    });

    io.on("connection", (socket) => {
        socket.on("message", (data) => {
            socket.emit("response", "Message received!");
        });
    });

    // 每个工作进程绑定不同端口
    httpServer.listen(3000 + cluster.worker.id);
    console.log(`Worker ${process.pid} started on port ${3000 + cluster.worker.id}`);
}

3. 系统级优化,调整文件描述符限制

Linux默认文件描述符上限为1024,无法支撑10000+连接,需调高限制:

  1. 临时生效(当前会话):
ulimit -n 65535
  1. 永久生效:
    编辑/etc/security/limits.conf:
* soft nofile 65535
* hard nofile 65535
root soft nofile 65535
root hard nofile 65535

编辑/etc/sysctl.conf:

fs.file-max = 65535
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

执行sysctl -p使配置生效。

4. 消息可靠性优化

启用Socket.IO的确认机制,确保消息送达:

// 客户端发送消息时等待服务器确认
socket.emit("message", data, (ack) => {
    console.log(ack); // 收到服务器返回的确认信息
});

// 服务器端处理消息并返回确认
socket.on("message", (data, callback) => {
    callback("Message received successfully");
    socket.emit("response", "Message received!");
});

内容的提问来源于stack exchange,提问作者Milan Gohel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:32:14