Spring-Cloud-参考文档客户端负载均衡器Ribbon

6次阅读

共计 6245 个字符,预计需要花费 16 分钟才能阅读完成。

客户端负载均衡器:Ribbon

Ribbon 是一个客户端负载均衡器,可以让你对 HTTP 和 TCP 客户端的行为进行大量控制,Feign 已经使用了 Ribbon,因此,如果你使用@FeignClient,此部分也适用。

Ribbon 中的一个核心概念是命名客户端,每个负载均衡器都是一组组件的一部分,这些组件一起工作以按需联系远程服务器,并且该集合具有你作为应用程序开发人员提供的名称(例如,通过使用 @FeignClient 注解)。根据需要,Spring Cloud 通过使用 RibbonClientConfiguration 为每个命名客户端创建一个新的集合作为 ApplicationContext,这包含(除其他外)ILoadBalancerRestClientServerListFilter

如何包含 Ribbon

要在项目中包含 Ribbon,使用组 ID 为 org.springframework.cloud 和工件 ID 为spring-cloud-starter-netflix-ribbon

自定义 Ribbon 客户端

你可以使用 <client>.ribbon.* 中的外部属性配置 Ribbon 客户端的某些,这类似于使用原生 Netflix API,但你可以使用 Spring Boot 配置文件,可以在 CommonClientConfigKey(ribbon-core 的一部分)中将原生选项作为静态字段进行检查。

Spring Cloud 还允许你通过使用 @RibbonClient 声明其他配置(在 RibbonClientConfiguration 之上)来完全控制客户端,如以下示例所示:

@Configuration
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class TestConfiguration {}

在这种情况下,客户端由 RibbonClientConfiguration 中已有的组件以及CustomConfiguration(后者通常覆盖前者)中的任何组件组成。

CustomConfiguration类必须是 @Configuration 类,但要注意它不在 @ComponentScan 中用于主应用程序上下文,否则,它由所有 @RibbonClients 共享。如果使用 @ComponentScan(或@SpringBootApplication),则需要采取措施以避免包含它(例如,你可以将其放在单独的非重叠包中,或指定要在@ComponentScan 中显式扫描的包)。

下表显示了 Spring Cloud Netflix 默认为 Ribbon 提供的 bean:

Bean 类型 Bean 名称 类名称
IClientConfig ribbonClientConfig DefaultClientConfigImpl
IRule ribbonRule ZoneAvoidanceRule
IPing ribbonPing DummyPing
ServerList<Server> ribbonServerList ConfigurationBasedServerList
ServerListFilter<Server> ribbonServerListFilter ZonePreferenceServerListFilter
ILoadBalancer ribbonLoadBalancer ZoneAwareLoadBalancer
ServerListUpdater ribbonServerListUpdater PollingServerListUpdater

创建其中一种类型的 bean 并将其置于 @RibbonClient 配置(例如下面的FooConfiguration)中,可以覆盖所描述的每个 bean,如以下示例所示:

@Configuration
protected static class FooConfiguration {
    @Bean
    public ZonePreferenceServerListFilter serverListFilter() {ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
        filter.setZone("myTestZone");
        return filter;
    }

    @Bean
    public IPing ribbonPing() {return new PingUrl();
    }
}

前面示例中的语句将 NoOpPing 替换为PingUrl,并提供自定义serverListFilter

自定义所有 Ribbon 客户端的默认值

可以使用 @RibbonClients 注解并注册默认配置为所有 Ribbon 客户端提供默认配置,如以下示例所示:

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig {

    public static class BazServiceList extends ConfigurationBasedServerList {public BazServiceList(IClientConfig config) {super.initWithNiwsConfig(config);
        }
    }
}

@Configuration
class DefaultRibbonConfig {

    @Bean
    public IRule ribbonRule() {return new BestAvailableRule();
    }

    @Bean
    public IPing ribbonPing() {return new PingUrl();
    }

    @Bean
    public ServerList<Server> ribbonServerList(IClientConfig config) {return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
    }

    @Bean
    public ServerListSubsetFilter serverListFilter() {ServerListSubsetFilter filter = new ServerListSubsetFilter();
        return filter;
    }

}

通过设置属性自定义 Ribbon 客户端

从版本 1.2.0 开始,Spring Cloud Netflix 现在支持通过将属性设置为与 Ribbon 文档兼容来自定义 Ribbon 客户端。

这使你可以在不同环境中启动时更改行为。

以下列表显示了支持的属性:

  • <clientName>.ribbon.NFLoadBalancerClassName:应该实现ILoadBalancer
  • <clientName>.ribbon.NFLoadBalancerRuleClassName:应该实现IRule
  • <clientName>.ribbon.NFLoadBalancerPingClassName:应该实现IPing
  • <clientName>.ribbon.NIWSServerListClassName:应该实现ServerList
  • <clientName>.ribbon.NIWSServerListFilterClassName:应该实现ServerListFilter

这些属性中定义的类优先于使用 @RibbonClient(configuration=MyRibbonConfig.class) 定义的 bean 以及 Spring Cloud Netflix 提供的默认值。

要为名为 users 的服务名称设置IRule,你可以设置以下属性:

application.yml

users:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

有关 Ribbon 提供的实现,请参阅 Ribbon 文档。

使用 Ribbon 与 Eureka

当 Eureka 与 Ribbon 一起使用时(即两者都在类路径上),ribbonServerListDiscoveryEnabledNIWSServerList 的扩展覆盖,该扩展填充 Eureka 的服务器列表,它还用 NIWSDiscoveryPing 替换 IPing 接口,它委托 Eureka 确定服务器是否启动,默认情况下安装的 ServerListDomainExtractingServerList,其目的是在不使用 AWS AMI 元数据的情况下使负载均衡器可以使用元数据(这是 Netflix 所依赖的)。默认情况下,服务器列表使用“zone”信息构建,如实例元数据中所提供的(因此,在远程客户端上,设置 eureka.instance.metadataMap.zone)。如果缺少该标志并且设置了approximateZoneFromHostname 标志,则可以使用服务器主机名中的域名作为区域的代理,区域信息可用后,可以在 ServerListFilter 中使用。默认情况下,它用于在与客户端相同的区域中查找服务器,因为默认值为ZonePreferenceServerListFilter,默认情况下,客户端区域的确定方式与远程实例相同(即通过eureka.instance.metadataMap.zone)。

设置客户端区域的传统“archaius”方法是通过名为“@zone”的配置属性,如果可用,Spring Cloud 优先于所有其他设置使用它(请注意,必须在 YAML 配置中引用该键)。

如果没有其他区域数据源,则根据客户端配置进行猜测(与实例配置相反),获取eureka.client.availabilityZones,它是从 region 名称到 zone 列表的映射,并为实例自己的 region 拉出第一个 zone(即eureka.client.region,默认为“us-east-1”,以便与原生 Netflix 兼容)。

示例:如何在没有 Eureka 的情况下使用 Ribbon

Eureka 是一种抽象远程服务器发现的便捷方式,因此你无需在客户端中对其 URL 进行硬编码,但是,如果你不想使用 Eureka,Ribbon 和 Feign 也可以使用。假设你已为“stores”声明了@RibbonClient,并且未使用 Eureka(甚至在类路径中也没有),Ribbon 客户端默认为已配置的服务器列表,你可以按如下方式提供配置:

application.yml

stores:
  ribbon:
    listOfServers: example.com,google.com

示例:禁用在 Ribbon 中使用 Eureka

ribbon.eureka.enabled 属性设置为 false 会显式禁用在 Ribbon 中使用 Eureka,如以下示例所示:

application.yml

ribbon:
  eureka:
   enabled: false

直接使用 Ribbon API

你也可以直接使用LoadBalancerClient,如以下示例所示:

public class MyClass {
    @Autowired
    private LoadBalancerClient loadBalancer;

    public void doStuff() {ServiceInstance instance = loadBalancer.choose("stores");
        URI storesUri = URI.create(String.format("http://%s:%s", instance.getHost(), instance.getPort()));
        // ... do something with the URI
    }
}

Ribbon 配置的缓存

每个 Ribbon 命名客户端都有一个 Spring Cloud 维护的相应子应用程序上下文,在对命名客户端的第一次请求上延迟加载此应用程序上下文,通过指定 Ribbon 客户端的名称,可以将此延迟加载行为更改为在启动时急切地加载这些子应用程序上下文,如以下示例所示:

application.yml

ribbon:
  eager-load:
    enabled: true
    clients: client1, client2, client3

如何配置 Hystrix 线程池

如果将 zuul.ribbonIsolationStrategy 更改为 THREAD,则 Hystrix 的线程隔离策略将用于所有路由,在这种情况下,HystrixThreadPoolKey 设置为 RibbonCommand 作为默认值,这意味着所有路由的 HystrixCommands 都在同一个 Hystrix 线程池中执行,可以使用以下配置更改此行为:

application.yml

zuul:
  threadPool:
    useSeparateThreadPools: true

前面的示例导致每个路由都在 Hystrix 线程池中执行 HystrixCommands。

在这种情况下,默认 HystrixThreadPoolKey 与每个路由的服务 ID 相同,要向 HystrixThreadPoolKey 添加前缀,请将 zuul.threadPool.threadPoolKeyPrefix 设置为要添加的值,如以下示例所示:

application.yml

zuul:
  threadPool:
    useSeparateThreadPools: true
    threadPoolKeyPrefix: zuulgw

如何为 Ribbon 的 IRule 提供一个键

如果你需要提供自己的 IRule 实现来处理特殊的路由要求,如“canary”测试,请将一些信息传递给 IRulechoose方法。

com.netflix.loadbalancer.IRule.java

public interface IRule{public Server choose(Object key);
         :

你可以提供 IRule 实现用于选择目标服务器的一些信息,如以下示例所示:

RequestContext.getCurrentContext()
              .set(FilterConstants.LOAD_BALANCER_KEY, "canary-test");

如果使用 FilterConstants.LOAD_BALANCER_KEY 的键将任何对象放入 RequestContext,则会将其传递给IRule 实现的 choose 方法,必须在执行 RibbonRoutingFilter 之前执行前面示例中显示的代码,Zuul 的预过滤器是最好的选择。你可以通过预过滤器中的 RequestContext 访问 HTTP headers 和查询参数,因此可以用它来确定传递给 Ribbon 的 LOAD_BALANCER_KEY,如果未在RequestContext 中为 LOAD_BALANCER_KEY 设置任何值,则将 null 作为 choose 方法的参数传递。


上一篇:Hystrix 超时和 Ribbon 客户端

下一篇:外部配置:Archaius

正文完
 0