Socket.io搭配Redis适配器未写入Redis,跨节点消息异常求助
Socket.io多Pod部署Redis适配器未生效问题解决方案
核心问题分析
- 你使用的
socket.io-redis是已废弃的旧版适配器,仅兼容Socket.io v3及以下版本,最新版Socket.io(v4+)需使用官方维护的@socket.io/redis-adapter。 redis包v4+采用Promise API,默认未建立连接,直接使用会报错“The client is closed”,且不再支持回调写法。- 旧适配器的初始化逻辑与新版不兼容,导致Redis未被实际启用。
分步解决
1. 替换依赖包
卸载旧适配器,安装官方新版:
npm uninstall socket.io-redis npm install @socket.io/redis-adapter redis
2. 修正Redis客户端与适配器初始化代码
以下是适配最新版Socket.io与Redis的完整代码:
import { Server } from 'socket.io'; import { createAdapter } from '@socket.io/redis-adapter'; import { createClient } from 'redis'; let io = null; const WebSocketsManager = { // 改为async函数,等待Redis连接建立 init: async (server) => { // 创建Redis发布/订阅客户端 const pubClient = createClient({ host: REDIS_HOST, port: REDIS_PORT }); const subClient = pubClient.duplicate(); // 等待客户端连接完成 await Promise.all([pubClient.connect(), subClient.connect()]); // 创建Redis适配器并绑定到Socket.io const adapter = createAdapter(pubClient, subClient); io = new Server(server, { origins: '*:*', path: '/public/socket.io', }); io.adapter(adapter); io.on('connection', (socket) => { socket.on('disconnect', () => { console.log(`用户 ${socket.id} 断开连接`); }); socket.on('enteredRoomName', async (data) => { const roomName = WebSocketsManager.getRoomName(data, 'RoomName'); // Socket.io v4+中join返回Promise,建议await保证操作完成 await socket.join(roomName); // 从Redis适配器获取房间信息 const room = io.sockets.adapter.rooms.get(roomName); console.log(`用户 ${socket.id} 加入房间 '${roomName}' (当前人数: ${room.size})`); // 测试Redis写入(Promise风格) try { await pubClient.set('mykey2', 'myvalue'); console.log('Redis写入成功'); } catch (err) { console.error('Redis写入失败:', err); } }); socket.on('exitedRoomName', async (data) => { const roomName = WebSocketsManager.getRoomName(data, 'RoomName'); await WebSocketsManager.exitRoom(roomName, socket); }); }); }, getRoomName: (data, actionType) => { // 你的房间名称生成逻辑,示例: return `${actionType}-${data.userId}`; }, exitRoom: async (roomName, socket) => { await socket.leave(roomName); const room = io.sockets.adapter.rooms.get(roomName); const userCount = room ? room.size : 0; console.log(`用户 ${socket.id} 离开房间 '${roomName}' (当前人数: ${userCount})`); }, };
3. 验证Redis生效
部署后,当用户加入房间时,使用redis-cli执行以下命令,应能看到Socket.io存储的房间相关键:
SCAN 0 MATCH *RoomName*
额外说明(使用ioredis的情况)
若你偏好使用ioredis,只需替换Redis客户端初始化代码即可,适配器逻辑不变:
import Redis from 'ioredis'; // 创建ioredis客户端 const pubClient = new Redis({ host: REDIS_HOST, port: REDIS_PORT }); const subClient = new Redis({ host: REDIS_HOST, port: REDIS_PORT }); // 后续适配器创建与绑定逻辑与上述一致 const adapter = createAdapter(pubClient, subClient);
内容的提问来源于stack exchange,提问作者Anton Shestakov
相关产品推荐
相关产品推荐

