前言
在前面的文章中我们分析了SpringCloud 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.ZonePreferenceServerListFilter实现,该策略能够优先过滤出与请求调用方处于同区域的服务实例。ILoadBalancer:负载均衡器,默认采用com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,它具备了区域感知的能力。
通过自动化配置的实现,我们可以轻松地实现客户端负载均衡。如果我们想实现一些个性化需求,也可以替换掉这些默认实现。
代码配置
如果我们想实现个性化配置,可以通过实现自定义的配置来完成,如下:
我们制定配置为CustomLoadBalancer。
1  | 
  | 
其实现如下:
使用了NIWSDiscoveryPing、RandomRule和我们前面文章自写的ParallelPingStrategy策略。
1  | 
  | 
当然,如果我们不需这么多改动,只想改变负载均衡策略。则如下配置即可:
1  | 
  | 
其他也与之类似。
这种配置方式唯一一个缺点是对于集群部署,如果我们想让每个节点的策略不同,需要变更相关代码,当然一般情况下每个节点的策略应是一致的。
配置文件配置
相比代码配置,使用配置文件配置相关参数更加灵活。
我们在org.springframework.cloud.netflix.ribbon.PropertiesFactory这个类里可以看到如下代码:
1  | public class PropertiesFactory {  | 
该类可以动态地为RibbonClient创建接口实现。使用时,我们只需要<clientName>.ribbon.<key>=<value>的形式进行配置即可。
比如上面我们的代码配置,则可以用配置文件进行如下配置:
1  | = com.netflix.niws.loadbalancer.NIWSDiscoveryPing  | 
关于参数配置
对于Ribbon的参数配置通常有两种方式:全局配置及指定客户端配置。
全局配置:全局配置很简单,类如如下形式即可,ribbon.<key>=<value>格式配置即可。
比如,我们全局配置Ribbon创建连接的超时时间。
1
=300
全局配置可以作为默认值使用,当指定客户端配置了相应的key的值时,将覆盖全局配置的内容。
指定客户端配置:采用<client>.ribbon.<key>=<value>的格式进行配置。其中的<client>代表客户端名称,我们可以通过在
@RibbonClient进行指定。比如,我们可以为客户端指定具体的实例清单,如下:
1
=localhost:8001,localhost:8002
在com.netflix.client.config.CommonClientConfigKey类中,我们可以找到Ribbon更为详细的配置参数内容。
我把参数详细信息整理如下,大家可以参考下:
| 配置项 | 类型 | 默认值 | 说明 | 
|---|---|---|---|
| AppName | String | 应用名称 | |
| Version | String | 应用版本号 | |
| Port | Integer | 7001 | 端口号 | 
| SecurePort | Integer | 443 | 安全端口号 | 
| VipAddress | String | 虚拟IP地址 | |
| ForceClientPortConfiguration | Boolean | false | 是否强制使用客户端口号配置 | 
| DeploymentContextBasedVipAddresses | String | ||
| MaxAutoRetries | Integer | 0 | 当前实例连接最大重试次数 | 
| MaxAutoRetriesNextServer | Integer | 1 | 实例连接最大重试次数,超过会换其他实例重试 | 
| OkToRetryOnAllOperations | Boolean | false | 是否对所有请求操作进行重试 | 
| RequestSpecificRetryOn | Boolean | false | 是否对特殊请求进行重试 | 
| ReceiveBufferSize | Integer | 接收到的数据流长度限制 | |
| EnablePrimeConnections | Boolean | false | 启用预连接 (关于预连接请参考下文) | 
| PrimeConnectionsClassName | String | com.netflix.niws.client.http.HttpPrimeConnection | 预连接类名 | 
| MaxRetriesPerServerPrimeConnection | Integer | 9 | 每个server的预连接最大重试次数 | 
| MaxTotalTimeToPrimeConnections | Integer | 30000 | 预连接超时时间 | 
| MinPrimeConnectionsRatio | Float | 1.0f | 预连接最小时间间隔 | 
| PrimeConnectionsURI | String | / | 预连接URI | 
| PoolMaxThreads | Integer | 200 | 连接池内最大可用线程数 | 
| PoolMinThreads | Integer | 1 | 连接池内最小可用线程数 | 
| PoolKeepAliveTime | Integer | 15 * 60L | 连接在池内存活时间,默认15min | 
| PoolKeepAliveTimeUnits | String | SECONDS | 连接在池内存活时间单位 | 
| EnableConnectionPool | Boolean | true | 是否启用连接池 | 
| MaxHttpConnectionsPerHost | Integer | 50 | 已过时,详见MaxConnectionsPerHost | 
| MaxTotalHttpConnections | Integer | 200 | 已过时,详见MaxTotalConnections | 
| MaxConnectionsPerHost | Integer | 50 | 每个主机的最大连接数 | 
| MaxTotalConnections | Integer | 200 | 最大连接总数 | 
| IsSecure | Boolean | false | 是否安全连接 | 
| GZipPayload | Boolean | true | 是否启用GZip传输 | 
| ConnectTimeout | Integer | 2000 | 请求连接超时时间 | 
| BackoffTimeout | Integer | ||
| ReadTimeout | Integer | 5000 | 请求处理超时时间 | 
| SendBufferSize | Integer | 发送的数据最大长度 | |
| StaleCheckingEnabled | Boolean | ||
| Linger | Integer | ||
| ConnectionManagerTimeout | Integer | 2000 | 连接管理器超时时间 | 
| FollowRedirects | Boolean | false | 连接是否自动处理重定向 | 
| ConnectionPoolCleanerTaskEnabled | Boolean | true | 是否启用连接池自动清理任务 | 
| ConnIdleEvictTimeMilliSeconds | Integer | 30000 | 空闲连接存活时间 | 
| ConnectionCleanerRepeatInterval | Integer | 30000 | 连接清理时间间隔 | 
| EnableGZIPContentEncodingFilter | Boolean | false | 是否启用GZIP编码过滤 | 
| ProxyHost | String | 服务代理地址 | |
| ProxyPort | Integer | Integer.MIN_VALUE + 1 | 代理服务端口号,默认值没有实际用途,如果使用需要用户自行设置 | 
| KeyStore | String | ||
| KeyStorePassword | String | ||
| TrustStore | String | ||
| TrustStorePassword | String | ||
| IsClientAuthRequired | Boolean | false | 是否需要客户端安全认证(如果请求需要的话) | 
| CustomSSLSocketFactoryClassName | String | 用户自定义的SSL连接类 | |
| IsHostnameValidationRequired | Boolean | 是否需要校验 | |
| IgnoreUserTokenInConnectionPoolForSecureClient | Boolean | ||
| ClientClassName | String | com.netflix.niws.client.http.RestClient | 请求客户端的实现类 | 
| InitializeNFLoadBalancer | Boolean | true | 是否初始化Ribbon负载均衡器 | 
| NFLoadBalancerClassName | String | com.netflix.loadbalancer.ZoneAwareLoadBalancer | 使用的负载均衡器类名 | 
| NFLoadBalancerRuleClassName | String | com.netflix.loadbalancer.AvailabilityFilteringRule | 负载均衡器的过滤规则 | 
| NFLoadBalancerPingClassName | String | com.netflix.loadbalancer.DummyPing | 负载均衡器的ping规则 | 
| NFLoadBalancerPingInterval | Integer | 30 | ping间隔时间 | 
| NFLoadBalancerMaxTotalPingTime | Integer | 2 | ping的最大次数 | 
| NFLoadBalancerStatsClassName | String | com.netflix.loadbalancer.LoadBalancerStats | 负载均衡状态统计类 | 
| NIWSServerListClassName | String | com.netflix.loadbalancer.ConfigurationBasedServerList | 获取服务列表所使用的类 | 
| ServerListUpdaterClassName | String | com.netflix.loadbalancer.PollingServerListUpdater | 服务列表更新所使用的类 | 
| NIWSServerListFilterClassName | String | com.netflix.loadbalancer.ZoneAffinityServerListFilter | 区域甄别服务列表过滤类名 | 
| ServerListRefreshInterval | Integer | 30 * 1000 ms | 服务列表刷新间隔,单位毫秒 | 
| EnableMarkingServerDownOnReachingFailureLimit | Boolean | ||
| ServerDownFailureLimit | Integer | ||
| ServerDownStatWindowInMillis | Integer | ||
| EnableZoneAffinity | Boolean | false | 是否开启区域甄别 | 
| EnableZoneExclusivity | Boolean | false | 是否开启ZoneAffinity | 
| PrioritizeVipAddressBasedServers | Boolean | true | |
| VipAddressResolverClassName | String | com.netflix.client.SimpleVipAddressResolver | |
| TargetRegion | String | ||
| RulePredicateClasses | String | ||
| RequestIdHeaderName | String | ||
| UseIPAddrForServer | Boolean | false | 是否使用IP地址请求 | 
| listOfServers | String | “” | 为客户端指定具体的实例清单 | 
预连接
对于那些拥有客户端负载均衡,并且知道要链接的服务器集群的客户端,我们可以预先与服务端建立连接,进行“预热”,这样做的好处是对于一些有防火墙的服务应用,请求时可以快速与之建立连接,提高应用体验。
详细信息可以查看 com.netflix.niws.client.http.HttpPrimeConnection 预连接处理类,这儿就不过多介绍了。
其他
关于上面的参数,很多是关于对Ribbon使用的HttpClient的配置,不太了解的可以先了解下HttpClient的一些参数配置等。
参数都遵循<client>.ribbon.<key>=<value>的配置。
比如我们以Ribbon的重试机制来进行举例,Spring Cloud整合了 Spring Retry来增强RestTemplate的重试能力,对于我们只需简单的配置,便可以实现重试功能。
我们在配置文件中添加如下配置信息,其配置信息含义已经说明。
1  | 该参数用来开启重试机制  | 
根据如上配置,当访问到故障请求时,Ribbon会再尝试访问一次当前实例(访问次数取决于MaxAutoRetries),如果不行,就换一个实例进行访问,如果还是不行,再换一次实例访问(更换次数取决于MaxAutoRetriesNextServer),如果依然不行,返回失败。
与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,其目的是为了让实例维护策略更加通用。
由于 Eureka 会为我们维护所有服务实例的清单,因此结合使用的时候,我们无需再配置类似sakura.ribbon.listOfServers的参数来指定服务实例清单。
此外,由于 Spring Cloud Ribbon 默认实现了区域亲和策略,所以我们可以通过 Eureka 实例的元数据配置来实现区域化的实例配置方案。比如,可以将处于不同机房的实例配置成不同的区域值,以作为跨区域的容错机制实现。而实现方式非常简单,只需在服务实例的元数据中增加 zone参数来指定自己所在的区域,比如:
1  | =beijing  | 
在 Spring Cloud Ribbon 和 Spring Cloud Eureka 结合的工程中,我们也可以通过参数配置来禁用 Eureka 对 Ribbon 服务实例的维护实现。只需在配置文件加入如下参数:
1  | =false  | 
禁用后,我们服务实例的维护需要手动指定listOfServers等参数。
总结
以上就是关于 Spring Cloud Ribbon 的一些配置及介绍,实际应用中,我们大多数与 Eureka 结合使用,很多遵循默认配置,真正的开箱即用,但我们也应对它们的配置及原理有所了解,方便我们更好的使用及解决可能出现的一系列问题。

