Ribbon是一個客戶端負載均衡器,可讓你對HTTP和TCP客戶端的行爲進行大量控制,Feign已經使用了Ribbon,所以,若是你使用@FeignClient
,此部分也適用。java
Ribbon中的一個核心概念是命名客戶端,每一個負載均衡器都是一組組件的一部分,這些組件一塊兒工做以按需聯繫遠程服務器,而且該集合具備你做爲應用程序開發人員提供的名稱(例如,經過使用@FeignClient
註解)。根據須要,Spring Cloud經過使用RibbonClientConfiguration
爲每一個命名客戶端建立一個新的集合做爲ApplicationContext
,這包含(除其餘外)ILoadBalancer
、RestClient
和ServerListFilter
。git
要在項目中包含Ribbon,使用組ID爲org.springframework.cloud
和工件ID爲spring-cloud-starter-netflix-ribbon
。github
你可使用<client>.ribbon.*
中的外部屬性配置Ribbon客戶端的某些,這相似於使用原生Netflix API,但你可使用Spring Boot配置文件,能夠在CommonClientConfigKey(ribbon-core的一部分)中將原生選項做爲靜態字段進行檢查。spring
Spring Cloud還容許你經過使用@RibbonClient
聲明其餘配置(在RibbonClientConfiguration
之上)來徹底控制客戶端,如如下示例所示:segmentfault
@Configuration @RibbonClient(name = "custom", configuration = CustomConfiguration.class) public class TestConfiguration { }
在這種狀況下,客戶端由RibbonClientConfiguration
中已有的組件以及CustomConfiguration
(後者一般覆蓋前者)中的任何組件組成。緩存
CustomConfiguration
類必須是@Configuration
類,但要注意它不在@ComponentScan
中用於主應用程序上下文,不然,它由全部@RibbonClients
共享。若是使用@ComponentScan
(或@SpringBootApplication
),則須要採起措施以免包含它(例如,你能夠將其放在單獨的非重疊包中,或指定要在@ComponentScan
中顯式掃描的包)。
下表顯示了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 |
PollingServerListUpdater |
建立其中一種類型的bean並將其置於@RibbonClient
配置(例以下面的FooConfiguration
)中,能夠覆蓋所描述的每一個bean,如如下示例所示:app
@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
。負載均衡
可使用@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; } }
從版本1.2.0開始,Spring Cloud Netflix如今支持經過將屬性設置爲與Ribbon文檔兼容來自定義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: ribbon: NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
有關Ribbon提供的實現,請參閱Ribbon文檔。
當Eureka與Ribbon一塊兒使用時(即二者都在類路徑上),ribbonServerList
被DiscoveryEnabledNIWSServerList
的擴展覆蓋,該擴展填充Eureka的服務器列表,它還用NIWSDiscoveryPing
替換IPing
接口,它委託Eureka肯定服務器是否啓動,默認狀況下安裝的ServerList
是DomainExtractingServerList
,其目的是在不使用AWS AMI元數據的狀況下使負載均衡器可使用元數據(這是Netflix所依賴的)。默認狀況下,服務器列表使用「zone」信息構建,如實例元數據中所提供的(所以,在遠程客戶端上,設置eureka.instance.metadataMap.zone
)。若是缺乏該標誌而且設置了approximateZoneFromHostname
標誌,則可使用服務器主機名中的域名做爲區域的代理,區域信息可用後,能夠在ServerListFilter
中使用。默認狀況下,它用於在與客戶端相同的區域中查找服務器,由於默認值爲ZonePreferenceServerListFilter
,默認狀況下,客戶端區域的肯定方式與遠程實例相同(即經過eureka.instance.metadataMap.zone
)。
設置客戶端區域的傳統「archaius」方法是經過名爲「@zone」的配置屬性,若是可用,Spring Cloud優先於全部其餘設置使用它(請注意,必須在YAML配置中引用該鍵)。
若是沒有其餘區域數據源,則根據客戶端配置進行猜想(與實例配置相反),獲取eureka.client.availabilityZones
,它是從region名稱到zone列表的映射,併爲實例本身的region 拉出第一個zone(即eureka.client.region
,默認爲「us-east-1」,以便與原生Netflix兼容)。
Eureka是一種抽象遠程服務器發現的便捷方式,所以你無需在客戶端中對其URL進行硬編碼,可是,若是你不想使用Eureka,Ribbon和Feign也可使用。假設你已爲「stores」聲明瞭@RibbonClient
,而且未使用Eureka(甚至在類路徑中也沒有),Ribbon客戶端默認爲已配置的服務器列表,你能夠按以下方式提供配置:
application.yml
stores: ribbon: listOfServers: example.com,google.com
將ribbon.eureka.enabled
屬性設置爲false
會顯式禁用在Ribbon中使用Eureka,如如下示例所示:
application.yml
ribbon: eureka: enabled: false
你也能夠直接使用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命名客戶端都有一個Spring Cloud維護的相應子應用程序上下文,在對命名客戶端的第一次請求上延遲加載此應用程序上下文,經過指定Ribbon客戶端的名稱,能夠將此延遲加載行爲更改成在啓動時急切地加載這些子應用程序上下文,如如下示例所示:
application.yml
ribbon: eager-load: enabled: true clients: client1, client2, client3
若是將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
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
方法的參數傳遞。