前言
在前面的文章中我们分析了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 结合使用,很多遵循默认配置,真正的开箱即用,但我们也应对它们的配置及原理有所了解,方便我们更好的使用及解决可能出现的一系列问题。