微服務(wù)架構(gòu)如何實(shí)現(xiàn)客戶端負(fù)載均衡

?Spring Cloud Ribbon 是一一基于HTTP 和TCP 的客戶端負(fù)載均衡工具,它基于NetflixRibbon實(shí)現(xiàn)。通過Spring Cloud 的封裝,可以讓我們輕松地將面向服務(wù)的REST 模板請求自動(dòng)轉(zhuǎn)換成客戶端負(fù)載均衡的服務(wù)調(diào)用。Spring Cloud Ribbon 雖然只是一個(gè)工具類框架,它不像服務(wù)注冊中心、配置中心、API 網(wǎng)關(guān)那樣需要獨(dú)立部署,但是它兒乎存在于每一個(gè)SpringCloud 構(gòu)建的微服務(wù)和基礎(chǔ)設(shè)施中。因?yàn)槲⒎?wù)間的調(diào)用,API 網(wǎng)關(guān)的請求轉(zhuǎn)發(fā)等內(nèi)容,實(shí)際上都是通過Ribbon 來實(shí)現(xiàn)的,包括后續(xù)我們將要介紹的Feign,它也是基于Ribbon實(shí)現(xiàn)的工具。所以,對Spring Cloud Ribbon 的理解和使用,對于我們使用Spring Cloud 來構(gòu)建微服務(wù)非常重要。

在這里,我們將介紹如何使用Ribbon 來實(shí)現(xiàn)客戶端的負(fù)載均衡,并且通過源碼分析來了解Ribbon 實(shí)現(xiàn)客戶端負(fù)載均衡的基本原理。

客戶端負(fù)載均衡

負(fù)載均衡在系統(tǒng)架構(gòu)中是一個(gè)非常重要,并且是不得不去實(shí)施的內(nèi)容。因?yàn)樨?fù)載均衡是對系統(tǒng)的高可用、網(wǎng)絡(luò)壓力的緩解和處理能力擴(kuò)容的重要手段之一。我們通常所說的負(fù)載均衡都指的是服務(wù)端負(fù)載均衡,其中分為硬件負(fù)載均衡和軟件負(fù)載均衡。硬件負(fù)載均衡主要通過在服務(wù)器節(jié)點(diǎn)之間安裝專門用于負(fù)載均衡的設(shè)備,比如F5 等; 而軟件負(fù)載均衡則是通過在服務(wù)器上安裝一些具有均衡負(fù)載功能或模塊的軟件來完成請求分發(fā)工作,比如Nginx 等。不論采用硬件負(fù)載均衡還是軟件負(fù)載均衡,只要是服務(wù)端負(fù)載均衡都能以架構(gòu)方式構(gòu)建起來:

? 硬件負(fù)載均衡的設(shè)備或是軟件負(fù)載均衡的軟件模塊都會維護(hù)一個(gè)下掛可用的服務(wù)端清單,通過心跳檢測來剔除故障的服務(wù)端節(jié)點(diǎn)以保證清單中都是可以正常訪問的服務(wù)端節(jié)點(diǎn)。當(dāng)客戶端發(fā)送請求到負(fù)載均衡設(shè)備的時(shí)候,該設(shè)備按某種算法(比如線性輪詢、按權(quán)重負(fù)載、按流量負(fù)載等)?從維護(hù)的可用服務(wù)端清單中取出一臺服務(wù)端的地址,然后進(jìn)行轉(zhuǎn)發(fā)。

而客戶端負(fù)載均衡和服務(wù)端負(fù)我均衡最大的不同點(diǎn)在于上面所提到的服務(wù)清單所存儲的位置。在客戶端負(fù)載均衡中,所有客戶端節(jié)點(diǎn)都維護(hù)著自己要訪問的服務(wù)端清單,而這些服務(wù)端的清單來自于服務(wù)注冊中心,比如Eureka 服務(wù)端。同服務(wù)端負(fù)載均衡的架構(gòu)類似,在客戶端負(fù)載均衡中也需要心跳去維護(hù)服務(wù)端清單的健康性,只是這個(gè)步驟需要與服務(wù)注冊中心配合完成。在Spring Cloud 實(shí)現(xiàn)的服務(wù)治理框架中,默認(rèn)會創(chuàng)建針對各個(gè)服務(wù)治理框架的Ribbon 自動(dòng)化整合配置,比如Eureka 中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAuto-?Configurationo 在實(shí)際使用的時(shí)候,我們可以通過查看這兩個(gè)類的實(shí)現(xiàn),以找到它們的配置詳情來幫助我們更好地使用它。

通過SpringCloudRibbon 的封裝,我們在微服務(wù)架構(gòu)中使用客戶端負(fù)載均衡調(diào)用非常簡單,只需要如下兩步:

1.服務(wù)提供者只需要啟動(dòng)多個(gè)服務(wù)實(shí)例并注冊到一個(gè)注冊中心或是多個(gè)相關(guān)聯(lián)的服務(wù)注冊中心。

2. 服務(wù)消費(fèi)者直接通過調(diào)用被@LoadBalanced?注解修飾過的RestTemplate來實(shí)現(xiàn)面向服務(wù)的接口調(diào)用。

??這樣,我們就可以將服務(wù)提供者的高可用以及服務(wù)消費(fèi)者的負(fù)載均衡調(diào)用一起實(shí)現(xiàn)了。 ?其中,我們使用了個(gè)非常有用的對象RestTemplate.該對象會使用Ribbon?的自動(dòng)化配置,同時(shí)通過配置@LoadBalanced?還能夠開啟客戶端負(fù)載均衡。之前我們演示了通過RestTemplate實(shí)現(xiàn)了最簡單的服務(wù)訪問,下面我們將詳細(xì)介紹RestTemplate?針對幾種不同請求類型和參數(shù)類型的服務(wù)調(diào)用實(shí)現(xiàn)。

??GET?請求

??在RestTemplate?中,對GET?請求可以通過如下兩個(gè)方法進(jìn)行調(diào)用實(shí)現(xiàn)。??第一種:?getForEntity?函數(shù)。該方法返回的是ResponseEntity,該對象是Spring對HTTP?請求響應(yīng)的封裝,其中主要存儲了HTTP?的幾個(gè)重要元素,比如HTTP?請求狀態(tài)馬的枚舉對象HttpStatus?(也就是我們常說的404、500?這些錯(cuò)誤碼)、在它的父類ittpEntity中還存儲著HTTP請求的頭信息對象HttpHeaders?以及泛型類型的請求體時(shí)象。比如下面的例子,就是訪問USER-SERVER服務(wù)的/user?請求,同時(shí)最后一個(gè)參數(shù)idi?會替換url?中的(1}占位符,而返回的ResponseEntity?對象中的body?內(nèi)容類型:根據(jù)第二個(gè)參數(shù)轉(zhuǎn)換為String類型。

? ? RestTemplate?restTemplate?二newRestTemplate?()?;?

? ?ResponseEntityStri?xesponseEntity?一restTemplate.getFor?("http:?//USER-RVICE/user?name={1}",string.class,"didi")?;??

String?body=?responseEntity.getBody?()?;??

若我們希望返回的body是一個(gè)User對象類型,也可以這樣實(shí)現(xiàn):?

? ?Restremplate?restTemplate=?new?Restremplate()?;??

? ResponseEntity?responseEntity?-restremplate.get?"http:?/USER-??vICE/user?name={1}",User.class,"didi")?;

? user?body=?responseEntity.getBody?()?;?

?上面的例子是比較常用的方法

POST 請求

在RestTemplate 中,

對POST 請求時(shí)可以通過如下三個(gè)方法進(jìn)行調(diào)用實(shí)現(xiàn)。

第一種: postEorEntity 函數(shù)。該方法同GET 請求中的getrorEntity 類似,會

在調(diào)用后返回ResponseEntity對象,其中T 為請求響應(yīng)的body 類型。

比如下面這

個(gè)例子,使用postForEntity 提交POST請求到USER-SERVICE 服務(wù)的/user 接口,

提交的body 內(nèi)容為user對象,請求響應(yīng)返回的body 類型為String。

RestTemplate restTemplate= new RestTemplate () ;

User user = new User ("didi",30) ;

ResponseEntity responseEntity=

restTemplate.postForEntity ("http: //USER-SERVICE/user",user,String.class) ;

String body= responseEntity.getBody () ;

postForEntity 函數(shù)也實(shí)現(xiàn)了三種不同的重載方法。

PUT?請求

GResTemplate中,對PUT請求可以通過pot?方法進(jìn)行調(diào)用實(shí)現(xiàn),比如, ? ?

?? RestTemplaterestTemplate=new?RestTemplate();

? Long?id?=?100011;

? User?user=new?User("didi",40);

? restemplate.put(http://USER-SERVICE/user/{1} ”,user,id ;

put?函數(shù)也實(shí)現(xiàn)了三種不同的重載方法:

1.put?(string?url,Object?request,0bject...urlVariables)

2.put?(Stringurl,Object?request,Map?urlVariables)

3.put?(URI?url,object?request?)

put函數(shù)為void類型,所以沒有返回內(nèi)容,也就沒有其他函數(shù)定義的responserype參數(shù),除此之外的其他傳入?yún)?shù)定義與用法與postforobject基本一致。

DELETE?請求

在RestTemplate?中,對DELETE?請求可以通過delete?方法進(jìn)行調(diào)用實(shí)現(xiàn),比如:

RestTemplate?restTemplate?=?new?RestTemplate?()?;

Long?id?=?10001L;restTemplate.delete?("http:?//USER-SERVICE/user/?(1}",id)?;

delete?函數(shù)也實(shí)現(xiàn)了三種不同的重載方法:

1.delete?(String?url,0bject...urlVariables)

2.delete?(String?url,Map?urlVariables)

3.delete?(URi url)由于我們在進(jìn)行REST請求時(shí),通常都將DELETE?請求的唯一標(biāo)識拼接在url?中,所DELETE?請求也不需要equest?的body信息,就如上面的三個(gè)函數(shù)實(shí)現(xiàn)一樣,非常簡單。1指定DELETE?請求的位置,urlVariables?綁定url?中的參數(shù)即可。

想學(xué)習(xí)更多更詳細(xì)的知識的,在此我向大家推薦一個(gè)交流學(xué)習(xí)群:744642380 里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容