Skip to main content
Version: 4.x

Redis 适配器

工作原理

¥How it works

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

¥The Redis adapter relies on the Redis Pub/Sub mechanism.

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

¥Every packet that is sent to multiple clients (e.g. io.to("room1").emit() or socket.broadcast.emit()) is:

  • 发送到连接到当前服务器的所有匹配客户端

    ¥sent to all matching clients connected to the current server

  • 在 Redis 通道中发布,并由集群中的其他 Socket.IO 服务器接收

    ¥published in a Redis channel, and received by the other Socket.IO servers of the cluster

Diagram of how the Redis adapter worksDiagram of how the Redis adapter works

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

¥The source code of this adapter can be found here.

支持的功能

¥Supported features

特性socket.io 版本支持
套接字管理4.0.0:白色复选标记:是(自版本 6.1.0 起)
服务器间通信4.1.0:白色复选标记:是(自版本 7.0.0 起)
广播并致谢4.5.0:白色复选标记:是(自版本 7.2.0 起)
连接状态恢复4.6.0:X:不

安装

¥Installation

npm install @socket.io/redis-adapter

兼容性表

¥Compatibility table

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

用法

¥Usage

使用 redis

¥With the redis package

caution

redis 包似乎在重新连接后恢复 Redis 订阅时出现问题:

¥The redis package seems to have problems restoring the Redis subscriptions after reconnection:

你可能想改用 ioredis 包。

¥You may want to use the ioredis package instead.

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 集群

¥With the redis package and a Redis cluster

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

¥With the ioredis package

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 集群

¥With the ioredis package and a Redis cluster

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 共享 Pub/Sub

¥With Redis sharded Pub/Sub

Redis 7.0 中引入了分片 Pub/Sub,以帮助扩展集群模式下 Pub/Sub 的使用。

¥Sharded Pub/Sub was introduced in Redis 7.0 in order to help scaling the usage of Pub/Sub in cluster mode.

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

¥Reference: https://redis.io/docs/interact/pubsub/#sharded-pubsub

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

¥A dedicated adapter can be created with the createShardedAdapter() method:

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);

最低要求:

¥Minimum requirements:

caution

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

¥It is not currently possible to use the sharded adapter with the ioredis package and a Redis cluster (reference).

选项

¥Options

默认适配器

¥Default adapter

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

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

¥Setting the publishOnSpecificResponseChannel option to true is more efficient since the responses (for example when calling fetchSockets() or serverSideEmit()) are only sent to the requesting server, and not to all the servers.

但是,为了向后兼容,它目前默认为 false

¥However, it currently defaults to false for backward-compatibility.

共享适配器

¥Sharded adapter

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

常见问题

¥Common questions

Redis 中是否存储有数据?

¥Is there any data stored in Redis?

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

¥No, the Redis adapter uses the Pub/Sub mechanism to forward the packets between the Socket.IO servers, so there are no keys stored in Redis.

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

¥Do I still need to enable sticky sessions when using the Redis adapter?

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

¥Yes. Failing to do so will result in HTTP 400 responses (you are reaching a server that is not aware of the Socket.IO session).

更多信息可参见 此处

¥More information can be found here.

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

¥What happens when the Redis server is down?

如果与 Redis 服务器的连接被切断,数据包只会发送到与当前服务器连接的客户端。

¥In case the connection to the Redis server is severed, the packets will only be sent to the clients that are connected to the current server.

socket.io-redis 迁移

¥Migrating from socket.io-redis

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

¥The package was renamed from socket.io-redis to @socket.io/redis-adapter in v7, in order to match the name of the Redis emitter (@socket.io/redis-emitter).

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

¥To migrate to the new package, you'll need to make sure to provide your own Redis clients, as the package will no longer create Redis clients on behalf of the user.

前:

¥Before:

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

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

后:

¥After:

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));
tip

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

¥The communication protocol between the Socket.IO servers has not been updated, so you can have some servers with socket.io-redis and some others with @socket.io/redis-adapter at the same time.

最新版本

¥Latest releases

版本发布日期发行说明差异
8.3.02024 年 3 月link8.2.1...8.3.0
8.2.12023 年 5 月link8.2.0...8.2.1
8.2.02023 年 5 月link8.1.0...8.2.0
8.1.02023 年 2 月link8.0.0...8.1.0
8.0.02022 年 12 月link7.2.0...8.0.0
7.2.02022 年 5 月link7.1.0...7.2.0

完整的变更日志

¥Complete changelog

触发器

¥Emitter

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

¥The Redis emitter allows sending packets to the connected clients from another Node.js process:

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

该触发器还有多种语言版本:

¥This emitter is also available in several languages:

安装

¥Installation

npm install @socket.io/redis-emitter redis

用法

¥Usage

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()

¥Note: with redis@3, calling connect() on the Redis client is not needed:

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);

请参阅备忘单 此处

¥Please refer to the cheatsheet here.

socket.io-emitter 迁移

¥Migrating from socket.io-emitter

该包在 v4 年从 socket.io-emitter 更名为 @socket.io/redis-emitter,以便更好地体现与 Redis 的关系。

¥The package was renamed from socket.io-emitter to @socket.io/redis-emitter in v4, in order to better reflect the relationship with Redis.

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

¥To migrate to the new package, you'll need to make sure to provide your own Redis clients, as the package will no longer create Redis clients on behalf of the user.

前:

¥Before:

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

后:

¥After:

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

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

最新版本

¥Latest releases

版本发布日期发行说明差异
5.1.02023 年 1 月link5.0.0...5.1.0
5.0.02022 年 9 月link4.1.1...5.0.0
4.1.12022 年 1 月link4.1.0...4.1.1
4.1.02021 年 5 月link4.0.0...4.1.0
4.0.02021 年 3 月link3.2.0...4.0.0

完整的变更日志

¥Complete changelog