javascript
SpringCloud Ribbon源码探索学习
Ribbon使用
在平時使用Ribbon時,更多的是將Ribbon與RestTemplate相結合:
@Bean@LoadBalancedRestTemplate restTemplate(){return new RestTemplate();} 復制代碼首先定義一個RestTemplate,通過注解注入,同時注解也完成了負載均衡。
同時去使用restTemplate進行Rest調用
@Overridepublic String hiService(String name){return restTemplate.getForObject("http://SERVER-HI/hi?name="+name,String.class);} 復制代碼那么在我們在輸入http://localhost:8770/hi?name=lixin后,到底做了什么
一、封裝
首先,在進行getForObject方法后,會將帶入的url進行封裝,封裝成http請求request,然后被攔截器LoadBalancerInterceptor進行攔截,代碼分別是:
@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);} 復制代碼二、攔截
以及攔截部分:將request攔截下,截取其中URL及服務名,用于之后調用負載均衡方法時,選擇合適的服務實例
@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));} 復制代碼三、根據負載均衡器調用服務實例
至此,調用RibbonLoadBalancerClient中的execute方法,先查看一下RibbonLoadBalancerClient類:
其中LoadBalancerClient接口,有如下三個方法,其中excute()為執行請求,reconstructURI()用來重構url。
ServiceInstanceChooser接口,主要有一個方法,用來根據serviceId來獲取ServiceInstance。
它繼承了ServiceInstanceChooser及LoadBalancerClient類,最終的負載均衡的請求處理,由它來執行
首先,去獲取需要加載的負載均衡策略,通過getLoadBalancer方法執行,默認是輪詢RoundRobbinRule方式:
在獲取到負載均衡策略之后,通過getServer()方法去獲取實例,點擊進入getServer方法,發現是ILoadBalancer類去選擇服務實例。
在ILoadBalancer接口中,addServers()方法是添加一個Server集合;chooseServer()方法是根據key去獲取Server;markServerDown()方法用來標記某個服務下線;getReachableServers()獲取可用的Server集合;getAllServers()獲取所有的Server集合。
chooseServer則是由BaseLoadBalancer類進行實現:
根據代碼可以看出,具體choose方法是根據不同的負載均衡策略,會有不同的選擇方法,返回具體根據策略得到的服務實例。
最后根據服務實例,進行請求的調用。
負載均衡策略
IRule用于復雜均衡的策略,它有三個方法,其中choose()是根據key 來獲取server,setLoadBalancer()和getLoadBalancer()是用來設置和獲取ILoadBalancer的
IRule有很多默認的實現類,這些實現類根據不同的算法和邏輯來處理負載均衡。Ribbon實現的IRule有以下幾個。在大多數情況下,這些默認的實現類是可以滿足需求的,如果有特性的需求,可以自己實現。
- BestAvailableRule 選擇最小請求數
- ClientConfigEnabledRoundRobinRule 輪詢
- RandomRule 隨機選擇一個server
- RoundRobinRule 輪詢選擇server
- RetryRule 根據輪詢的方式重試
- WeightedResponseTimeRule 根據響應時間去分配一個weight ,weight越低,被選擇的可能性就越低
- ZoneAvoidanceRule 根據server的zone區域和可用性來輪詢選擇
RoundRobbinRule
那我們就先看看RoundRobbinRule類中的輪詢策略:
①首先獲取所有存活的服務列表reachableServers及所有服務列表allServers,判斷兩個list是否為空。 ②incrementAndGetModulo中則是對一個原子性變量進行+1操作,并同時進行一個CAS操作,去修改nextServerIndex值,保證輪詢的可靠性。③最后判斷服務是否可用,如果不可用,則重新進入循環。
④如果在10次循環后,仍然沒有可用的服務,則退出循環并進行警告。最后返回服務實例
RetryRule
可重試的輪詢策略如下:
可見此處多了兩行代碼:
long requestTime = System.currentTimeMillis(); long deadline = requestTime + maxRetryMillis; 復制代碼定義了500ms的總重試時間,如果服務實例獲取不到,則進入循環,在循環中每次需要判斷一下是否超過總時間
while循環中,每次都會去獲取一下服務實例,然后進行判斷,如果實例仍然沒有獲取到,則對當前線程進行Thread.yield()操作,此操作的意義是:讓出當前線程時間分片,重新爭奪時間片,讓定時任務去執行,看是否達到規定時間,如到時間,則執行interrupt()操作,退出循環
這即是可重試的策略
總體流程
Ribbon + RestTemplate 的負載平衡,流程是: 通過注解后,對url進行封裝request,攔截器對request進行攔截,然后根據負載均衡器去調用服務實例,完成負載平衡和服務調用
總結
以上是生活随笔為你收集整理的SpringCloud Ribbon源码探索学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javascript中创建对象的几种方式
- 下一篇: Java核心技术笔记 语言基础