在没有自动配置的情况下配置 spring-cloud 负载均衡器

Mar*_*cha 7 spring-cloud

我已经阅读了整个文档、教程 [1],并在源代码中花费了几个小时,但我仍然不明白如何配置负载均衡器,特别是如果我不使用魔术注释的话。

我有以下配置:

@Configuration
public class AppConfig {

    public static final String SERVICE_ID = "service";

    @Primary
    @Bean
    public ServiceInstanceListSupplier serviceInstanceListSupplier() {
        return ServiceInstanceListSuppliers.from(SERVICE_ID,
                new DefaultServiceInstance(SERVICE_ID + "1", SERVICE_ID, "localhost", 8886, false),
                new DefaultServiceInstance(SERVICE_ID + "2", SERVICE_ID, "localhost", 8887, false));
    }

    @Bean
    public LoadBalancerClientFactory loadBalancerClientFactory() {
        return new LoadBalancerClientFactory();
    }

    @Bean
    public ReactorLoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(LoadBalancerProperties properties) {
        return new ReactorLoadBalancerExchangeFilterFunction(loadBalancerClientFactory(), properties);
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用 beanloadBalancerExchangeFilterFunction作为:

WebClient.builder()
            .baseUrl("http://service/test-consumer")
            .filter(lbFunction)
            .build();
Run Code Online (Sandbox Code Playgroud)

它有效。问题是,无论我使用什么主机名,它都可以工作。因此,如果我将主机名“service”替换为我喜欢的任何工作,我仍将向 localhost:8886 或 localhost:8887 发送数据。

有人可以解释一下 serviceId 的作用是什么以及它如何与 DefaultServiceInstance 集合配对吗?

(我想了解内部结构,关键组件是什么,它们的用途和相互作用。我主要不是在寻找魔法注释,但实际解释的也很棒。调试它真的很难,我有几个 A4与类图,它仍然没有任何意义)。

问题:是否存在配置错误?serviceId 的用途是什么?似乎没有,因为 Web 客户端使用ReactorLoadBalancerExchangeFilterFunction将在配置的 ServiceInstances 上创建循环负载均衡器,无论给定 Web 客户端中使用的实际主机名是什么。

问题2:我如何创建2个负载平衡服务并控制将请求发送到哪个服务(而不是节点)?我是否需要 2 个独立的 Web 客户端或某种 url 模式(例如使用 serviceId 代替主机名)?如果我需要 2 个 Web 客户端,如何与 DefaultServiceInstance 配对?

[1] https://spring.io/guides/gs/spring-cloud-loadbalancer/


编辑:

建议更新后,配置如下所示:

@Configuration
public class AppConfig {

    @Bean
    public ServiceInstanceListSupplier instanceSupplier(ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                .withDiscoveryClient()
                .withHealthChecks()
                .build(context);
    }

    @Bean
    public LoadBalancerClientFactory loadBalancerClientFactory() {
        return new LoadBalancerClientFactory();
    }

    @Bean
    public ReactorLoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(LoadBalancerProperties properties) {
        return new ReactorLoadBalancerExchangeFilterFunction(loadBalancerClientFactory(), properties);
    }
}
Run Code Online (Sandbox Code Playgroud)

application.properties 包含:

spring.cloud.discovery.client.simple.instances.complicated[0].uri=http://localhost:8886
spring.cloud.discovery.client.simple.instances.complicated[1].uri=http://localhost:8887
Run Code Online (Sandbox Code Playgroud)

Webclient 调用 URL:(http://localhost:8888/test-consumer即主机名与 serviceID 不匹配)会产生:

o.s.c.l.core.RoundRobinLoadBalancer      : No servers available for service: localhost
eactorLoadBalancerExchangeFilterFunction : LoadBalancer does not contain an instance for the service localhost
Run Code Online (Sandbox Code Playgroud)

Webclient 调用 URL:(http://complicated/test-consumer即主机名匹配 serviceID)会产生:

o.s.c.l.core.RoundRobinLoadBalancer      : No servers available for service: complicated
eactorLoadBalancerExchangeFilterFunction : LoadBalancer does not contain an instance for the service complicated
Run Code Online (Sandbox Code Playgroud)

原因是this.serviceId = environment.getProperty(PROPERTY_NAME);inDiscoveryClientServiceInstanceListSupplier(ReactiveDiscoveryClient,Environment)计算结果为 null,因此即使我正在寻找某个 serviceId,delegate.getInstance也会使用 null 调用,因此找不到 ServiceInstances。如果我删除了 @Bean instanceSupplier,并希望自动配置以某种方式神奇地完成,那么它this.serviceId = environment.getProperty(PROPERTY_NAME);会以某种方式神奇地设置,serviceId 会正确传播,并且它可以工作。对于在配置的 serviceId 之外的其他地方进行的调用,它会失败说该 serviceId 不知道,而不是进行调用。

所以这确实意味着,如果我配置负载均衡器,除了(自动)配置的服务之外我无法调用其他任何东西???

Olg*_*zek 2

LoadBalancer 配置不应该位于@Configuration-annotated 类中;@LoadBalancerClient相反,它应该是通过或注释传递配置的类@LoadBalancerClients,如此处所述

另外,您需要实例化的唯一 bean 是ServiceInstanceListSupplier(如果您添加spring-cloud-starter-loadbalancer、 、LoadBalancerClientFactory,并且ReactorLoadBalancerExchangeFilterFunction将由启动器实例化)。

因此,您的 LoadBalancer 配置类将如下所示(不带@Configuration):

public class AppConfig {

    @Bean
    public ServiceInstanceListSupplier instanceSupplier(ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                .withDiscoveryClient()
                .withHealthChecks()
                .build(context);
    }

}
Run Code Online (Sandbox Code Playgroud)

并且您的实际@Configuration类(例如,配置其他与 webflux 相关的 bean 的位置)将具有以下注释:@LoadBalancerClients(defaultConfiguration = AppConfig.class)

然后,如果您在实例中启用运行状况检查complicated,它应该可以正常工作。