hyperf 3.1 跨节点 websocket 广播需 redis 存储连接元数据(ws:connections:{uid} 和 ws:nodes),通过 pub/sub 或消息队列分发广播,nginx 启用 sticky 策略与长连接保活配置协同实现可靠广播。

Hyperf 3.1 的 WebSocket 广播在单机多 Worker 进程下靠 Sender 组件通过管道通信就能完成;但跨服务节点(即多个 Hyperf 实例部署在不同机器或容器)时,必须引入外部协调机制——因为每个节点的连接状态只存在于本机内存,彼此不可见。
连接归属需全局可查
广播前得知道“用户 A 当前连在哪台服务器上”。不能靠猜测或轮询,必须把连接元数据持久化到共享存储:
- 用 Redis Hash 存储:
ws:connections:{uid}记录用户 ID 对应的node_id:fd,同时设置过期时间(如 30 分钟),配合心跳刷新 - 每个节点启动时注册自身
node_id(如node-01)到 Redis Set:ws:nodes,便于后续广播时遍历或做健康剔除 - 连接建立时写入,断开时主动删除;若异常断连,依赖心跳超时自动清理,避免脏数据
消息广播走中间件,不走节点直连
禁止让节点 A 主动调用节点 B 的 HTTP 接口推送消息——易引发雪崩、环路、超时堆积。推荐两种稳定路径:
-
Redis Pub/Sub:业务服务发布消息到频道
ws:broadcast,所有节点都订阅该频道;收到后,查本地连接缓存 + Redis 元数据,只向本节点管理的 fd 推送 - RabbitMQ/Kafka:更适合高吞吐或需消息持久、重试、顺序保障的场景;各节点作为消费者,消费后按连接归属做本地投递
Nginx 层必须做连接粘性
否则客户端 WebSocket 握手请求被轮询到不同节点,导致同一用户多次重复连接、旧连接残留、广播错乱:
- 用
ip_hash最简单,适合公网 IP 相对稳定、移动端不多的场景 - 用 OpenResty 或 Nginx Plus 的
sticky cookie更精准:首次响应写入route=node-01,后续请求带该 cookie 路由固定节点 - 禁用
least_conn和纯轮询;WebSocket 不是短连接,负载均衡策略要为长连接服务
保活与生命周期协同
从客户端、Nginx 到后端,每一层都可能静默断连,必须统一应对:
- Nginx 配置
proxy_read_timeout 3600、proxy_send_timeout 3600、proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade - Hyperf 启用
ping/pong帧(默认已支持),间隔建议 30 秒;收到 pong 后更新 Redis 中该连接的最后活跃时间 - 断连回调中,不仅清理本地 fd,还要发一条「连接失效」事件到 Redis Pub/Sub,通知其他节点同步剔除该用户缓存











