Ribbon是一个客户端的负载均衡器,可以用来控制HTTP和TCP客户端的行为。
Ribbon核心的概念是命名的客户端。每个负载均衡器作为组件团体的一部分,这些组件会按需共同协作去联络一个远程服务端。此外,这个团体通过在@FeignClient注解指定name属性的方式设定一个名字。Spring Cloud为每个命名的客户端通过使用RibbonClientConfiguration的方式创建了一个新的团体,作为一个ApplicationContext。这包含了一个ILoadBalancer,RestTemplate,ServerListFilter。
可以在配置文件中,指定<client>.ribbon.*,对一个Ribbon客户端进行配置。在CommonClientConfigKey这个类中根据需要,寻找对应的属性进行设置。
可以指定一个配置类,作为该Ribbon客户端的配置。
在@RibbonClient注解中指定的自定义的配置类,必须是一个@Configuration类。不要被主应用程序上下文的@ComponentScan注解扫描到,否则会被所有的@RibbonClients所共享。可以将它放到一个独立的、与@ComponentScan扫描的包不重叠的包中。
为所有的Ribbon客户端,提供一个默认的配置,注册它。
从版本1.2.0开始,Spring Cloud Netflix支持自定义Ribbon客户端,通过设置一些属性。
可以对服务名叫做“users”的,进行设置。
users: ribbon: NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule当Eureka和Ribbon组合使用(也就是,两者都在类路径中),ribbonServerList由DiscoveryEnabledNIWSServerList进行重写,其添加了来自Eureka的服务器列表。替换IPing为NIWSDiscoveryPing,委派Eureka判断服务器是否上线。ServerList,默认由一个DomainExtractingServerList设置。这个目的是使元数据对于负载均衡器可用,而没有使用AWS AMI元数据(这个是Netflix所依赖的)。默认,服务器列表使用“zone”信息进行构造(对于远程客户端,设置eureka.instance.metadataMap.zone)。如果这个缺失了,并且有设置approximateZoneFromHostname标识,可以使用服务器主机名的域名作为时区的一个代理。一旦时区信息可用,可以在ServerListFilter中被使用。默认,这个可以被用来定位和客户端相同的时区的服务器,因为默认是一个ZonePreferenceServerListFilter。默认,客户端的时区和远程实例使用相同的方式设置,即使用eureka.instance.metadataMap.zone。
Eureka是一个远程服务发现的便捷的方式,不需要对客户端URL硬编码。如果不想使用Eureka,Ribbon和Feign也能正常工作。假设有一个声明@RibbonClient的"stores",没有使用Eureka(甚至都没有在类路径中)。Ribbon客户端默认使用一个配置过的服务器列表。如下:
stores: ribbon: listOfServers: example.com,google.com设置在Ribbon中关闭Eureka的使用,如下:
ribbon: eureka: enabled: false可以直接使用LoadBalancerClient,如下:
public class MyClass { @Autowired private LoadBalancerClient loadBalancer; public void doStuff() { ServiceInstance instance = loadBalancer.choose("stores"); URI storeUri = URI.create(String.format("https://%s:%s", instance.getHost(), instance.getPort())); // ... doSomething with the URI } }每一个Ribbon命名的客户端,有一个对应的由Spring Cloud维护的子上下文。这个上下文是延迟加载的,直到有请求到命名的客户端时才加载。这个延迟加载的行为可以设置为启动时,就进行加载。如下:
ribbon: eager-load: enabled: true clients: client1, client2, client3如果对zuul.ribbonIsolationStrategy设置为THREAD,线程隔离策略对于Hystrix来说,会用于所有的routes。这种情况下,HystrixThreadPoolKey默认设置为RibbonCommand。也就意味着,对于所有的routes的HystrixCommands会在同一个Hystrix线程池中执行。这个可以通过如下的方式改变:
zuul: threadPool: useSeparateThreadPools: true这种设置,会导致HystrixCommands会在每一个route的Hystrix线程池中执行。这种情况下,默认的HystrixThreadPoolKey和每个route的service ID相同。可以通过如下方式添加一个自定义的前缀:
zuul: threadPool: useSeparateThreadPools: true threadPoolKeyPrefix: zuulgw如果要求IRule实现类,处理一个特殊的路由要求,比如一个“金丝雀测试”,那么在IRule的chosse方法中传递一些信息。
public interface IRule { public Server choose(Object key); }此外,可以通过以下方式,传递一些信息:
RequestContext.getCurrentContext().set(FilterConstants.LOAD_BALANCER_KEY, "canary-test");上面的代码要求在RibbonRoutingFilter执行之前被执行。Zuul的前置过滤器是最佳的方式去做这件事。你可以在其前置过滤器中使用 RequestContext,访问HTTP头和查询参数。所以可以用来设置LOAD_BALANCER_KEY。如果在RequestContext中没有设置LOAD_BALANCER_KEY任何值,那么对于choose方法会传递null作为方法参数。