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

如何在PM2 Cluster模式下使用Socket.IO?求兼容示例代码

解决Socket.io与PM2集群模式兼容的问题

我之前也踩过这个坑!PM2集群模式下每个Worker都是独立的Node进程,内存完全隔离,而Socket.io默认的内存适配器没法跨进程共享连接状态——当客户端请求打到不同Worker时,Socket.io根本识别不了已有的连接,自然就会出现你遇到的NaN这类异常响应。

要解决这个问题,核心是用共享存储适配器让所有Worker同步Socket.io的状态,最常用的就是Redis适配器。下面给你一套完整的可运行示例:


第一步:安装依赖

先把需要的包装全:

npm install socket.io @socket.io/redis-adapter redis pm2 express

注:如果你的Socket.io是v3及以下版本,用socket.io-redis替代@socket.io/redis-adapter即可。

第二步:编写服务器代码(server.js)

这里用Express+Socket.io,配置Redis适配器实现跨进程状态共享:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const { createAdapter } = require('@socket.io/redis-adapter');
const { createClient } = require('redis');

const app = express();
const server = http.createServer(app);

// 初始化Redis客户端(主从客户端,适配Socket.io的适配器要求)
const pubClient = createClient({ url: 'redis://localhost:6379' });
const subClient = pubClient.duplicate();

// 连接Redis
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  // 创建Socket.io实例并绑定Redis适配器
  const io = new Server(server, {
    cors: {
      origin: "*", // 测试环境放开,生产环境要指定具体域名
      methods: ["GET", "POST"]
    }
  });
  io.adapter(createAdapter(pubClient, subClient));

  // 监听Socket连接
  io.on('connection', (socket) => {
    console.log(`Client connected: ${socket.id} (Worker: ${process.pid})`);

    // 示例:处理客户端请求并返回数据
    socket.on('get-data', (callback) => {
      // 这里可以替换成你的业务逻辑
      const responseData = { value: Math.floor(Math.random() * 100) };
      callback(responseData); // 确保用回调返回,Artillery能正确捕获响应
    });

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

  // 启动HTTP服务器
  const PORT = process.env.PORT || 3000;
  server.listen(PORT, () => {
    console.log(`Worker ${process.pid} listening on port ${PORT}`);
  });
}).catch(err => {
  console.error('Redis connection failed:', err);
  process.exit(1);
});

第三步:配置PM2集群模式(ecosystem.config.js)

创建PM2的配置文件,指定集群模式和实例数:

module.exports = {
  apps: [
    {
      name: 'socket-io-cluster',
      script: './server.js',
      instances: 'max', // 自动启动与CPU核心数一致的Worker
      exec_mode: 'cluster', // 启用集群模式
      env: {
        NODE_ENV: 'development',
        PORT: 3000
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 3000
      }
    }
  ]
};

第四步:编写Artillery测试配置(artillery.yml)

确保测试脚本正确调用Socket.io的事件:

config:
  target: "http://localhost:3000"
  phases:
    - duration: 10
      arrivalRate: 10
  socketio:
    transports: ["websocket"] # 指定用WebSocket传输

scenarios:
  - name: "Test Socket.io get-data endpoint"
    engine: "socketio"
    flow:
      - emit:
          channel: "get-data"
          response:
            - channel: "get-data"
              match:
                value: "{{ value }}"
              capture:
                json: "$.value"
                as: "responseValue"
      - log: "Received response: {{ responseValue }}"

运行步骤

  1. 先启动Redis服务(确保本地Redis在6379端口运行,或者修改代码里的Redis地址)
  2. 启动PM2集群:
pm2 start ecosystem.config.js
  1. 运行Artillery测试:
artillery run artillery.yml

这样测试下来,你应该就能正常获取响应,不会再出现NaN的问题了。核心就是通过Redis适配器让所有PM2 Worker共享Socket.io的连接和事件状态,不管请求打到哪个Worker,都能正确处理客户端的连接和请求。

内容的提问来源于stack exchange,提问作者Bhuvanesh Arasu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:23:23