ribbon原理+源碼解析

1 總體流程圖

image.png

核心:
(1)@balance,最終讓template 加一層filter,作負載均衡。
(2)負載均衡用的serverlist,來自spring容器環境,一個server一個容器。
(3)定時任務更新serverlist,ping任務更新server的狀態。
(4)chooseServer的rule,ping組件都支持擴展。算法

2 ribbon 自動裝配-LoadBalanceAutoConfiguration

image.png
(1)@balance 實際上是個類註解,至關於標籤,核心是加了@qualify,注入的時候 @balance+@autowired 配合list,能夠獲得全部加@balance註解的bean,就是獲得List<Template>。
(2)生成LoadBalanceInterceptor組件bean,做爲攔截器,核心是loadBalanceClient;生成RestTemplateCutomizer組件bean,用來裝配interceptor
(3)核心SmartInitialzingSingleton組件bean,調用RestTemplateCutomizer,把interceptor放到每一個template中spring

interceptor原理:使用loadBalanceClient,利用irule規則,從servers中挑選實現負載均衡,用requestFactory建立request,向server發請求。springboot

3 loadBalanceClient 原理

在spring-cloud-netflix-ribbon裏,找到了LoadBalanceClient類,經過RibbonAutoConfiguration 自動配置。併發

(1)RibbonAutoConfiguration,負載均衡

@AutoConfigureBefore({ LoadBalancerAutoConfiguration.class,  在這個以前,說明是template收集和加入攔截以前要自動配置,說明攔截和收集要用到它,須要先初始化loadbalanceclient。dom

@AutoConfigureAfter(
        name = "[org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration](http://org.springframework.cloud.netflix.eureka.eurekaclientautoconfiguration/)」)

在eureka-client註冊以後配置,說明要用eureka的註冊表。
在這個配置類裏,完成了LoadBalancerClient的@bean初始化。ide

(2)excute過程,先拿ILoadBalance -> getLoadBalancer(serviceId);atom

本質上是從SpringClientFactory中,根據serviceId, 獲得對應的AnnotationConfigApplicationContext,而後從這個環境中拿到這個service對應的ILoadBalancer。spa

問題:爲何要用Spring的容器?AnnotationConfigApplicationContext? 由於區分環境後,在後面注入serverlist的時候,直接經過@bean在參數裏注入便可,不須要用serviceid判斷。.net

(3)ILoadBalance的本質,

RibbonClientConfiguration中完成初始化,核心是
new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,serverListFilter, serverListUpdater);
融合了irule組件,ping組件,serverlist,serverupdate,還執行了個restOfInit方法感知eureka。

(4)loadBlance感知eureka

 a 接上面的restOfInit,參數裏有個serverlist,是經過bean傳遞進來,頗有迷惑性,本類的那個bean不是。實際是在EurekaRibbonClientConfiguration的ribbonServerList,注入到了serverListImpl,

 b 本質是restOfInit,  updateListOfServers( ) -> servers = serverListImpl.getUpdatedListOfServers();調用了obtainServersViaDiscovery,從eurekaClientProvider 獲得了eureka-client,從而獲得了serverlist,存到iloadbalance本地。

(5)獲取eureka後的更新serverlist。
仍是restOfInit(),裏面啓動線程定時更新(30s),enableAndInitLearnNewServersFeature 調用 serverListUpdater.start(updateAction);開啓線程。

(6)ping各個server
ping組件也是能夠擴展本身寫的,不擴展來自於EurekaRibbonClientConfiguration的NIWSDiscoveryPing,isAlive()方法,就是傳入server,檢查狀態是不是InstanceStatus.UP狀態。

在zoneLoadBalance的父類 baseLoadBalance的實例化裏,initWithConfig ->setPingInterval ,啓動了ping線程,runPinger中調用server的isAlive()方法,默認30s一次。返回false的時候,就放到changelist裏,返回true的收集起來做新的serverlist。

(7)excute繼續,getServer(),實際上是根據irule獲得具體某個server,irule好比用atomicLong,遞增取模。

總體過程 ,獲得IloadBalance->根據irule 算出server->執行excute

4 負載均衡算法種類

RandomRule:隨機選取負載均衡策略。
RoundRobinRule:輪詢負載均衡策略。
WeightedResponseTimeRule:根據平均響應時間計算全部服務的權重,時間越短權重越大。剛啓動時,若是統計信息不足,則使用線性輪詢策略,等信息足夠時,再切換到WeightedResponseTimeRule。
RetryRule:使用線性輪詢策略獲取服務,若是獲取失敗則在指定時間內重試,從新獲取可用服務。
BestAvailableRule:繼承自ClientConfigEnabledRoundRobinRule。從全部沒有斷開的服務中,選取到目前爲止請求數量最小的服務。
ClientConfigEnabledRoundRobinRule:默認經過線性輪詢策略選取服務。經過繼承該類,而且對choose方法進行重寫,能夠實現更多的策略,繼承後保底使用RoundRobinRule策略。
AvailabilityFilteringRule:按可用性進行過濾,會先過濾掉因爲屢次訪問故障而處於斷路器跳閘狀態的服務,還有併發的鏈接數超過閾值的服務,而後對剩餘的服務列表進行線性輪詢。
ZoneAvoidanceRule:自己沒有重寫choose方法,用的仍是抽象父類PredicateBasedRule的choose。~~~~

5 負載均衡算法使用

(1)正常全局策略

@Configuration
public class LoadBalanced {
    @Bean
    public IRule iRule() {
        return new RandomRule();
    }
}

irule能夠換本身的

(2)指定均衡策略

能夠註解配置 @RibbonClient(name = "service1", configuration = cn.wbnull.springbootconsumer.config.LoadBalanced.class)

文件配置

service1:
  ribbon:
    NFLoadBalancerRuleClassName: cn.wbnull.springbootconsumer.config.loadbalancer.GlobalRule
相關文章
相關標籤/搜索