javascript
SpringCloud Ribbon源码探索学习
Ribbon使用
在平時(shí)使用Ribbon時(shí),更多的是將Ribbon與RestTemplate相結(jié)合:
@Bean@LoadBalancedRestTemplate restTemplate(){return new RestTemplate();} 復(fù)制代碼首先定義一個(gè)RestTemplate,通過(guò)注解注入,同時(shí)注解也完成了負(fù)載均衡。
同時(shí)去使用restTemplate進(jìn)行Rest調(diào)用
@Overridepublic String hiService(String name){return restTemplate.getForObject("http://SERVER-HI/hi?name="+name,String.class);} 復(fù)制代碼那么在我們?cè)谳斎雋ttp://localhost:8770/hi?name=lixin后,到底做了什么
一、封裝
首先,在進(jìn)行g(shù)etForObject方法后,會(huì)將帶入的url進(jìn)行封裝,封裝成http請(qǐng)求request,然后被攔截器LoadBalancerInterceptor進(jìn)行攔截,代碼分別是:
@Override@Nullablepublic <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);HttpMessageConverterExtractor<T> responseExtractor =new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);} 復(fù)制代碼二、攔截
以及攔截部分:將request攔截下,截取其中URL及服務(wù)名,用于之后調(diào)用負(fù)載均衡方法時(shí),選擇合適的服務(wù)實(shí)例
@Overridepublic ClientHttpResponse intercept(final HttpRequest request, final byte[] body,final ClientHttpRequestExecution execution) throws IOException {final URI originalUri = request.getURI();String serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));} 復(fù)制代碼三、根據(jù)負(fù)載均衡器調(diào)用服務(wù)實(shí)例
至此,調(diào)用RibbonLoadBalancerClient中的execute方法,先查看一下RibbonLoadBalancerClient類:
其中LoadBalancerClient接口,有如下三個(gè)方法,其中excute()為執(zhí)行請(qǐng)求,reconstructURI()用來(lái)重構(gòu)url。
ServiceInstanceChooser接口,主要有一個(gè)方法,用來(lái)根據(jù)serviceId來(lái)獲取ServiceInstance。
它繼承了ServiceInstanceChooser及LoadBalancerClient類,最終的負(fù)載均衡的請(qǐng)求處理,由它來(lái)執(zhí)行
首先,去獲取需要加載的負(fù)載均衡策略,通過(guò)getLoadBalancer方法執(zhí)行,默認(rèn)是輪詢RoundRobbinRule方式:
在獲取到負(fù)載均衡策略之后,通過(guò)getServer()方法去獲取實(shí)例,點(diǎn)擊進(jìn)入getServer方法,發(fā)現(xiàn)是ILoadBalancer類去選擇服務(wù)實(shí)例。
在ILoadBalancer接口中,addServers()方法是添加一個(gè)Server集合;chooseServer()方法是根據(jù)key去獲取Server;markServerDown()方法用來(lái)標(biāo)記某個(gè)服務(wù)下線;getReachableServers()獲取可用的Server集合;getAllServers()獲取所有的Server集合。
chooseServer則是由BaseLoadBalancer類進(jìn)行實(shí)現(xiàn):
根據(jù)代碼可以看出,具體choose方法是根據(jù)不同的負(fù)載均衡策略,會(huì)有不同的選擇方法,返回具體根據(jù)策略得到的服務(wù)實(shí)例。
最后根據(jù)服務(wù)實(shí)例,進(jìn)行請(qǐng)求的調(diào)用。
負(fù)載均衡策略
IRule用于復(fù)雜均衡的策略,它有三個(gè)方法,其中choose()是根據(jù)key 來(lái)獲取server,setLoadBalancer()和getLoadBalancer()是用來(lái)設(shè)置和獲取ILoadBalancer的
IRule有很多默認(rèn)的實(shí)現(xiàn)類,這些實(shí)現(xiàn)類根據(jù)不同的算法和邏輯來(lái)處理負(fù)載均衡。Ribbon實(shí)現(xiàn)的IRule有以下幾個(gè)。在大多數(shù)情況下,這些默認(rèn)的實(shí)現(xiàn)類是可以滿足需求的,如果有特性的需求,可以自己實(shí)現(xiàn)。
- BestAvailableRule 選擇最小請(qǐng)求數(shù)
- ClientConfigEnabledRoundRobinRule 輪詢
- RandomRule 隨機(jī)選擇一個(gè)server
- RoundRobinRule 輪詢選擇server
- RetryRule 根據(jù)輪詢的方式重試
- WeightedResponseTimeRule 根據(jù)響應(yīng)時(shí)間去分配一個(gè)weight ,weight越低,被選擇的可能性就越低
- ZoneAvoidanceRule 根據(jù)server的zone區(qū)域和可用性來(lái)輪詢選擇
RoundRobbinRule
那我們就先看看RoundRobbinRule類中的輪詢策略:
①首先獲取所有存活的服務(wù)列表reachableServers及所有服務(wù)列表allServers,判斷兩個(gè)list是否為空。 ②incrementAndGetModulo中則是對(duì)一個(gè)原子性變量進(jìn)行+1操作,并同時(shí)進(jìn)行一個(gè)CAS操作,去修改nextServerIndex值,保證輪詢的可靠性。③最后判斷服務(wù)是否可用,如果不可用,則重新進(jìn)入循環(huán)。
④如果在10次循環(huán)后,仍然沒有可用的服務(wù),則退出循環(huán)并進(jìn)行警告。最后返回服務(wù)實(shí)例
RetryRule
可重試的輪詢策略如下:
可見此處多了兩行代碼:
long requestTime = System.currentTimeMillis(); long deadline = requestTime + maxRetryMillis; 復(fù)制代碼定義了500ms的總重試時(shí)間,如果服務(wù)實(shí)例獲取不到,則進(jìn)入循環(huán),在循環(huán)中每次需要判斷一下是否超過(guò)總時(shí)間
while循環(huán)中,每次都會(huì)去獲取一下服務(wù)實(shí)例,然后進(jìn)行判斷,如果實(shí)例仍然沒有獲取到,則對(duì)當(dāng)前線程進(jìn)行Thread.yield()操作,此操作的意義是:讓出當(dāng)前線程時(shí)間分片,重新爭(zhēng)奪時(shí)間片,讓定時(shí)任務(wù)去執(zhí)行,看是否達(dá)到規(guī)定時(shí)間,如到時(shí)間,則執(zhí)行interrupt()操作,退出循環(huán)
這即是可重試的策略
總體流程
Ribbon + RestTemplate 的負(fù)載平衡,流程是: 通過(guò)注解后,對(duì)url進(jìn)行封裝request,攔截器對(duì)request進(jìn)行攔截,然后根據(jù)負(fù)載均衡器去調(diào)用服務(wù)實(shí)例,完成負(fù)載平衡和服務(wù)調(diào)用
總結(jié)
以上是生活随笔為你收集整理的SpringCloud Ribbon源码探索学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: javascript中创建对象的几种方式
- 下一篇: Java核心技术笔记 语言基础