Vert.x 实战(三):Event Loop、HTTP 边界与异步测试
订单项目目前所有 Handler 都只操作内存并发送异步消息,很快就会返回。但一旦接入同步 JDBC、文件读取或旧 SDK,最容易出现的错误就是把阻塞调用直接放进路由 Handler。
1 | router.post("/orders").handler(ctx -> { |
问题不只影响当前请求。这个 Event Loop 负责的其他连接也无法及时处理读写事件,因此延迟会成片上升。
先观察,不先调线程数
开发环境可以把检查阈值调低,让问题尽早暴露:
1 | VertxOptions options = new VertxOptions() |
这些值用于诊断,不应该不经测量照搬到生产。出现警告后先看堆栈,确认阻塞位置;增加 Event Loop 线程数只能延后拥塞,不能修复同步调用。
无法替换的阻塞 API
旧 SDK 暂时没有异步版本时,可以把小段阻塞操作移到 Worker Pool:
1 | vertx.executeBlocking(() -> legacyClient.reserve(sku, quantity)) |
Worker Pool 也有上限。必须同时设置下游超时、监控队列等待并限制并发;否则只是把 Event Loop 堵塞改成 Worker Pool 排队。
用 JFR 保留证据
1 | jcmd <pid> JFR.start name=vertx settings=profile duration=60s filename=vertx.jfr |
录制期间执行稳定、可重复的请求,再用 JDK Mission Control 查看线程状态、Socket I/O、锁等待和分配热点。文章不会给出“JFR 固定小于 2%”之类脱离工作负载的承诺;开销应在自己的环境中测量。
本章也不声称当前示例能达到某个 QPS。没有独立压测机、请求模型、延迟分位和错误率的单个吞吐数字没有参考意义。
HTTP 层只承担协议职责
一个教学项目无法完整覆盖网关所需的协议安全、连接池、限流、动态配置和可观测性,因此当前项目只实现订单服务真正需要的 HTTP 接入层:
1 | Router router = Router.router(vertx); |
HttpVerticle 把 JSON 转成 Event Bus 消息,再将回复转换为 HTTP 响应。订单规则仍留在 OrderVerticle,以后增加其他协议入口时不需要复制业务校验。
JSON 解析失败应立即返回 400:
1 | try { |
创建成功使用 201,库存不足使用 409,内部依赖不可用使用 503。状态码会影响客户端究竟修正参数、提示用户还是稍后重试,不能把所有错误统一包装成 200 或 500。
公开部署前还需要请求体大小限制、Schema、认证授权、请求 ID、结构化日志、幂等键、TLS 和优雅停机。本文称它为“HTTP 边界”,而不是无法由代码支撑的“生产网关”。
用 VertxTestContext 测真实异步链路
每个测试先部署实际消费者:
1 |
|
只有两个 Verticle 都启动成功后才进入测试。忘记完成 VertxTestContext 会等待到超时,过早完成又可能让尚未运行的断言被跳过。
创建和查询通过同一条 Future 链验证:
1 | vertx.eventBus().<JsonObject>request(OrderVerticle.CREATE_ADDRESS, request) |
context.verify 会把异步回调中的断言异常交还 JUnit。第二条测试通过 context.failing 验证库存不足必须失败,而不是仅检查成功路径。
1 | ./gradlew test |
这些测试证明当前消息链在已覆盖场景下工作,但还不能替代 HTTP 集成测试、并发库存测试、超时测试和线上监控。
- 标题: Vert.x 实战(三):Event Loop、HTTP 边界与异步测试
- 作者: Elvis
- 创建于 : 2026-03-04 18:00:00
- 更新于 : 2026-04-01 13:20:00
- 链接: https://qianwj.github.io/2026/03/04/vertx-series-3/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。