Quarkus+Vert.x部署双Verticle查询多数据库未并行执行问题咨询
问题原因
- Verticle串行部署:你当前的部署代码中使用
await().indefinitely()阻塞等待第一个Verticle部署完成后,才开始部署第二个Verticle,导致两个Verticle的EventBus consumer注册存在时间差。如果事件触发时第二个consumer还未完成注册,就会出现任务触发延迟,看起来像串行执行。 - 查询结果返回时间差:如果两个Verticle的handler触发时间(即
>>> Start Handler日志的时间戳)几乎一致,那日志呈现的串行输出只是因为fruit库查询响应更快,结果先全部返回打印,bill库查询响应慢200ms左右,所以后输出,实际查询已经是并行触发的,只是结果返回时序导致看起来串行。
调整方案
方案1:并行部署Verticle
如果要保留现有Verticle的实现,把串行部署逻辑改为并行部署,确保两个Verticle的consumer同时注册完成:
public void init(@Observes StartupEvent event, Vertx vertx, DbTestVerticle dbTestVerticle, DbFruitVerticle dbFruitVerticle) { // 同时触发两个Verticle部署,等待全部部署完成后再结束启动逻辑 Uni.join().all( vertx.deployVerticle(dbTestVerticle), vertx.deployVerticle(dbFruitVerticle) ).await().indefinitely(); }
调整后两个consumer会几乎同时注册完成,此时再publish事件,两个查询任务会同时触发。
方案2:直接用Mutiny流组合实现并行查询(更推荐)
这类并行拉取多数据源的场景不需要单独创建Verticle,直接通过Mutiny的流组合能力即可实现并行,代码更简洁,没有EventBus通信的额外开销:
@ApplicationScoped public class DbQueryService { @Inject @ReactiveDataSource("fruit") PgPool pgPoolFruit; @Inject @ReactiveDataSource("bill") PgPool pgPoolBill; // 并行拉取两个库的数据,返回Tuple封装的两个结果集 public Uni<Tuple2<List<Fruit>, List<Bill>>> parallelGetAll() { return Uni.join().all( // fruit库查询逻辑 pgPoolFruit.query("select f.* from fruit f").execute() .onItem().transformToMulti(set -> Multi.createFrom().iterable(set)) .map(this::mapFruit) .collect().asList(), // bill库查询逻辑 pgPoolBill.query("select b.* from bill b").execute() .onItem().transformToMulti(set -> Multi.createFrom().iterable(set)) .map(this::mapBill) .collect().asList() ).asTuple(); } private Fruit mapFruit(Row row) { // 映射逻辑 } private Bill mapBill(Row row) { // 映射逻辑 } }
该方案中两个查询是冷流,调用join时会同时订阅两个流,触发并行执行,不需要依赖EventBus通信。
最佳实践
- 无依赖关系的Verticle部署要并行执行,不要串行加
await阻塞,避免不必要的启动延迟和注册时序问题。 - 多数据源并行查询场景优先使用Mutiny的
Uni.join()/Multi.join()能力组合流,不要依赖EventBus广播触发任务,避免消息投递时序问题和额外的通信开销。 - 所有IO操作都使用响应式客户端,不要在EventLoop线程中执行任何阻塞操作,避免EventLoop被阻塞导致任务串行执行。
- 验证并行是否生效可在任务触发入口打印时间戳,不要只看结果输出的时序,结果返回的时间差会导致输出看起来串行,不代表任务没有并行触发。
内容的提问来源于stack exchange,提问作者Anhelica
相关产品推荐
相关产品推荐

