Skip to content

Redis 消息总线

多实例部署时,每个 IM 后端只持有自己进程内的 WebSocket 连接。当用户 A 连在实例 1、用户 B 连在实例 2 时,A 发给 B 的消息需要跨实例传递。Redis Pub/Sub 充当消息总线,解决这一问题。

工作原理

实例 1 ──发布──▶ Redis Pub/Sub Channel ──▶ 实例 2 ──推送──▶ 用户 B
                   (im:broadcast)
实例 2 ──发布──▶ Redis Pub/Sub Channel ──▶ 实例 1 ──推送──▶ 用户 A
                   (im:broadcast)

每个 IM 实例启动后订阅 Redis 的 im:broadcast 频道。当某个实例需要向用户发送消息时,先将消息发布到 Redis 频道,所有实例收到广播后检查目标用户是否连在本实例上,如果是则推送。

为什么需要 Redis

本地 Messenger(local)使用内存 Map 维护连接关系,只在单进程内有效。多实例场景下,进程间无法直接共享内存,必须借助外部消息中间件。

Redis Pub/Sub 的优势在于延迟极低(微秒级)、部署简单、无需额外队列存储,非常适合实时消息广播场景。

配置

通过环境变量启用 Redis 消息总线:

bash
MESSENGER=redis \
REDIS_HOST=127.0.0.1 \
REDIS_PORT=6379 \
REDIS_PASSWORD=your_password \
node index.js

或在 config.yaml 中配置:

yaml
messenger: redis

redis:
  host: 127.0.0.1
  port: 6379
  password: your_password
  db: 0

核心机制

连接注册:用户 WebSocket 连入某实例时,该实例在 Redis 的 im:online:{userId} 集合中记录自己的实例 ID,表示该用户当前在本实例在线。

消息路由:发送消息时,先查询目标用户在哪个实例在线,然后只向该实例广播。如果用户多端在线分布在多个实例,则向相关实例都广播。

离线处理:如果目标用户不在线(Redis 中无记录),消息写入数据库并触发推送通知,不走 Redis 广播。

断线清理:WebSocket 断开时,实例从 Redis 中移除该用户的在线记录。

在线状态同步

Redis 不仅用于消息广播,还承担在线状态存储:

# 用户上线
SADD im:online:user_123 instance_1

# 查询用户在线实例
SMEMBERS im:online:user_123
# → ["instance_1", "instance_3"]

# 用户下线
SREM im:online:user_123 instance_1

这使得任何实例都能快速判断目标用户的连接位置,避免全实例广播。

部署建议

单节点 Redis:中小规模(10 实例以内)使用单节点 Redis 即可满足需求。

Redis Sentinel:需要高可用时,使用 Sentinel 实现自动故障转移。

Redis Cluster:超大规模场景可使用 Cluster 分片,但通常 IM 的消息广播不需要分片。

内存配置:Redis 在此场景下主要存储在线状态(Set 结构),内存占用很小。建议分配 256MB~512MB 即可。

免费版说明

免费版使用本地 Messenger,所有连接在单进程内管理,不需要 Redis。Redis 消息总线是收费版分布式架构的组件,配合 MySQL 存储插件实现多实例协作。