Vert.x 实战(四):WebSocket 通知与多实例部署边界
订单创建后,管理界面希望立即看到新订单。轮询可以工作,但会产生固定延迟和大量空请求。本章在同一个 HTTP Server 上增加 /events WebSocket,并把订单事件推送给已连接客户端。
业务层只发布事件
1 | orders.put(id, order); |
订单层不知道 WebSocket 的存在。以后增加审计日志或指标消费者时,只需要订阅同一地址。这里的 publish 是进程内即时通知,不是可靠消息:没有消费者时事件会丢失,消费者失败也不会让订单创建回滚。
管理连接生命周期
1 | private void connectEvents(ServerWebSocket socket) { |
创建事件到达 HTTP Verticle 后,对连接集合调用 writeTextMessage。写失败的连接会被移除,避免长期持有已失效对象。
可以使用任意 WebSocket 客户端连接:
1 | wscat -c ws://localhost:8080/events |
另一个终端创建订单,前一个终端应收到包含订单 ID 的 JSON。
当前版本不能直接上生产
演示实现没有处理慢客户端的写队列、身份认证、心跳、断线补发和事件顺序;服务多实例部署后,每个实例也只知道连接到自己的客户端。真实系统通常需要消息代理或持久事件流,并让客户端携带最后确认的事件位置进行恢复。
“能保持十万连接”不是 WebSocket API 自带的属性。文件描述符、TLS、消息大小、广播比例、内存和客户端网络都会改变结果。没有测试环境和原始记录时,本文不会给出具体连接数结论。
把运行参数移出代码
监听端口不应写死。入口从环境变量读取端口,再通过 DeploymentOptions 传入 HTTP Verticle:
1 | int port = Integer.parseInt( |
可以在不改源码的情况下启动另一个端口:
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 进行许可。