跳至主要内容
版本: 4.x

Redis 适配器

工作原理

Redis 适配器依赖于 Redis 的 发布/订阅机制.

发送到多个客户端的每个数据包(例如 io.to("room1").emit()socket.broadcast.emit())都会

  • 发送到连接到当前服务器的所有匹配客户端
  • 发布到 Redis 通道,并由集群中的其他 Socket.IO 服务器接收
Diagram of how the Redis adapter worksDiagram of how the Redis adapter works

此适配器的源代码可以在 此处 找到。

支持的功能

功能socket.io 版本支持
套接字管理4.0.0✅ 是(从版本 6.1.0 开始)
服务器间通信4.1.0✅ 是(从版本 7.0.0 开始)
带有确认的广播4.5.0✅ 是(从版本 7.2.0 开始)
连接状态恢复4.6.0❌ 否

安装

npm install @socket.io/redis-adapter

兼容性表

Redis 适配器版本Socket.IO 服务器版本
4.x1.x
5.x2.x
6.0.x3.x
6.1.x4.x
7.x 及更高版本4.3.1 及更高版本

用法

使用 redis

注意

redis 包似乎在重新连接后恢复 Redis 订阅方面存在问题

您可能希望改用 ioredis 包。

import { createClient } from "redis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = createClient({ url: "redis://localhost:6379" });
const subClient = pubClient.duplicate();

await Promise.all([
pubClient.connect(),
subClient.connect()
]);

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

使用 redis 包和 Redis 集群

import { createCluster } from "redis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = createCluster({
rootNodes: [
{
url: "redis://localhost:7000",
},
{
url: "redis://localhost:7001",
},
{
url: "redis://localhost:7002",
},
],
});
const subClient = pubClient.duplicate();

await Promise.all([
pubClient.connect(),
subClient.connect()
]);

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

使用 ioredis

import { Redis } from "ioredis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = new Redis();
const subClient = pubClient.duplicate();

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

使用 ioredis 包和 Redis 集群

import { Cluster } from "ioredis";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";

const pubClient = new Cluster([
{
host: "localhost",
port: 7000,
},
{
host: "localhost",
port: 7001,
},
{
host: "localhost",
port: 7002,
},
]);
const subClient = pubClient.duplicate();

const io = new Server({
adapter: createAdapter(pubClient, subClient)
});

io.listen(3000);

使用 Redis 分片发布/订阅

分片发布/订阅是在 Redis 7.0 中引入的,旨在帮助扩展集群模式下发布/订阅的使用。

参考: https://redis.ac.cn/docs/interact/pubsub/#sharded-pubsub

可以使用 createShardedAdapter() 方法创建专用适配器

import { Server } from "socket.io";
import { createClient } from "redis";
import { createShardedAdapter } from "@socket.io/redis-adapter";

const pubClient = createClient({ host: "localhost", port: 6379 });
const subClient = pubClient.duplicate();

await Promise.all([
pubClient.connect(),
subClient.connect()
]);

const io = new Server({
adapter: createShardedAdapter(pubClient, subClient)
});

io.listen(3000);

最低要求

注意

目前无法将分片适配器与 ioredis 包和 Redis 集群一起使用 (参考)。

选项

默认适配器

名称描述默认值
keyRedis 发布/订阅通道的前缀。socket.io
requestsTimeout超过此超时时间后,适配器将停止等待请求的响应。5_000
publishOnSpecificResponseChannel是否将响应发布到请求节点的特定通道。false
parser用于对发送到 Redis 的消息进行编码和解码的解析器。-
提示

publishOnSpecificResponseChannel 选项设置为 true 效率更高,因为响应(例如在调用 fetchSockets()serverSideEmit() 时)仅发送到请求服务器,而不是发送到所有服务器。

但是,它目前默认为 false,以实现向后兼容。

分片适配器

名称描述默认值
channelPrefixRedis 发布/订阅通道的前缀。socket.io
subscriptionMode订阅模式会影响适配器使用的 Redis 发布/订阅通道数量。dynamic

常见问题

Redis 中是否存储了任何数据?

没有,Redis 适配器使用 发布/订阅机制 在 Socket.IO 服务器之间转发数据包,因此 Redis 中没有存储任何键。

在使用 Redis 适配器时,我是否仍然需要启用粘性会话?

是的。如果未这样做,将导致 HTTP 400 响应(您正在访问一个不知道 Socket.IO 会话的服务器)。

可以在 此处 找到更多信息。

Redis 服务器宕机时会发生什么?

如果与 Redis 服务器的连接断开,数据包将仅发送到连接到当前服务器的客户端。

socket.io-redis 迁移

该包已在 v7 中从 socket.io-redis 重命名为 @socket.io/redis-adapter,以匹配 Redis 发射器 (@socket.io/redis-emitter) 的名称。

要迁移到新包,您需要确保提供自己的 Redis 客户端,因为该包将不再代表用户创建 Redis 客户端。

之前

const redisAdapter = require("socket.io-redis");

io.adapter(redisAdapter({ host: "localhost", port: 6379 }));

之后

const { createClient } = require("redis");
const { createAdapter } = require("@socket.io/redis-adapter");

const pubClient = createClient({ url: "redis://localhost:6379" });
const subClient = pubClient.duplicate();

io.adapter(createAdapter(pubClient, subClient));
提示

Socket.IO 服务器之间的通信协议尚未更新,因此您可以同时使用一些具有 socket.io-redis 的服务器和一些具有 @socket.io/redis-adapter 的服务器。

最新版本

版本发布日期发行说明差异
8.3.02024 年 3 月链接8.2.1...8.3.0
8.2.12023 年 5 月链接8.2.0...8.2.1
8.2.02023 年 5 月链接8.1.0...8.2.0
8.1.02023 年 2 月链接8.0.0...8.1.0
8.0.02022 年 12 月链接7.2.0...8.0.0
7.2.02022 年 5 月链接7.1.0...7.2.0

完整变更日志

发射器

Redis 发射器允许从另一个 Node.js 进程向连接的客户端发送数据包

Diagram of how the Redis emitter worksDiagram of how the Redis emitter works

此发射器也以多种语言提供

安装

npm install @socket.io/redis-emitter redis

用法

import { Emitter } from "@socket.io/redis-emitter";
import { createClient } from "redis";

const redisClient = createClient({ url: "redis://localhost:6379" });

redisClient.connect().then(() => {
const emitter = new Emitter(redisClient);

setInterval(() => {
emitter.emit("time", new Date);
}, 5000);
});

注意: 使用 redis@3 时,无需在 Redis 客户端上调用 connect()

import { Emitter } from "@socket.io/redis-emitter";
import { createClient } from "redis";

const redisClient = createClient({ url: "redis://localhost:6379" });
const emitter = new Emitter(redisClient);

setInterval(() => {
emitter.emit("time", new Date);
}, 5000);

请参考 此处 的速查表。

socket.io-emitter 迁移

该包已在 v4 中从 socket.io-emitter 重命名为 @socket.io/redis-emitter,以更好地反映与 Redis 的关系。

要迁移到新包,您需要确保提供自己的 Redis 客户端,因为该包将不再代表用户创建 Redis 客户端。

之前

const io = require("socket.io-emitter")({ host: "127.0.0.1", port: 6379 });

之后

const { Emitter } = require("@socket.io/redis-emitter");
const { createClient } = require("redis");

const redisClient = createClient();
const io = new Emitter(redisClient);

最新版本

版本发布日期发行说明差异
5.1.02023 年 1 月链接5.0.0...5.1.0
5.0.02022 年 9 月链接4.1.1...5.0.0
4.1.12022 年 1 月链接4.1.0...4.1.1
4.1.02021 年 5 月链接4.0.0...4.1.0
4.0.02021 年 3 月链接3.2.0...4.0.0

完整变更日志