Socket.io Node.js集群环境下同一事件重复触发问题求助
Socket.io集群下事件重复触发的问题解决
问题根源
- 版本不兼容:你使用的
@socket.io/sticky是为Socket.io v3+开发的工具,和当前使用的v2.0.5版本完全不兼容,这会导致连接分配逻辑混乱,直接引发事件重复发送。 - 冗余服务实例:Worker进程中额外创建了
httpServer实例,虽然未监听端口,但会干扰sticky session的正常工作流程,加剧连接处理异常。 - 广播逻辑叠加:结合Redis适配器使用
io.to('data').emit时,版本不兼容会导致事件被当前Worker和其他Worker重复广播,最终客户端收到多次相同事件。
修复方案
第一步:替换兼容的sticky session工具
卸载不兼容的@socket.io/sticky,安装适配Socket.io v2的sticky-session:
npm uninstall @socket.io/sticky npm install sticky-session
第二步:修正服务端代码
const cluster = require("cluster"); const http = require("http"); const { Server } = require("socket.io"); const redisAdapter = require("socket.io-redis"); const sticky = require("sticky-session"); const server = http.createServer(); // 启动sticky session集群 if (!sticky.listen(server, 3000)) { // Master进程逻辑 console.log(`Master ${process.pid} 已启动`); cluster.on("exit", (worker) => { console.log(`Worker ${worker.process.pid} 已退出,重启中...`); cluster.fork(); }); } else { // Worker进程逻辑 console.log(`Worker ${process.pid} 已启动`); const io = new Server(); io.attach(server); // 配置Redis适配器,确保本地Redis服务正常运行 io.adapter(redisAdapter({ host: "localhost", port: 6379 })); io.on("connection", (socket) => { console.log("新客户端连接"); socket.join("data"); // 如果仅需给当前连接的客户端发送事件,用socket.emit更高效,避免不必要的广播 // socket.emit("event", "data"); // 若需给整个房间发送事件,确保socket.io-redis版本为5.x(与Socket.io v2.0.5兼容) io.to('data').emit("event", "data"); }); }
额外提示
- 如果业务允许,建议直接升级Socket.io到v3+版本,配合官方的
@socket.io/sticky使用,兼容性和稳定性会更有保障。 - 检查Redis服务是否正常启动,避免因Redis连接失败导致的适配器逻辑异常。
内容的提问来源于stack exchange,提问作者İrem Simsar
相关产品推荐
相关产品推荐

