Spring ribbon

目錄

如何引入Ribbon

自定義Ribbon客戶端

負載均衡器的組件

通用規則

RandomRule

RoundRobinRule

RetryRule

WeightedResponseTimeRule

ClientConfigEnableRoundRobinRule

BestAvailableRule

PredicateBasedRule

AvailabilityFilteringRule

ServerList

即席靜態列表(StaticServerList)

ConfigurationBasedServerList

DiscoveryEnabledNIWSServerList

ServerListFilter

ZoneAffinityServerListFilter

ServerListSubsetFilter

自定義所有Ribbon客戶端的默認值

配置文件

註解方式

通過設置屬性自定義Ribbon客戶端

與Eureka集成

不使用Eureka

禁用Eureka

直接使用Ribbon API

Ribbon配置的緩存

如何配置Hystrix線程池

如何爲Ribbon的IRule提供一個鍵

Ribbon屬性

IClientConfig

DefaultClientConfigImpl

CommonClientConfigKey

參考


Ribbon是一個客戶端負載均衡器,可以對HTTP和TCP客戶端的行爲進行大量控制,Feign已經使用了Ribbon,因此,如果使用@FeignClient,此部分也適用。

Ribbon中的一個核心概念是命名客戶端,每個負載均衡器都是一組組件的一部分,這些組件一起工作以按需聯繫遠程服務器,並且該集合具有你作爲應用程序開發人員提供的名稱(例如,通過使用@FeignClient註解)。根據需要,Spring Cloud通過使用RibbonClientConfiguration爲每個命名客戶端創建一個新的集合作爲ApplicationContext,這包含(除其他外)ILoadBalancerRestClientServerListFilter

 

如何引入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

PollingServerListUpdater

 

創建其中一種類型的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上),ribbonServerListDiscoveryEnabledNIWSServerList的擴展覆蓋,從Eureka獲取服務列表,它還用NIWSDiscoveryPing替換IPing接口,它委託Eureka確定服務器是否啓動,默認情況下安裝的ServerListDomainExtractingServerList,其目的是在不使用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”測試,請將一些信息傳遞給IRulechoose方法。

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://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.2.2.RELEASE/reference/html/#spring-cloud-ribbon

https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers#components-of-load-balancer

https://github.com/Netflix/ribbon/blob/master/ribbon-core/src/main/java/com/netflix/client/config/CommonClientConfigKey.java

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章