【问题标题】:Configuring spring-cloud loadbalancer without autoconfiguration在没有自动配置的情况下配置 spring-cloud 负载均衡器
【发布时间】:2021-03-08 17:50:12
【问题描述】:

我已经阅读了整个文档、教程 [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);
    }
}

并使用 bean loadBalancerExchangeFilterFunction 作为:

WebClient.builder()
            .baseUrl("http://service/test-consumer")
            .filter(lbFunction)
            .build();

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

谁能解释一下 serviceId 的作用是什么以及它如何与 DefaultServiceInstance 的集合配对?

(我想了解内部原理,关键组件是什么,它们的目的和相互作用。我主要不是在寻找魔术注释,但实际解释的那个也很好。调试它真的很难,我有好几张带类图的A4,还是一点意义都没有)。

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

问题 2:我如何创建 2 个负载均衡服务并控制将请求转到哪个服务(不是节点)?我需要 2 个单独的网络客户端或一些 url 模式(比如使用 serviceId 代替主机名)吗?如果我需要 2 个网络客户端,如何与 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);
    }
}

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

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

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

原因是DiscoveryClientServiceInstanceListSupplier(ReactiveDiscoveryClient,Environment) 中的this.serviceId = environment.getProperty(PROPERTY_NAME); 评估为null,因此即使我正在寻找一些serviceId,delegate.getInstance 也以null 调用,因此没有找到ServiceInstances。如果我删除了@Bean instanceSupplier,并希望自动配置以某种方式神奇地做到这一点,this.serviceId = environment.getProperty(PROPERTY_NAME); 以某种方式神奇地设置,serviceId 被正确传播,并且它可以工作。对于在配置的 serviceId 以外的其他地方进行的调用,它会说这个 serviceId 不知道,而不是进行调用。

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

【问题讨论】:

  • 在使用自动配置的负载均衡器时,serviceId 被用作从 servicediscovery 中获取信息的键。您已经配置了一个静态ServiceInstanceListSupplier,主要用于测试。如果您将DiscoveryClientServiceInstanceListSupplierSimpleDiscoveryClient github.com/spring-cloud/spring-cloud-commons/issues/… 结合使用,则servicId 将再次用作实例的键。大部分自动配置已完成,因此可以使用 spring bean 为每个 serviceid 配置不同的行为。
  • 好的,这清除了通过属性文件配置 ServiceInstances 的黑点。谢谢!所以说我做了你建议的改变。 ReactorLoadBalancerExchangeFilterFunction 如何知道要从 DiscoveryClientServiceInstanceListSupplier 加载什么 serviceId?配对是如何完成的?是否基于 hostname-from-original-uri == serviceId?
  • 是的,是主机名。
  • 我已尝试根据您的建议调整代码,但似乎不起作用。 — 好吧,我真的在猜测正确的配置会是什么样子,因为我无法在任何地方找到任何完整的示例;任何教程,文档,任何东西。您可以显示完整配置或提供指向显示它的任何位置的链接吗?我将尝试继续调试 spring-cloud 内部以找出发生了什么,但那里非常复杂,所以我不希望成功。
  • ... this.serviceId = environment.getProperty(PROPERTY_NAME); in DiscoveryClientServiceInstanceListSupplier(ReactiveDiscoveryClient,Environment) 评估为 null,因此即使我正在寻找一些 serviceId,delegate.getInstance 也被称为 null。所以看来DiscoveryClientServiceInstanceListSupplier也和单个serviceId有关。所以必须缺少一些设置这个环境变量的东西。非常令人费解

标签: spring-cloud


【解决方案1】:

LoadBalancer 配置不应在 @Configuration-annotated 类中;相反,它应该是通过@LoadBalancerClient@LoadBalancerClients 注释传递给配置的类,如here 所述。

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

所以你的 LoadBalancer 配置类看起来像这样(没有@Configuration):

public class AppConfig {

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

}

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

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

【讨论】:

    【解决方案2】:

    最后,能够通过以下配置解决此问题。不知道为什么它只适用于非阻塞方法以及当我们通过新的 RestTemplate 时

    @Bean
        public ServiceInstanceListSupplier instanceSupplier(ConfigurableApplicationContext context) {
            return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withBlockingHealthChecks(new RestTemplate())//this change
                    .build(context);
        } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-26
      • 2018-11-05
      • 2011-12-29
      • 2019-01-09
      • 1970-01-01
      • 2018-02-28
      • 2022-01-23
      • 2012-12-24
      相关资源
      最近更新 更多