目錄
ClientConfigEnableRoundRobinRule
DiscoveryEnabledNIWSServerList
Ribbon是一個客戶端負載均衡器,可以對HTTP和TCP客戶端的行爲進行大量控制,Feign已經使用了Ribbon,因此,如果使用@FeignClient
,此部分也適用。
Ribbon中的一個核心概念是命名客戶端,每個負載均衡器都是一組組件的一部分,這些組件一起工作以按需聯繫遠程服務器,並且該集合具有你作爲應用程序開發人員提供的名稱(例如,通過使用@FeignClient
註解)。根據需要,Spring Cloud通過使用RibbonClientConfiguration
爲每個命名客戶端創建一個新的集合作爲ApplicationContext
,這包含(除其他外)ILoadBalancer
、RestClient
和ServerListFilter
。
如何引入Ribbon
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
自定義Ribbon客戶端
默認Ribbon採用全局配置獲取服務列表,但是如果不使用服務註冊,則可以自定義。
開發人員可以用<client>.ribbon.*外部配置來開啓Ribbon的功能,這種方式除了使用了Spring Boot 配置文件外,和使用原生的Nexflix APIs沒什麼不同。原生的選項在CommonClientConfigKey的常量中可以看到(是ribbon-core的一部分)。
Spring Cloud還允許你通過使用@RibbonClient
聲明其他配置(在RibbonClientConfiguration
之上)來完全控制客戶端,如以下示例所示:
@Configuration
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class TestConfiguration {
}
CustomConfiguration
類必須是@Configuration
類,但要注意它不在@ComponentScan
中用於主應用程序上下文,否則,它由所有@RibbonClients
共享。如果使用@ComponentScan
(或@SpringBootApplication
),則需要採取措施以避免包含它(例如,你可以將其放在單獨的非重疊包中,或指定要在@ComponentScan
中顯式掃描的包)。
在這種情況下,客戶端由RibbonClientConfiguration
中已有的組件以及CustomConfiguration
(後者通常覆蓋前者)中的任何組件組成。
下表顯示了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 |
|
創建其中一種類型的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
。
負載均衡器的組件
- Rule
決定從server list中返回哪個。
- Ping
運行在後臺,確保server是活的。
- ServerList
可以是靜態的,也可以是動態的。如果是動態的(DynamicServerListLoadBalancer),一個後臺線程會以一定頻率刷新,過濾,得到server列表。
通用規則
RandomRule
com.netflix.loadbalancer.RandomRule,從服務實例清單中隨機選擇一個服務實例,作爲請求服務對象。
#設置一個服務(helloword-service)客戶端的Ribbon配置
helloword-service:
ribbon:
#配置Ribbon能訪問 的微服務節點,多個節點用逗號隔開
listOfServers: localhost:8001,localhost:8002,localhost:8003,localhost:8004,localhost:8005
#配置Ribbon負載均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule;
RoundRobinRule
com.netflix.loadbalancer.RoundRobinRule,按照線性輪詢的方式一次輪詢服務清單上的每個服務實例。
RetryRule
com.netflix.loadbalancer.RetryRule,該策略具備重試機制的實例選擇功能,在給定時間內能夠得到選擇到具體的服務實例就返回,當超過時間還有沒選到就返回null,參數maxRetryMillis控制這個超時時間。
WeightedResponseTimeRule
com.netflix.loadbalancer.WeightedResponseTimeRule,該策略是對RoundRobinRule的擴展,增加了根據實例的響應時間來計算權重,並從權重中選擇對應的實例。該策略實現主要有三個核心內容:
定時任務
初始化的時候會啓動一個定時任務,默認每隔30秒計算一次每個服務實例的權重
權重計算
累計所有實例的響應時間,得到總的totalResponseTime,然後爲實例清單中的每個實例逐個計算權重,計算公式爲
weightSoFar = weightSoFar + totalResponseTime - 該實例的平均響應時間
weightSoFar 起始爲零
示例
有A,B,C,D四個實例,他們的平均響應時間是10,40,80,100,
計算總的響應時間10+40+80+100 =230
計算各個實例的權重
A: 230-10=220
B:220+(230-40)=410
C:410+(230-80)=560
D:560+(230-100)=690;
計算各個實例的權重區間
A:[0,220]
B:(220,410]
C:(410,560]
D:(560,690)
實例選擇
策略會在[0,最大權重值)之間隨機選取一個數,然後在看這個數落在哪個實例的權重區間內,接着就會去選擇該實例。
可以看出,響應時間越短,獲取的權重區間就會越大,隨機數落到的概率就會越大
ClientConfigEnableRoundRobinRule
該策略一般不直接使用,有些高級的策略會繼承該類,完成一些高級的策略,ClientConfigEnableRoundRobinRule策略默認使用RoundRibinRule的線性輪詢機制。
BestAvailableRule
BestAvailableRule策略繼承ClientConfigEnableRoundRobinRule,通過遍歷負載均衡中維護的所有服務實例,會過濾掉故障實例,並找出併發數請求數最小的實例,所以該策略的特性就是選出最空閒的實例。
PredicateBasedRule
PredicateBasedRule策略繼承ClientConfigEnableRoundRobinRule,該策略主要特性是“先過濾,再輪詢”,也就是先過濾掉一些實例,得到過濾後的實例清單,然後輪詢該實例清單,PredicateBasedRule中“過濾”功能沒有實現,需要繼承它的類完成,也就是說不同繼承PredicateBasedRule的類有不同的“過濾特性”。
AvailabilityFilteringRule
AvailabilityFilteringRule策略繼承PredicateBasedRule策略的“先過濾,再輪詢”特性,
AvailabilityFilteringRule策略的過濾特性是
1:是否故障,即斷路器是否生效已斷開
2:實例的併發請求數大於閾值,默認2的32次方減一,該閾值可以通過
<clientName>.<nameSpace>.ActiveConnectionsLimit來設置,只要滿足其中一個那麼就會過濾掉。
ServerList
即席靜態列表(StaticServerList)
通過BaseLoadBalancer.setServersList()方法設置serverlist。
ConfigurationBasedServerList
通過配置文件參數listOfservers,來實現ServerList.多個用逗號分隔。
client-name.ribbon.listOfServers=www.microsoft.com:80,www.yahoo.com:80
DiscoveryEnabledNIWSServerList
通過Eureka的服務發現,實現的ServerList。
myClient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
# the server must register itself with Eureka server with VipAddress "myservice"#vipAddress可以理解爲邏輯上的服務名,比如“USER-SERVICE”,用於eureka通過名稱選擇服務實例。
myClient.ribbon.DeploymentContextBasedVipAddresses=myservice
ServerListFilter
ZoneAffinityServerListFilter
過濾掉所有的不和客戶端在相同zone的服務,如果和客戶端相同的zone不存在,纔不過濾不同zone服務
myclient.ribbon.EnableZoneAffinity=true
ServerListSubsetFilter
在第一個類的基礎上,只返回所有服務的子集。
此過濾器確保客戶端僅看到由ServerList實現返回的整個服務器的固定子集。 它還可以定期用新服務器替代可用性差的子集中的服務器。 如果服務器場很大,這很有用。在成百上千的情況下,使用它們中的每一個,並保持http客戶端連接池中的連接是不必要的。它還可以通過比較總的網絡故障和併發連接來驅逐相對不健康的服務器
要啓用此過濾器,配置如下:
myClient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
# 指定要負載均衡服務實例的服務應用名稱
myClient.ribbon.DeploymentContextBasedVipAddresses=myservice
myClient.ribbon.NIWSServerListFilterClassName=com.netflix.loadbalancer.ServerListSubsetFilter
# 指定返回服務器子集的數量,默認20
myClient.ribbon.ServerListSubsetFilter.size=5
自定義所有Ribbon客戶端的默認值
配置文件
通用格式:ribbon.<key>=<value>
key:表示參數名稱
value:表示參數值
例如:全局配置Ribbon創建連接的超時時間
ribbon.ConnectTimeout=250
註解方式
可以使用@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客戶端。
以下列表顯示了支持的屬性:
<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是服務提供者的名稱
users:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
與Eureka集成
當Eureka與Ribbon一起使用時(即兩者都在classpath上),ribbonServerList
被DiscoveryEnabledNIWSServerList
的擴展覆蓋,從Eureka獲取服務列表,它還用NIWSDiscoveryPing
替換IPing
接口,它委託Eureka確定服務器是否啓動,默認情況下安裝的ServerList
是DomainExtractingServerList
,其目的是在不使用AWS AMI元數據的情況下使負載均衡器可以使用元數據(這是Netflix所依賴的)。默認情況下,服務器列表使用“zone”信息構建,如實例元數據中所提供的(因此,在遠程客戶端上,設置eureka.instance.metadataMap.zone
)。如果缺少該標誌並且設置了approximateZoneFromHostname
標誌,則可以使用服務器主機名中的域名作爲區域的代理,區域信息可用後,可以在ServerListFilter
中使用。默認情況下,它用於在與客戶端相同的區域中查找服務器,因爲默認值爲ZonePreferenceServerListFilter
,默認情況下,客戶端區域的確定方式與遠程實例相同(即通過eureka.instance.metadataMap.zone
)。
不使用Eureka
Eureka是一種抽象遠程服務器發現的便捷方式,因此你無需在客戶端中對其URL進行硬編碼,但是,如果你不想使用Eureka,Ribbon和Feign也可以使用。假設你已爲“stores”聲明瞭@RibbonClient,並且未使用Eureka(甚至在類路徑中也沒有),Ribbon客戶端默認爲已配置的服務器列表,你可以按如下方式提供配置:
application.yml
stores:
ribbon:
listOfServers: example.com,google.com
禁用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”測試,請將一些信息傳遞給IRule
的choose
方法。
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
方法的參數傳遞。
Ribbon屬性
IClientConfig
它主要的作用就是裝載配置信息,用於初始化客戶端和負載均衡器。默認的實現方式是DefaultClientConfigImpl。
public <T> IClientConfig set(IClientConfigKey<T> key, T value);
public <T> T get(IClientConfigKey<T> key, T defaultValue);
DefaultClientConfigImpl
它是通過Archaius加載ClientConfig. 配置參數可以通過配置文件或system properties。也可以通過編程的方式實現IClientConfig的加載。
配置文件的配置參數格式:
<clientName>.<nameSpace>.<propertyName>=<value>
clientName正對某個服務的服務名稱,如:userService。
nameSpace是命名空間,默認是ribbon.
public static final String DEFAULT_NAME_SPACE = "ribbon";
如果沒有clientName,則是對所有的client都有效。
CommonClientConfigKey
CommonClientConfigKey的作用就是定義各種參數以及對應類型。實現特點:自包含定義常量類。
AppName
Version
Port: 7001
SecurePort: 7001
VipAddress
ForceClientPortConfiguration
DeploymentContextBasedVipAddresses
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1
OkToRetryOnAllOperations: false
RequestSpecificRetryOn
ReceiveBufferSize
EnablePrimeConnections: false
PrimeConnectionsClassName: com.netflix.niws.client.http.HttpPrimeConnection
MaxRetriesPerServerPrimeConnection: 9
MaxTotalTimeToPrimeConnections: 30000
MinPrimeConnectionsRatio: 1.0f
PrimeConnectionsURI: /
PoolMaxThreads: 200
PoolMinThreads: 1
PoolKeepAliveTime: 15 * 60
EnableConnectionPool: true
MaxConnectionsPerHost: 50
MaxTotalConnections: 200
IsSecure
GZipPayload
ConnectTimeout: 2000
BackoffTimeout: 0
ReadTimeout: 5000
SendBufferSize
StaleCheckingEnabled: false
Linger: 0
ConnectionManagerTimeout: 2000
FollowRedirects: false
ConnectionPoolCleanerTaskEnabled: true
ConnIdleEvictTimeMilliSeconds: 30*1000
ConnectionCleanerRepeatInterval: 30*1000
EnableGZIPContentEncodingFilter: false
ProxyHost
ProxyPort
KeyStore
KeyStorePassword
TrustStore
TrustStorePassword
IsClientAuthRequired: false
CustomSSLSocketFactoryClassName
IsHostnameValidationRequired
IgnoreUserTokenInConnectionPoolForSecureClient
ClientClassName: com.netflix.niws.client.http.RestClient
InitializeNFLoadBalancer: true
NFLoadBalancerClassName: com.netflix.loadbalancer.ZoneAwareLoadBalancer
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.AvailabilityFilteringRule
NFLoadBalancerPingClassName: com.netflix.loadbalancer.DummyPing
NFLoadBalancerPingInterval
NFLoadBalancerMaxTotalPingTime
NFLoadBalancerStatsClassName: com.netflix.loadbalancer.LoadBalancerStats
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
ServerListUpdaterClassName: com.netflix.loadbalancer.PollingServerListUpdater
NIWSServerListFilterClassName
ServerListRefreshInterval
EnableMarkingServerDownOnReachingFailureLimit
ServerDownFailureLimit
ServerDownStatWindowInMillis
EnableZoneAffinity: false
EnableZoneExclusivity: false
PrioritizeVipAddressBasedServers: true
VipAddressResolverClassName: com.netflix.client.SimpleVipAddressResolver
TargetRegion
RulePredicateClasses
RequestIdHeaderName
UseIPAddrForServer: false
listOfServers:
參考
ribbon官方文檔:
https://github.com/Netflix/archaius
https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers#components-of-load-balancer