天天看點

Spring Cloud教程 第二彈 用戶端負載均衡Ribbon

更多Spring與微服務相關的教程請戳這裡 Spring與微服務教程合集

1、淺談負載均衡

負載均衡(Load Balance),是利用特定方式将流量分攤到多個操作單元上的一種手段。這個應該大家耳熟能詳了!

負載均衡的分類:

硬負載:即利用硬體進行負載均衡處理,如F5

軟負載:即利用軟體進行負載均衡處理,如nginx

負載均衡的另一種分類:

集中式負載(服務端負載):集中式負載位于網際網路與服務提供者之間,如nginx、F5

程序内負載(用戶端負載):指從一個執行個體庫(即服務注冊中心)選取一個執行個體進行流量導入。這類負載的負載均衡器是類似與Ribbon的IPC(Inter-process communication,程序間通信 )元件

Spring Cloud教程 第二彈 用戶端負載均衡Ribbon

2、走進Ribbo世界

簡介:

Ribbon是一個負載均衡用戶端,在實際使用中,Ribbon相當于一個服務消費者的存在。是以,我下面會介紹如何搭建以Ribbon元件為基礎的消費者工程,Eureka Server工程與服務提供者工程這裡暫不介紹

注意:

這裡隻有Ribbon入門實戰中暫時不涉及ribbon相關的配置,ribbon相關配置後續介紹

RestTemplate是spring web子產品提供的一個操作Rest接口的模闆類,該類Ribbon似乎并沒有任何關系

我們一直強調Ribbon是一個用戶端負載均衡元件,正是@LoadBalanced注解讓RestTemplate具有負載均衡能力,其背後的原理下面講解

首先,服務提供者暴露一個傳回自身端口号的接口,服務消費者消費該方法

關鍵代碼:

restTemplate.getForObject("http://service-a/service-a/common/port", String.class);

本來URL應該是這樣的:http://ip:port/service-a/common/port,但是由于Ribbon是從Eureka Server上拉取服務執行個體,是以這裡可以将ip:port替換成服務名稱。

而由于@LoadBalanced讓RestTemplate具有負載均衡能力,是以當服務提供者有多個執行個體時(單機情況下,可以通過使用不同端口号來啟動多個執行個體),每次傳回的端口号也都不一樣

首先看看Eureka Server的儀表盤

Spring Cloud教程 第二彈 用戶端負載均衡Ribbon

這裡我服務消費者啟動了一個執行個體,而服務提供者啟動了多個執行個體,浏覽器多次通路​​http://localhost:8020/consumer-a/common/provider/port​​  可以看到頁面顯示的端口号是變化的,這說明負載均衡生效

Spring Cloud教程 第二彈 用戶端負載均衡Ribbon
Spring Cloud教程 第二彈 用戶端負載均衡Ribbon
Spring Cloud教程 第二彈 用戶端負載均衡Ribbon

Ribbon核心接口共同定義了Ribbon的行為,是Ribbon的骨架。官方文檔上指出了Ribbon的核心接口,下表顯示了Spring Cloud Netflix預設為Ribbon提供的bean

<col>

Bean Type

Bean Name

 Class Name 

描述

IClientConfig  

ribbonClientConfig  

DefaultClientConfigImpl  

定義配置

IRule  

ribbonRule  

ZoneAvoidanceRule  

定義負載均衡政策

IPing  

ribbonPing  

DummyPing  

定期Ping服務檢查可用性

ServerList

ribbonServerList

ConfigurationBasedServerList

定義服務清單

ServerListFilter

 ribbonServerListFilter

ZonePreferenceServerListFilter  

定義特定期望擷取服務清單

ILoadBalancer   

ribbonLoadBalancer

ZoneAwareLoadBalancer  

定義負載均衡選擇服務的核心方法

ServerListUpdater

 ribbonServerListUpdater

 PollingServerListUpdater

為DynamicServerListLoadBalancer定義動态更新服務清單接口

由于Ribbon的負載均衡政策是由IRule接口定義的,是以下面看一下IRule接口的繼承關系:

綠色表示接口,藍色表示抽象類

IRule

        AbstractLoadBalancerRule (com.netflix.loadbalancer)

                ClientConfigEnabledRoundRobinRule (com.netflix.loadbalancer) 這個類看名字就知道實際上是用的RoundRobinRule

                        BestAvailableRule (com.netflix.loadbalancer) (1)最低并發政策

                        PredicateBasedRule (com.netflix.loadbalancer)

                                ZoneAvoidanceRule (com.netflix.loadbalancer) (2)區域回避政策

                                AvailabilityFilteringRule (com.netflix.loadbalancer) (3)可用過濾政策。過濾掉一直連接配接失敗和存在高并發連接配接的server

                RoundRobinRule (com.netflix.loadbalancer) (4)輪詢政策

                        WeightedResponseTimeRule (com.netflix.loadbalancer) (5)響應時間權重政策。根據server的響應時間配置設定權重,響應時間越長,權重越低。綜合了網絡磁盤IO各種因素,這些因素直接影響了響應時間

                        ResponseTimeWeightedRule (com.netflix.loadbalancer) 過時,不建議使用

                RandomRule (com.netflix.loadbalancer) (6)随機政策

                RetryRule (com.netflix.loadbalancer)  (7)重試政策

綜上所屬,Ribbon預設有7種負載均衡政策

IRule接口源碼:

choose方法主要實作負載均衡邏輯

在調用過程中,Ribbon是通過ILoadBalancer來關聯IRule的,ILoadBalancer的chooseServer方法會轉換為調用IRule的choose方法。

AbstractLoadBalancerRule類将IRule接口與ILoadBalancer接口關聯起來了

AbstractLoadBalancerRule類源碼:

關于Ribbon核心工作原理的源碼解讀,請看這篇文章 Spring Cloud教程 第三彈 Ribbon工作原理

3、個性化配置

對于Ribbon的核心接口,都是按預設規則配置好的,比如負載均衡算法,預設采用的是ZoneAvoidanceRule 算法,如果我們想采用别的負載均衡算法呢,那麼需要我們做一些個性化配置

隻需要将個性化配置類打上@Configuration注解,并且讓spring boot掃到它即可生效

首先要做的事就是,避免讓spring boot掃到CustomRibbonConfig ,通過@ComponentScan注解的excludeFilters屬性實作

再通過@RibbonClients注解的defaultConfiguration屬性實作全局配置

首先自定義一個注解

将@AVoidScan注解打在CustomRibbonConfig類上,然後再spring boot的啟動類上分别打上@ComponentScan注解和@RibbonClients注解,部分代碼如下所示

同樣要做的事就是,避免讓spring boot掃到CustomRibbonConfig,實作方式上面已經講過了

再通過@RibbonClient注解針對單個服務源進行配置,如下所示

格式為:      

*代表配置項的key,key在CommonClientConfigKey類中定義,而值在RibbonProperties中擷取

比如我要配置負載均衡政策,配置細節如下:

當多種配置方式并存時,其優先級如下:

配置檔案中定義的 &gt; RibbonClient注解定義的 &gt; 預設的

4、使用負載均衡API

除了通過RestTemplate進行負載均衡,還可以直接使用負載均衡用戶端

5、Ribbon緩存機制

Ribbon并不是實時從eureka server上更新服務清單的,而是有一個緩沖時間,預設每30秒從eureka server上更新一次服務執行個體,可以通過如下配置項修改

6、不使用Eureka

ribbon預設是結合eureka使用的,ribbon會定期從eureka server上拉取執行個體清單

ribbon同樣支援不使用eureka,如何實作呢?

首先要做的是去除eureka client的依賴

去掉@EnableEurekaClient注解

關閉eureka

在配置檔案中針對單個服務源手動配置執行個體清單

7、開啟Ribbon的饑餓加載

Ribbon在進行用戶端負載均衡時并不是啟動時就加載上下文,而采用了懶加載,即第一次請求的時候才會去加載,這樣會導緻第一次請求發生逾時

初始化方法是RibbonApplicationContextInitializer.initialize方法

如何開啟饑餓加載?如下所示

8、Ribbon的逾時與重試機制

對于重試機制:如果ribbon在重試期間,時間超過了hystrix的逾時時間,則會熔斷。是以ribbon的重試時間 必須要小于 hystrix逾時時間,否則重試沒有意義

對于OkToRetryOnAllOperations,false表示隻會對get請求重試。而true表示所有請求都重試。true要慎用,如果接口沒有做幂等性,重試可能會導緻不良的後果

預設情況下,GET方式請求無論是連接配接異常還是讀取異常,都會進行重試,非GET方式請求,隻有連接配接異常時,才會進行重試

繼續閱讀