Axon框架QueryHandler扩容后负载不均问题咨询
问题描述
在扩容查询处理应用时,我期望多个实例能获得相对均衡的请求负载,但所有查询都集中到了单个实例上。

有多个外部服务通过QueryGateway发送此类查询,我需要能在高请求量下分发负载的异步请求/响应服务,这难道不是QueryGateway的适用场景吗?
QueryHandler代码(Spring Boot应用)
@Component public class CalculateProfanityScoreQueryHandler { @QueryHandler public CompletableFuture<ProfanityScore> handle(CalculateProfanityScoreQuery query) { int score = rateComment(); ProfanityScore profanityScore = new ProfanityScore(score); return CompletableFuture.completedFuture(profanityScore); } }
外部服务发送请求代码(连接同一Axon Server实例)
@Override public ProfanityEvaluation calculateScore(String comment) { var profanityScore = queryGateway .query( new CalculateProfanityScoreQuery(comment), ResponseTypes.instanceOf(ProfanityScore.class)) .get(); // rest of logic }
服务扩容至6个实例后的Axon仪表板概览:
解决方案
Axon Framework的QueryGateway默认采用点对点路由策略,同一类型查询会固定路由到单个处理实例,这就是负载集中的核心原因。针对你的无状态查询场景(评分计算无需依赖实例本地状态),可以通过以下方式实现负载均衡:
1. 使用Scatter-Gather查询模式
直接修改外部服务的查询发送逻辑,用scatterGather替代query方法。该模式会将查询广播给所有可用的处理实例,返回第一个收到的响应,天然实现负载均衡:
@Override public ProfanityEvaluation calculateScore(String comment) { var profanityScore = queryGateway .scatterGather( new CalculateProfanityScoreQuery(comment), ResponseTypes.instanceOf(ProfanityScore.class), ScatterGatherQueryDefinition.builder() .timeout(Duration.ofSeconds(2)) // 配置超时时间 .build()) .blockFirst(); // 替代.get(),避免强制阻塞的不优雅写法 // rest of logic }
2. 配置全局负载均衡策略
如果需要所有查询默认启用负载均衡,可通过Spring Boot配置或Java代码全局设置:
方式一:配置文件
axon.query.gateway.load-balancing-strategy=round-robin
方式二:Java配置类
@Configuration public class AxonConfig { @Bean public QueryGateway queryGateway(QueryBus queryBus) { return DefaultQueryGateway.builder() .queryBus(queryBus) .loadBalancingStrategy(new RoundRobinLoadBalancingStrategy()) // 轮询策略 .build(); } }
3. 确认Axon Server注册状态
确保所有6个服务实例都成功注册到Axon Server,且Axon Server未配置针对该查询的特殊路由规则,实例状态均为在线可用。
内容的提问来源于stack exchange,提问作者Robin van den Bogaard
相关产品推荐
相关产品推荐

