Vert.x 实战(四):WebSocket 通知与多实例部署边界

Vert.x 实战(四):WebSocket 通知与多实例部署边界

Elvis Lv2

订单创建后,管理界面希望立即看到新订单。轮询可以工作,但会产生固定延迟和大量空请求。本章在同一个 HTTP Server 上增加 /events WebSocket,并把订单事件推送给已连接客户端。

业务层只发布事件

1
2
3
orders.put(id, order);
vertx.eventBus().publish(OrderVerticle.CREATED_ADDRESS, order);
message.reply(order);

订单层不知道 WebSocket 的存在。以后增加审计日志或指标消费者时,只需要订阅同一地址。这里的 publish 是进程内即时通知,不是可靠消息:没有消费者时事件会丢失,消费者失败也不会让订单创建回滚。

管理连接生命周期

1
2
3
4
5
6
7
8
9
private void connectEvents(ServerWebSocket socket) {
if (!"/events".equals(socket.path())) {
socket.close((short) 1008, "unsupported path");
return;
}
eventClients.add(socket);
socket.closeHandler(ignored -> eventClients.remove(socket));
socket.exceptionHandler(ignored -> eventClients.remove(socket));
}

创建事件到达 HTTP Verticle 后,对连接集合调用 writeTextMessage。写失败的连接会被移除,避免长期持有已失效对象。

可以使用任意 WebSocket 客户端连接:

1
wscat -c ws://localhost:8080/events

另一个终端创建订单,前一个终端应收到包含订单 ID 的 JSON。

当前版本不能直接上生产

演示实现没有处理慢客户端的写队列、身份认证、心跳、断线补发和事件顺序;服务多实例部署后,每个实例也只知道连接到自己的客户端。真实系统通常需要消息代理或持久事件流,并让客户端携带最后确认的事件位置进行恢复。

“能保持十万连接”不是 WebSocket API 自带的属性。文件描述符、TLS、消息大小、广播比例、内存和客户端网络都会改变结果。没有测试环境和原始记录时,本文不会给出具体连接数结论。

把运行参数移出代码

监听端口不应写死。入口从环境变量读取端口,再通过 DeploymentOptions 传入 HTTP Verticle:

1
2
3
4
int port = Integer.parseInt(
System.getenv().getOrDefault("HTTP_PORT", "8080"));
DeploymentOptions options = new DeploymentOptions()
.setConfig(new JsonObject().put("http.port", port));

可以在不改源码的情况下启动另一个端口:

1
HTTP_PORT=9090 ./gradlew run

正式项目还要验证端口范围,对格式错误给出清晰启动失败,并从密钥管理系统读取敏感配置而不是提交到仓库。

本地状态决定扩展方式

当前服务有两份进程内状态:库存 Map 与 WebSocket 连接集合。增加实例会让库存分裂,每个实例也只能向连接到自己的客户端推送。

水平扩展至少需要:

  • 将订单和库存事实保存到支持并发控制的持久化存储;
  • 通过可靠消息系统传播订单事件;
  • 为事件设计 ID、幂等消费与重放位置;
  • 区分存活检查和就绪检查;
  • 在优雅停机期间停止接收请求并迁移连接。

Vert.x Cluster Event Bus 能处理一部分跨节点消息寻址,但不会自动解决消息持久化、数据库一致性和 WebSocket 断线补发。对于订单事件,可靠性需求通常比“消息能够跨 JVM 到达”更重要。

一次实际的启动验证

本地验证时 8080 已被其他程序占用,Verticle 的启动 Promise 正确失败,没有报告启动成功。改用 HTTP_PORT=18080 后,健康检查返回 200,创建订单返回 201,库存不足返回 409。这也说明外部配置和错误生命周期不是可有可无的样板代码。

  • 标题: Vert.x 实战(四):WebSocket 通知与多实例部署边界
  • 作者: Elvis
  • 创建于 : 2026-03-05 14:00:00
  • 更新于 : 2026-07-12 14:00:00
  • 链接: https://qianwj.github.io/2026/03/05/vertx-series-4/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。