(目錄)
Ribbon負載均衡
我們添加了 @LoadBalanced
注解,即可實作負載均衡功能,這是什麼原理呢?
負載均衡原理
其實是利用了一個名為
SpringCloud 底層
的元件,來
Ribbon
的。
實作負載均衡功能
那麼我們發出的請求明明是 http://userservice/user/1 ,怎麼變成了http://localhost:8081的呢?
源碼跟蹤
為什麼我們隻輸入了service名稱就可以通路了呢?之前還要擷取ip和端口。
顯然有人幫我們根據service名稱,擷取到了服務執行個體的ip和端口。
它就是
,這個類會在對RestTemplate的請求進行攔截,然後從Eureka根據服務id擷取服務清單,随後利用負載均衡算法得到真實的服務位址資訊,替換服務id
LoadBalancerInterceptor
我們進行源碼跟蹤:
1)LoadBalancerIntercepor
可以看到這裡的
intercept
方法,攔截了使用者的HttpRequest請求,然後做了幾件事:
這裡的
:擷取請求uri,本例中就是 http://user-service/user/8
request.getURI()
:擷取uri路徑的主機名,其實就是服務id,
originalUri.getHost()
user-service
:處理服務id,和使用者請求。
this.loadBalancer.execute()
是
this.loadBalancer
類型,我們繼續跟入。
LoadBalancerClient
2)LoadBalancerClient
繼續跟入 execute()
方法:
代碼是這樣的:
:根據服務id擷取
getLoadBalancer(serviceId)
,而ILoadBalancer會拿着服務id去eureka中擷取服務清單并儲存起來。
ILoadBalancer
:利用内置的負載均衡算法,從服務清單中選擇一個。本例中,可以看到擷取了8082端口的服務
getServer(loadBalancer)
可以看到擷取服務時,通過一個
getServer()
方法來做負載均衡:
果然實作了負載均衡。
3)負載均衡政策IRule
在剛才的代碼中,可以看到擷取服務使通過一個 getServer
方法來做負載均衡:
繼續跟蹤源碼 chooseServer()
方法,發現這麼一段代碼:
繼續跟蹤源碼chooseServer方法,發現這麼一段代碼:
我們看看這個 rule
是誰:
這裡的rule預設值是一個 RoundRobinRule
,看類的介紹:
負載均衡預設使用了輪訓算法,當然我們也可以自定義
到這裡,整個負載均衡的流程我們就清楚了。
4)總結
采用了一個
SpringCloudRibbon的底層
,
攔截器
發出的
攔截了RestTemplate
,
請求
對位址做了修改
用一幅圖來總結一下:
- 攔截我們的
請求 http://userservice/user/1
RestTemplate
會從請求url中擷取服務名稱,也就是 user-service
RibbonLoadBalancerClient
根據 user-service 到 eureka 拉取服務清單
DynamicServerListLoadBalancer
- eureka 傳回清單,localhost:8081、localhost:8082
利用内置負載均衡規則,從清單中選擇一個,例如 localhost:8081
IRule
修改請求位址,用 localhost:8081 替代 userservice,得到 http://localhost:8081/user/1,發起真實請求
RibbonLoadBalancerClient
負載均衡政策
負載均衡政策
都定義在
負載均衡的規則
中,而IRule有很多不同的實作類:
IRule接口
不同規則的含義如下:
内置負載均衡規則類 | 規則描述 |
---|---|
RoundRobinRule | 簡單輪詢服務清單來選擇伺服器。它是Ribbon預設的負載均衡規則。 |
AvailabilityFilteringRule | 對以下兩種伺服器進行忽略: (1)在預設情況下,這台伺服器如果3次連接配接失敗,這台伺服器就會被設定為“短路”狀态。短路狀态将持續30秒,如果再次連接配接失敗,短路的持續時間就會幾何級地增加。 (2)并發數過高的伺服器。如果一個伺服器的并發連接配接數過高,配置了AvailabilityFilteringRule規則的用戶端也會将其忽略。并發連接配接數的上限,可以由用戶端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit屬性進行配置。 |
WeightedResponseTimeRule | 為每一個伺服器賦予一個權重值。伺服器響應時間越長,這個伺服器的權重就越小。這個規則會随機選擇伺服器,這個權重值會影響伺服器的選擇。 |
ZoneAvoidanceRule | 以區域可用的伺服器為基礎進行伺服器的選擇。使用Zone對伺服器進行分類,這個Zone可以了解為一個機房、一個機架等。而後再對Zone内的多個服務做輪詢。 |
BestAvailableRule | 忽略那些短路的伺服器,并選擇并發數較低的伺服器。 |
RandomRule | 随機選擇一個可用的伺服器。 |
RetryRule | 重試機制的選擇邏輯 |
預設的實作
就是
ZoneAvoidanceRule
,是一種輪詢方案
自定義負載均衡政策
通過定義IRule實作可以修改負載均衡規則,有兩種方式:
:在order-service中的OrderApplication類中,定義一個新的IRule:
代碼方式
@Bean
public IRule randomRule(){
return new RandomRule();
}
:在order-service的application.yml檔案中,添加新的配置也可以修改規則:
配置檔案方式
userservice: # 給某個微服務配置負載均衡規則,這裡是userservice服務
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 負載均衡規則
注意,一般用預設的負載均衡規則,不做修改。
饑餓加載
當我們啟動 orderservice,第一次通路時,時間消耗會大很多,這是因為
Ribbon 懶加載的機制
ribbon:
eager-load:
enabled: true
clients: userservice # 服務名稱