- 推荐序一
- 推荐序二
- 推荐序三
- 推荐语
- 前言
- 第1章 基础知识
- 第2章 微服务构建:Spring Boot
- 第3章 服务治理:Spring Cloud Eureka
- 第4章 客户端负载均衡:Spring Cloud Ribbon
- 第5章 服务容错保护:Spring Cloud Hystrix
- 第6章 声明式服务调用:Spring Cloud Feign
- 第7章 API网关服务:Spring Cloud Zuul
- 第8章 分布式配置中心:Spring Cloud Config
- 第9章 消息总线:Spring Cloud Bus
- 第10章 消息驱动的微服务:Spring Cloud Stream
- 附录 A Starter POMs
- 后记
配置详解
通过上一节对Spring Cloud Ribbon的源码分析,相信读者对于Ribbon的几个重要接口都已经有所了解。下面,我们将详细介绍Ribbon在使用时的各种配置方式。
自动化配置
由于Ribbon中定义的每一个接口都有多种不同的策略实现,同时这些接口之间又有一定的依赖关系,这使得第一次使用Ribbon的开发者很难上手,不知道如何选择具体的实现策略以及如何组织它们的关系。Spring Cloud Ribbon中的自动化配置恰恰能够解决这样的痛点,在引入Spring Cloud Ribbon的依赖之后,就能够自动化构建下面这些接口的实现。
- IClientConfig:Ribbon 的客户端配置,默认采用 com.netflix.client.config.DefaultClientConfigImpl实现。
- IRule:Ribbon 的负载均衡策略,默认采用 com.netflix.loadbalancer.ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。
- IPing:Ribbon的实例检查策略,默认采用com.netflix.loadbalancer.NoOpPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。
- ServerList<Server>:服务实例清单的维护机制,默认采用 com.netflix.loadbalancer.ConfigurationBasedServerList实现。
- ServerListFilter<Server>:服务实例清单过滤机制,默认采用 org.springframework.cloud.netflix.ribbon.ZonePreferenceServerLis tFilter实现,该策略能够优先过滤出与请求调用方处于同区域的服务实例。
- ILoadBalancer:负载均衡器,默认采用 com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,它具备了区域感知的能力。
上面这些自动化配置内容仅在没有引入Spring Cloud Eureka等服务治理框架时如此,在同时引入Eureka和Ribbon依赖时,自动化配置会有一些不同,后续我们会做详细的介绍。
通过自动化配置的实现,我们可以轻松地实现客户端负载均衡。同时,针对一些个性化需求,我们也可以方便地替换上面的这些默认实现。只需在Spring Boot应用中创建对应的实现实例就能覆盖这些默认的配置实现。比如下面的配置内容,由于创建了 PingUrl实例,所以默认的NoOpPing就不会被创建。
@Configuration
public class MyRibbonConfiguration {
@Bean
public IPing ribbonPing(IClientConfig config){
return new PingUrl();
}
}
另外,也可以通过使用@RibbonClient注解来实现更细粒度的客户端配置,比如下面的代码实现了为hello-service服务使用HelloServiceConfiguration中的配置。
@Configuration
@RibbonClient(name="hello-service",configuration=HelloServiceConfiguration.class)
public class RibbonConfiguration {
}
Camden版本对RibbonClient配置的优化
上面我们介绍了在Brixton版本中对RibbonClient的IPing、IRule等接口实现进行个性化定制的方法,主要通过独立创建一个Configuration类来定义IPing、IRule等接口的具体实现Bean,然后在创建RibbonClient时指定要使用的具体Configuration类来覆盖自动化配置的默认实现。虽然这种方式已经能够实现个性化的定义,但是当有大量这类配置的时候,对于各个 RibbonClient 的指定配置信息都将分散在这些配置类的注解定义中,这使得管理和修改都变得非常不方便。所以,在Camden版本中,Spring Cloud Ribbon对 RibbonClient 定义个性化配置的方法做了进一步优化。可以直接通过<clientName>.ribbon.<key>=<value>的形式进行配置。比如我们要实现与上面例子一样的配置(将hello-service服务客户端的IPing接口实现替换为PingUrl),只需在application.properties配置中增加下面的内容即可:
hello-service.ribbon.NFLoadBalancerPingClassName=com.netflix.loadbalancer.PingUrl
其中 hello-service 为服务名,NFLoadBalancerPingClassName 参数用来指定具体的 IPing 接口实现类。在 Camden 版本中,Spring Cloud Ribbon 新增了一个org.springframework.cloud.netflix.ribbon.PropertiesFactory类来动态地为RibbonClient创建这些接口实现。
public class PropertiesFactory {
@Autowired
private Environment environment;
private Map<Class,String> classToProperty=new HashMap<>();
public PropertiesFactory(){
classToProperty.put(ILoadBalancer.class,"NFLoadBalancerClassName");
classToProperty.put(IPing.class,"NFLoadBalancerPingClassName");
classToProperty.put(IRule.class,"NFLoadBalancerRuleClassName");
classToProperty.put(ServerList.class,"NIWSServerListClassName");
classToProperty.put(ServerListFilter.class,"NIWSServerListFilterClassName");
}
public boolean isSet(Class clazz,String name){
return StringUtils.hasText(getClassName(clazz,name));
}
public String getClassName(Class clazz,String name){
if(this.classToProperty.containsKey(clazz)){
String classNameProperty=this.classToProperty.get(clazz);
String className=environment.getProperty(name+"."+NAMESPACE+"."+classNameProperty);
return className;
}
return null;
}
@SuppressWarnings("unchecked")
public <C> C get(Class<C> clazz,IClientConfig config,String name){
String className=getClassName(clazz,name);
if(StringUtils.hasText(className)){
try {
Class<? > toInstantiate=Class.forName(className);
return(C)instantiateWithConfig(toInstantiate,config);
} catch(ClassNotFoundException e){
throw new IllegalArgumentException("Unknown class to load"+className+" for class "+clazz+" named "+name);
}
}
return null;
}
}
从上述源码定义中可以看到,除了 NFLoadBalancerPingClassName 参数之外,还提供了其他几个接口的动态配置实现,具体如下所述。
- NFLoadBalancerClassName:配置ILoadBalancer接口的实现。
- NFLoadBalancerPingClassName:配置IPing接口的实现。
- NFLoadBalancerRuleClassName:配置IRule接口的实现。
- NIWSServerListClassName:配置ServerList接口的实现。
- NIWSServerListFilterClassName:配置ServerListFilter接口的实现。
所以,在Camden版本中我们可以通过配置的方式,更加方便地为RibbonClient指定ILoadBalancer、IPing、IRule、ServerList和ServerListFilter的定制化实现。
参数配置
对于Ribbon的参数配置通常有两种方式:全局配置以及指定客户端配置。
- 全局配置的方式很简单,只需使用ribbon.<key>=<value>格式进行配置即可。
其中,<key>代表了 Ribbon 客户端配置的参数名,<value>则代表了对应参数的值。比如,我们可以像下面这样全局配置Ribbon创建连接的超时时间:
ribbon.ConnectTimeout=250
全局配置可以作为默认值进行设置,当指定客户端配置了相应key的值时,将覆盖全局配置的内容。
- 指定客户端的配置方式采用<client>.ribbon.<key>=<value>的格式进行配置。其中,<key>和<value>的含义同全局配置相同,而<client>代表了客户端的名称,如上文中我们在@RibbonClient中指定的名称,也可以将它理解为是一个服务名。为了方便理解这种配置方式,我们举一个具体的例子:假设,有一个服务消费者通过RestTemplate来访问hello-service服务的/hello接口,这时我们会这样调用restTemplate.getForEntity("http://helloservice/hello",String.class).getBody();。如果没有服务治理框架的帮助,我们需要为该客户端指定具体的实例清单,可以指定服务名来做详细的配置,具体如下:
hello-service.ribbon.listOfServers=localhost:8001,localhost:8002,localhost:8003
对于Ribbon参数的key以及value类型的定义,可以通过查看com.netflix.client.config.CommonClientConfigKey类获得更为详细的配置内容,在本书中不进行详细介绍。
与Eureka结合
当在Spring Cloud的应用中同时引入Spring Cloud Ribbon和Spring Cloud Eureka依赖时,会触发Eureka中实现的对Ribbon的自动化配置。这时ServerList的维护机制实现将被com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 的实例所覆盖,该实现会将服务清单列表交给Eureka的服务治理机制来进行维护;IPing的实现将被 com.netflix.niws.loadbalancer.NIWSDiscoveryPing 的实例所覆盖,该实现也将实例检查的任务交给了服务治理框架来进行维护。默认情况下,用于获取实例请求的ServerList接口实现将采用Spring Cloud Eureka中封装的org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList,其目的是为了让实例维护策略更加通用,所以将使用物理元数据来进行负载均衡,而不是使用原生的AWS AMI元数据。
在与Spring Cloud Eureka结合使用的时候,我们的配置将会变得更加简单。不再需要通过类似 hello-service.ribbon.listOfServers 的参数来指定具体的服务实例清单,因为Eureka将会为我们维护所有服务的实例清单。而对于Ribbon的参数配置,我们依然可以采用之前的两种配置方式来实现,而指定客户端的配置方式可以直接使用Eureka中的服务名作为<client>来完成针对各个微服务的个性化配置。
此外,由于Spring Cloud Ribbon默认实现了区域亲和策略,所以,我们可以通过Eureka实例的元数据配置来实现区域化的实例配置方案。比如,可以将处于不同机房的实例配置成不同的区域值,以作为跨区域的容错机制实现。而实现的方式非常简单,只需在服务实例的元数据中增加zone参数来指定自己所在的区域,比如:
eureka.instance.metadataMap.zone=shanghai
在Spring Cloud Ribbon与Spring Cloud Eureka结合的工程中,我们也可以通过参数配置的方式来禁用Eureka对Ribbon服务实例的维护实现。只需在配置文件中加入如下参数,这时我们对于服务实例的维护就又将回归到使用<client>.ribbon.listOfServers 参数配置的方式来实现了。
ribbon.eureka.enabled=false
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论