天天看點

SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載

(目錄)

Ribbon負載均衡

我們添加了

@LoadBalanced

注解,即可實作負載均衡功能,這是什麼原理呢?

負載均衡原理

SpringCloud 底層

其實是利用了一個名為

Ribbon

的元件,來

實作負載均衡功能

的。
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
那麼我們發出的請求明明是 http://userservice/user/1 ,怎麼變成了http://localhost:8081的呢?

源碼跟蹤

為什麼我們隻輸入了service名稱就可以通路了呢?之前還要擷取ip和端口。

顯然有人幫我們根據service名稱,擷取到了服務執行個體的ip和端口。

它就是

LoadBalancerInterceptor

,這個類會在對RestTemplate的請求進行攔截,然後從Eureka根據服務id擷取服務清單,随後利用負載均衡算法得到真實的服務位址資訊,替換服務id

我們進行源碼跟蹤:

1)LoadBalancerIntercepor

SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載

可以看到這裡的

intercept

方法,攔截了使用者的HttpRequest請求,然後做了幾件事:

  • request.getURI()

    :擷取請求uri,本例中就是 http://user-service/user/8
  • originalUri.getHost()

    :擷取uri路徑的主機名,其實就是服務id,

    user-service

  • this.loadBalancer.execute()

    :處理服務id,和使用者請求。
這裡的

this.loadBalancer

LoadBalancerClient

類型,我們繼續跟入。

2)LoadBalancerClient

繼續跟入

execute()

方法:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載

代碼是這樣的:

  • getLoadBalancer(serviceId)

    :根據服務id擷取

    ILoadBalancer

    ,而ILoadBalancer會拿着服務id去eureka中擷取服務清單并儲存起來。
  • getServer(loadBalancer)

    :利用内置的負載均衡算法,從服務清單中選擇一個。本例中,可以看到擷取了8082端口的服務

可以看到擷取服務時,通過一個

getServer()

方法來做負載均衡:

SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載

果然實作了負載均衡。

3)負載均衡政策IRule

在剛才的代碼中,可以看到擷取服務使通過一個

getServer

方法來做負載均衡:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
繼續跟蹤源碼

chooseServer()

方法,發現這麼一段代碼:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
繼續跟蹤源碼chooseServer方法,發現這麼一段代碼:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
我們看看這個

rule

是誰:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
這裡的rule預設值是一個

RoundRobinRule

,看類的介紹:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
負載均衡預設使用了輪訓算法,當然我們也可以自定義

到這裡,整個負載均衡的流程我們就清楚了。

4)總結

SpringCloudRibbon的底層

采用了一個

攔截器

攔截了RestTemplate

發出的

請求

對位址做了修改

用一幅圖來總結一下:

SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
  • 攔截我們的

    RestTemplate

    請求 http://userservice/user/1
  • RibbonLoadBalancerClient

    會從請求url中擷取服務名稱,也就是 user-service
  • DynamicServerListLoadBalancer

    根據 user-service 到 eureka 拉取服務清單
  • eureka 傳回清單,localhost:8081、localhost:8082
  • IRule

    利用内置負載均衡規則,從清單中選擇一個,例如 localhost:8081
  • RibbonLoadBalancerClient

    修改請求位址,用 localhost:8081 替代 userservice,得到 http://localhost:8081/user/1,發起真實請求

負載均衡政策

負載均衡政策

負載均衡的規則

都定義在

IRule接口

中,而IRule有很多不同的實作類:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載

不同規則的含義如下:

内置負載均衡規則類 規則描述
RoundRobinRule 簡單輪詢服務清單來選擇伺服器。它是Ribbon預設的負載均衡規則。
AvailabilityFilteringRule 對以下兩種伺服器進行忽略: (1)在預設情況下,這台伺服器如果3次連接配接失敗,這台伺服器就會被設定為“短路”狀态。短路狀态将持續30秒,如果再次連接配接失敗,短路的持續時間就會幾何級地增加。 (2)并發數過高的伺服器。如果一個伺服器的并發連接配接數過高,配置了AvailabilityFilteringRule規則的用戶端也會将其忽略。并發連接配接數的上限,可以由用戶端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit屬性進行配置。
WeightedResponseTimeRule 為每一個伺服器賦予一個權重值。伺服器響應時間越長,這個伺服器的權重就越小。這個規則會随機選擇伺服器,這個權重值會影響伺服器的選擇。
ZoneAvoidanceRule 以區域可用的伺服器為基礎進行伺服器的選擇。使用Zone對伺服器進行分類,這個Zone可以了解為一個機房、一個機架等。而後再對Zone内的多個服務做輪詢。
BestAvailableRule 忽略那些短路的伺服器,并選擇并發數較低的伺服器。
RandomRule 随機選擇一個可用的伺服器。
RetryRule 重試機制的選擇邏輯

預設的實作

就是

ZoneAvoidanceRule

,是一種輪詢方案

自定義負載均衡政策

通過定義IRule實作可以修改負載均衡規則,有兩種方式:

  1. 代碼方式

    :在order-service中的OrderApplication類中,定義一個新的IRule:
SpringCloud 的 Ribbon負載均衡、原理分析 及 負載均衡政策與自定義政策、饑餓加載
@Bean
public IRule randomRule(){
    return new RandomRule();
}
           
  1. 配置檔案方式

    :在order-service的application.yml檔案中,添加新的配置也可以修改規則:
userservice: # 給某個微服務配置負載均衡規則,這裡是userservice服務
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 負載均衡規則 
           
注意,一般用預設的負載均衡規則,不做修改。

饑餓加載

當我們啟動 orderservice,第一次通路時,時間消耗會大很多,這是因為

Ribbon 懶加載的機制

ribbon:
  eager-load:
    enabled: true
    clients: userservice # 服務名稱
           

繼續閱讀