问题描述
我已经实现了一个基于 Spring Cloud 的应用程序,它具有以下主要架构。 GatewayService
委托给 HelloService
的多个实例。我使用 Consul 进行服务发现。 GatewayService
的实现方式如下:
@EnablediscoveryClient
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class,args);
}
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
@RestController
static class GateWayController {
private final WebClient.Builder webClientBuilder;
@Data
@NoArgsConstructor
private static class Response {
private String message;
private String appName;
private int port;
}
@Autowired
public GateWayController(WebClient.Builder webClientBuilder) {
this.webClientBuilder = webClientBuilder;
}
@GetMapping("/lbhello")
public Mono<Response> hello() {
return webClientBuilder.build()
.get()
.uri("lb://hello-service/hello")
.retrieve()
.bodyToMono(Response.class);
}
}
}
spring-cloud-starter-consul-discovery
和 spring-cloud-starter-loadbalancer
作为依赖项包含在 pom.xml
中。在 application.yaml
中,我只设置了 application.name
并禁用了 Ribbon,以便使用 Spring Cloud Loadbalancer。当我启动 GatewayService
和 HelloService
的两个实例时,一切都按预期工作。对 lbhello
端点的服务调用交替委派给两个 HelloService
实例。
当 HelloService
的一个实例停止时,Consul 检测到该实例丢失并将其标记为 critical。因此,我希望负载均衡器至少在一段时间后停止将请求转发到不存在的服务。但这永远不会发生。每隔一个服务调用就被委托给这个服务实例,因此失败。当使用 Eureka 作为发现服务时,注册表会进行调整,只有剩余的 HelloService
被考虑用于服务调用。
这是 Consul 的预期行为吗?如果答案是肯定的,是否有 Spring Cloud 设置来适应这种行为?
解决方法
Spring Cloud ConsulDiscoveryClient
默认加载所有服务实例,无论它们的健康状态如何。可以通过以下配置设置更改此行为:
spring.cloud.consul.discovery.query-passing = true
使用此设置请求不会在一些延迟后委托给非健康实例。