PM2集群模式下Socket.io跨实例广播失败该如何解决
问题根因
报错Error: The client is closed是因为你使用的Redis v4.x版本API有变动:
- 创建客户端后不会自动建立连接,需要手动调用
connect方法 - 连接配置的结构与旧版不同,
host/port需要放到socket属性下,鉴权字段从auth_pass改为password
另外你的代码还有两个可优化点:
- 不需要手动给
subClient赋值psubscribe方法,Redis v4已原生支持 - 定时器不要放到
connection回调中,否则每有一个新客户端连接到实例0就会新增一个定时器,导致消息重复发送
修正后的服务端index.js代码
const { Server } = require("socket.io") const { createAdapter } = require("@socket.io/redis-adapter"); const { createClient } = require("redis"); const io = new Server({ transports: ['websocket'] }) // Redis v4 配置写法 const pubClient = createClient({ socket: { host: 'localhost', port: 6379 }, password: "root" }); const subClient = pubClient.duplicate(); // 等待Redis连接成功后再挂载适配器 Promise.all([ pubClient.connect(), subClient.connect() ]).then(() => { io.adapter(createAdapter(pubClient, subClient)) }).catch(err => { console.error('Redis连接失败', err) }) io.listen(3000) // 定时器放到全局,仅实例0启动一次 if(process.env.NODE_APP_INSTANCE == 0){ setInterval(() => { io.emit('test_msg', 'server: ' + process.env.NODE_APP_INSTANCE) }, 5000) } io.on("connection", (socket) => { console.log(socket.id + ' connected on server: ' + process.env.NODE_APP_INSTANCE) });
验证步骤
- 确认本地Redis服务已正常启动,密码配置为
root - 重启PM2集群:
pm2 reload ecosystem.config.js - 启动多个客户端进程测试,所有客户端都会收到实例0推送的
test_msg事件,服务端不会再抛出Redis客户端关闭的错误
你的PM2配置无需修改,集群模式下多个Node.js进程可以共享监听同一个端口,PM2会自动完成负载均衡。
内容的提问来源于stack exchange,提问作者Prem popatia
相关产品推荐
相关产品推荐

