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

Socket.io搭配Redis适配器未写入Redis,跨节点消息异常求助

Socket.io多Pod部署Redis适配器未生效问题解决方案

核心问题分析

  1. 你使用的socket.io-redis是已废弃的旧版适配器,仅兼容Socket.io v3及以下版本,最新版Socket.io(v4+)需使用官方维护的@socket.io/redis-adapter。
  2. redis包v4+采用Promise API,默认未建立连接,直接使用会报错“The client is closed”,且不再支持回调写法。
  3. 旧适配器的初始化逻辑与新版不兼容,导致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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:23:12