水平扩展
Sticky session、Redis 广播桥接概念。
30 分钟
水平扩展
单实例 enableSimpleBroker 只在 内存 广播;多 Spring Boot 副本时,A 实例上的用户收不到 B 实例上的消息。需 Sticky Session 或 Redis 桥接(redis-pubsub)。
学习目标
- 理解 WebSocket 与无状态 REST 的扩展差异
- 配置 Nginx
ip_hash/ cookie sticky - 知道 Redis Pub/Sub 做跨节点 fan-out 的思路
问题示意
用户1 ──WS──► 实例 A ── publish ──► 仅 A 的订阅者收到
用户2 ──WS──► 实例 B ── ✗ 收不到 A 上的消息
REST 可任意负载均衡;WS 连接 粘在某实例 直到断开。
方案一:Sticky Session
upstream coderoadmap_backend {
ip_hash; # 或 sticky cookie
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
见 ws-nginx。缺点:实例重启时该节点上的连接全断。
方案二:Redis 消息桥
实例 A ──► Redis channel lab.chat ──► 实例 A、B 都订阅 ──► 各自推给本地 WS 会话
Spring 可换 RabbitMQ / Redis 作为外部 Broker(enableStompBrokerRelay),替代 enableSimpleBroker:
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("redis") // 或 RabbitMQ
.setRelayPort(61613);
}
与 redis-pubsub 概念一致:发布到 channel,所有订阅者收到。
会话状态
| 数据 | 存放 | 说明 |
|---|---|---|
| 聊天历史 | MySQL | REST 写入 |
| 在线 presence | Redis SET | TTL 心跳 |
| WS 连接 | 实例内存 | 不可共享 |
redis-session 的会话共享 不替代 WS 连接共享,只解决 HTTP 登录态。
练习
- 画双实例 + Redis 桥的消息路径
- 说明 ip_hash 在 NAT 后校园网的弊端
- 查 Spring 文档: vs 选型表