微服務(wù)(4)
微服務(wù)(4)
在前面,我們添加了@LoadBalanced注解,即可實(shí)現(xiàn)負(fù)載均衡功能,這是什么原理、什么策略呢?
1. 負(fù)載均衡原理
SpringCloud底層其實(shí)是利用了一個(gè)名為Ribbon的組件,來(lái)實(shí)現(xiàn)負(fù)載均衡功能的。
那么我們發(fā)出的請(qǐng)求明明是http://userservice/user/1,怎么變成了http://localhost:8081的呢?
2. 源碼跟蹤
為什么我們只輸入了service名稱(chēng)就可以訪(fǎng)問(wèn)了呢?之前還要獲取ip和端口。
Ribbon是怎么攔截這個(gè)請(qǐng)求,并將url進(jìn)行處理的呢?
顯然有人幫我們根據(jù)service名稱(chēng),獲取到了服務(wù)實(shí)例的ip和端口。它就是LoadBalancerInterceptor
,這個(gè)類(lèi)會(huì)在對(duì)RestTemplate的請(qǐng)求進(jìn)行攔截,然后從Eureka根據(jù)服務(wù)id獲取服務(wù)列表,隨后利用負(fù)載均衡算法得到真實(shí)的服務(wù)地址信息,替換服務(wù)id。
我們進(jìn)行源碼跟蹤(雙擊shift搜索):
1)LoadBalancerIntercepor
調(diào)試一下:
打個(gè)斷點(diǎn):
瀏覽器訪(fǎng)問(wèn):
停在這了:
跳兩步觀察:
可以看到這里的intercept方法,攔截了用戶(hù)的HttpRequest請(qǐng)求,然后做了幾件事:
-
request.getURI()
:獲取請(qǐng)求uri,本例中就是 http://userservice/user/1 -
originalUri.getHost()
:獲取uri路徑的主機(jī)名,其實(shí)就是服務(wù)id名稱(chēng),userservice
-
this.loadBalancer.execute()
:處理服務(wù)id名稱(chēng),和用戶(hù)請(qǐng)求。
這里的this.loadBalancer
是LoadBalancerClient
類(lèi)型,我們繼續(xù)跟入。
2)LoadBalancerClient
繼續(xù)跟入execute方法,調(diào)用getLoadBalancer方法:
調(diào)用getServer方法:
這個(gè)就是我們的內(nèi)網(wǎng)ip(命令行cmd,ipconfig查看)
代碼是這樣的:
- getLoadBalancer(serviceId):根據(jù)服務(wù)id獲取ILoadBalancer,而ILoadBalancer會(huì)拿著服務(wù)id去eureka中獲取服務(wù)列表并保存起來(lái)。
- getServer(loadBalancer):利用內(nèi)置的負(fù)載均衡算法,從服務(wù)列表中選擇一個(gè)。本例中,可以看到獲取了8081端口的服務(wù)
放行后,再次訪(fǎng)問(wèn)并跟蹤,發(fā)現(xiàn)獲取的是8082:
果然實(shí)現(xiàn)了負(fù)載均衡。
3)負(fù)載均衡策略IRule
跟進(jìn)getServer方法:
進(jìn)入方法內(nèi)部:
- 通過(guò)規(guī)則選擇
IRule,故名思意就是規(guī)則接口,想必就是負(fù)載均衡算法的規(guī)則取決于它
可見(jiàn)IRule接口有很多的實(shí)現(xiàn)
最明顯的就是RandomRule,顧名思義就是隨機(jī);RoundRobinRule,顧名思義就是輪詢(xún)調(diào)度
而現(xiàn)在的規(guī)則是:ZoneAvoidanceRule
key是default(其實(shí)就是嘗試從配置文件里獲取常量,沒(méi)有配置就獲取不到,就默認(rèn)咯)
我們看看這個(gè)rule是誰(shuí):
這不就是輪詢(xún)的意思嘛。
到這里,整個(gè)負(fù)載均衡的流程我們就清楚了,至于這些策略規(guī)則是什么,隨后講解~
4)總結(jié)
SpringCloudRibbon的底層采用了一個(gè)攔截器,攔截了RestTemplate發(fā)出的請(qǐng)求,對(duì)地址做了修改。用一幅圖來(lái)總結(jié)一下:
基本流程如下:
- 攔截我們的RestTemplate請(qǐng)求http://userservice/user/1
- RibbonLoadBalancerClient會(huì)從請(qǐng)求url中獲取服務(wù)名稱(chēng),也就是userservice
- DynamicServerListLoadBalancer根據(jù)userservice到eureka拉取服務(wù)列表
- eureka返回列表,localhost:8081、localhost:8082
- IRule利用內(nèi)置負(fù)載均衡規(guī)則,從列表中選擇一個(gè),例如localhost:8081
- RibbonLoadBalancerClient修改請(qǐng)求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,發(fā)起真實(shí)請(qǐng)求
3. 負(fù)載均衡策略
3.1 負(fù)載均衡策略
負(fù)載均衡的規(guī)則都定義在IRule接口中,而IRule有很多不同的實(shí)現(xiàn)類(lèi):
不同規(guī)則的含義如下:
內(nèi)置負(fù)載均衡規(guī)則類(lèi) | 規(guī)則描述 |
---|---|
RoundRobinRule | 簡(jiǎn)單輪詢(xún)服務(wù)列表來(lái)選擇服務(wù)器。 |
AvailabilityFilteringRule | 對(duì)以下兩種服務(wù)器進(jìn)行忽略: (1)在默認(rèn)情況下,這臺(tái)服務(wù)器如果3次連接失敗,這臺(tái)服務(wù)器就會(huì)被設(shè)置為“短路”狀態(tài)。短路狀態(tài)將持續(xù)30秒,如果再次連接失敗,短路的持續(xù)時(shí)間就會(huì)幾何級(jí)地增加。 (2)并發(fā)數(shù)過(guò)高的服務(wù)器。如果一個(gè)服務(wù)器的并發(fā)連接數(shù)過(guò)高,配置了AvailabilityFilteringRule規(guī)則的客戶(hù)端也會(huì)將其忽略。并發(fā)連接數(shù)的上限,可以由客戶(hù)端的..ActiveConnectionsLimit屬性進(jìn)行配置。 |
WeightedResponseTimeRule | 為每一個(gè)服務(wù)器賦予一個(gè)權(quán)重值。服務(wù)器響應(yīng)時(shí)間越長(zhǎng),這個(gè)服務(wù)器的權(quán)重就越小。這個(gè)規(guī)則會(huì)隨機(jī)選擇服務(wù)器,這個(gè)權(quán)重值會(huì)影響服務(wù)器的選擇。 |
ZoneAvoidanceRule | 以區(qū)域可用的服務(wù)器為基礎(chǔ)進(jìn)行服務(wù)器的選擇。使用Zone對(duì)服務(wù)器進(jìn)行分類(lèi),這個(gè)Zone可以理解為一個(gè)機(jī)房、一個(gè)機(jī)架等。而后再對(duì)Zone內(nèi)的多個(gè)服務(wù)做輪詢(xún)。(如果沒(méi)有Zone的劃分,其實(shí)就是跟普通輪詢(xún)沒(méi)啥區(qū)別) |
BestAvailableRule | 忽略那些短路的服務(wù)器,并選擇并發(fā)數(shù)較低的服務(wù)器。 |
RandomRule | 隨機(jī)選擇一個(gè)可用的服務(wù)器。 |
RetryRule | 重試機(jī)制的選擇邏輯 |
默認(rèn)的實(shí)現(xiàn)就是ZoneAvoidanceRule,是一種輪詢(xún)方案
默認(rèn)情況下,瀏覽器依次訪(fǎng)問(wèn)101、102、103、104,查看日志:(右側(cè)欄有個(gè)垃圾桶,點(diǎn)擊清空日志)
其實(shí)每次都這樣(一個(gè)2 4;一個(gè)1 3),就是輪詢(xún)策略~
3.2 自定義負(fù)載均衡策略
通過(guò)定義IRule實(shí)現(xiàn)可以修改負(fù)載均衡規(guī)則,有兩種方式:
- 代碼方式:在order-service中的OrderApplication類(lèi)中,定義一個(gè)新的IRule:
- 那么ribbon就會(huì)以這個(gè)bean的規(guī)則優(yōu)先
@Bean
public IRule randomRule(){
return new RandomRule();
}
效果:
每次都不一樣,甚至?xí)霈F(xiàn)有一個(gè)服務(wù)一個(gè)都沒(méi)有,很明顯是隨機(jī)(次數(shù)多了還每個(gè)服務(wù)的調(diào)用次數(shù)是很均衡的)
- 配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改規(guī)則:
userservice: # 給某個(gè)微服務(wù)配置負(fù)載均衡規(guī)則,這里是userservice服務(wù)
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 負(fù)載均衡規(guī)則
效果一致~
注意,一般用默認(rèn)的負(fù)載均衡規(guī)則,不做修改。
- 配置文件的設(shè)置優(yōu)先級(jí)較高,如果代碼方法設(shè)置的是A,配置方法設(shè)置的是B,則最終呈現(xiàn)是B
- 代碼設(shè)置的是全局的方案,也就是說(shuō)在order-service訪(fǎng)問(wèn)哪個(gè)微服務(wù)的都是這個(gè)規(guī)則
- 配置設(shè)置的是特定的微服務(wù)負(fù)載均衡規(guī)則(優(yōu)先級(jí)高也正常了)
- 從配置設(shè)置的鍵(userservice)可見(jiàn),是針對(duì)一個(gè)微服務(wù)的
4. 饑餓加載
不知道你有沒(méi)有發(fā)現(xiàn),我們?yōu)g覽器測(cè)試剛才的用例的時(shí)候,第一次要反應(yīng)一會(huì)兒,后面的就很流暢:
我們通過(guò)瀏覽器開(kāi)發(fā)者工具來(lái)看看第一次訪(fǎng)問(wèn)的時(shí)候的時(shí)間:
達(dá)到恐怖的744ms!
而之后就比較快了:
這是因?yàn)椋?/p>
- Ribbon默認(rèn)是采用懶加載,即第一次訪(fǎng)問(wèn)時(shí)才會(huì)去創(chuàng)建LoadBalanceClient,請(qǐng)求時(shí)間會(huì)很長(zhǎng)。
- 嚴(yán)格來(lái)說(shuō)是第一次用到這個(gè)服務(wù)的LoadBalanceClient才會(huì)加載
- 加載之后就緩存下來(lái)了,可以直接用或者下一次拉取直接賦值給這個(gè)對(duì)象就行了
- 當(dāng)然,如果是別的服務(wù)的LoadBalanceClient,還需要加載
而饑餓加載則會(huì)在項(xiàng)目啟動(dòng)時(shí)創(chuàng)建,降低第一次訪(fǎng)問(wèn)的耗時(shí),通過(guò)下面配置開(kāi)啟饑餓加載:
ribbon:
eager-load:
enabled: true # 默認(rèn)false為懶加載,這里設(shè)置為true為饑餓加載
clients: userservice # 指定對(duì)哪個(gè)微服務(wù)饑餓加載
- clients的值是一個(gè)集合,可以這么寫(xiě):
重啟
- 可見(jiàn)已經(jīng)加載
觀察一下時(shí)間:
第一次訪(fǎng)問(wèn)快了不少了(第一次也要加載一些框架之類(lèi)的,當(dāng)然也可以設(shè)置為饑餓加載,不在這里演示)
文章到此結(jié)束!謝謝觀看
可以叫我 小馬,我可能寫(xiě)的不好或者有錯(cuò)誤,但是一起加油鴨??!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-713643.html代碼:cloud-demo · 游離態(tài)/云服務(wù) - 碼云 - 開(kāi)源中國(guó) (gitee.com)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-713643.html
到了這里,關(guān)于【微服務(wù) SpringCloud】實(shí)用篇 · Ribbon負(fù)載均衡的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!