久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Ribbon如何使用

194次閱讀
沒有評論

共計 9268 個字符,預計需要花費 24 分鐘才能閱讀完成。

這篇“Ribbon 如何使用”文章的知識點大部分人都不太理解,所以丸趣 TV 小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Ribbon 如何使用”文章吧。

Ribbon 基本使用簡介

Ribbon 是一個客戶端負載均衡工具,封裝 Netflix Ribbon 組件,能夠提供客戶端負載均衡能力。

理解 Ribbon 最重要的就是理解客戶端這個概念,所謂客戶端負載均衡工具不同于 Nginx(服務端負載均衡),Ribbon 和應用程序綁定,本身不是獨立的服務,也不存儲服務列表,需要負載均衡的時候,會通過應用程序獲取注冊服務列表,然后通過列表進行負載均衡和調用。

Nginx 獨立進程做負載均衡,通過負載均衡策略,將請求轉發到不同的服務上

客戶端負載均衡,通過在客戶端保存服務列表信息,然后自己調用負載均衡策略,分攤調用不同的服務

基本使用

Ribbon 的負載均衡有兩種方式

和 RestTemplate 結合 Ribbon+RestTemplate

和 OpenFeign 結合

Ribbon 的核心子模塊

ribbon-loadbalancer:可以獨立使用或者和其他模塊一起使用的負載均衡 API

ribbon-core:Ribbon 的核心 API

訂單服務集成 Ribbon

訂單服務調用商品服務

配置過程 分兩步

在訂單服務中導入 ribbon 的依賴

!--ribbon-- 
 dependency 
  groupId org.springframework.cloud /groupId 
  artifactId spring-cloud-starter-netflix-ribbon /artifactId 
 /dependency

配置 RestTemplate

訂單服務調用商品服務

訂單服務調用商品服務的鏈接 不能寫成 ip+ 端口號,需要寫成商品服務的服務名稱

重啟 訂單服務 測試負載均衡

Ribbon 負載均衡簡單版實現的流程

RestTemplate 發送的請求是服務名稱 http://nacos-product/product/getProductById/1

獲取 @LoadBalanced 注解標記的 RestTemplate

RestTemplate 添加一個攔截器,當使用 RestTemplate 發起 http 調用時進行攔截

根據 url 中的服務名稱 以及自身的負載均衡策略 去訂單服務的服務列表中找到一個要調用的 ip+ 端口號 localhost:8802

訪問該目標服務,并獲取返回結果

服務列表實際上是個 map

Ribbon 負載均衡原理 [了解]獲取 @LoadBalanced 注解標記的 RestTemplate。

Ribbon 將所有標記 @LoadBalanced 注解的 RestTemplate 保存到一個 List 集合當中,具體源碼如下:

@LoadBalanced
@Autowired(required = false)
private List RestTemplate  restTemplates = Collections.emptyList();

具體源碼位置是在 LoadBalancerAutoConfiguration 中。

RestTemplate 添加一個攔截器

攔截器不是 Ribbon 的功能

RestTemplate 添加攔截器需要有兩個步驟,首先是定義一個攔截器,其次是將定義的攔截器添加到 RestTemplate 中。

定義一個攔截器

實現 ClientHttpRequestInterceptor 接口就具備了攔截請求的功能,該接口源碼如下:

public interface ClientHttpRequestInterceptor {
 /**
 * 實現該方法,在該方法內完成攔截請求后的邏輯內容。 * 對于 ribbon 而言,在該方法內完成了根據具體規則從
 * 服務集群中選取一個服務,并向該服務發起請求的操作。 */
 ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
}

ribbon 中對應的實現類是 LoadBalancerInterceptor 具體源碼如下:

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
 private LoadBalancerClient loadBalancer;
 private LoadBalancerRequestFactory requestFactory;
 // 省略構造器代碼...
 @Override
 public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
 final ClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI();
 String serviceName = originalUri.getHost();
 /**
 * 攔截請求,并調用 loadBalancer.execute()方法
 * 在該方法內部完成 server 的選取。向選取的 server
 * 發起請求,并獲得返回結果。 */
 return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
 }
}

將攔截器添加到 RestTemplate 中

RestTemplate 繼承了 InterceptingHttpAccessor,在 InterceptingHttpAccessor 中提供了獲取以及添加攔截器的方法,具體源碼如下:

public abstract class InterceptingHttpAccessor extends HttpAccessor {
 /**
 *  所有的攔截器是以一個 List 集合形式進行保存。 */
 private List ClientHttpRequestInterceptor  interceptors = new ArrayList ClientHttpRequestInterceptor 
 /**
 *  設置攔截器。 */
 public void setInterceptors(List ClientHttpRequestInterceptor  interceptors) {
 this.interceptors = interceptors;
 }
 /**
 *  獲取當前的攔截器。 */
 public List ClientHttpRequestInterceptor  getInterceptors() {
 return interceptors;
 }
 // 省略部分代碼...
}

通過這兩個方法我們就可以將剛才定義的 LoadBalancerInterceptor 添加到有 @LoadBalanced 注解標識的 RestTemplate 中。具體的源碼如下 (LoadBalancerAutoConfiguration) 省略部分代碼:

public class LoadBalancerAutoConfiguration {
 /**
 *  獲取所有帶有 @LoadBalanced 注解的 restTemplate
 */
 @LoadBalanced
 @Autowired(required = false)
 private List RestTemplate  restTemplates = Collections.emptyList();
 /**
 *  創建 SmartInitializingSingleton 接口的實現類。Spring 會在所有
 *  單例 Bean 初始化完成后回調該實現類的 afterSingletonsInstantiated()
 *  方法。在這個方法中會為所有被 @LoadBalanced 注解標識的
 * RestTemplate 添加 ribbon 的自定義攔截器 LoadBalancerInterceptor。 */
 @Bean
 public SmartInitializingSingleton loadBalancedRestTemplateInitializer( final List RestTemplateCustomizer  customizers) { return new SmartInitializingSingleton() {
 @Override
 public void afterSingletonsInstantiated() { for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) { for (RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate);
 }
 }
 }
 };
 }
 /**
 *  創建 Ribbon 自定義攔截器 LoadBalancerInterceptor
 *  創建前提是當前 classpath 下不存在 spring-retry。 *  所以 LoadBalancerInterceptor 是默認的 Ribbon 攔截
 *  請求的攔截器。 */
 @Configuration
 @ConditionalOnMissingClass(org.springframework.retry.support.RetryTemplate)
 static class LoadBalancerInterceptorConfig {
 @Bean
 public LoadBalancerInterceptor ribbonInterceptor(
 LoadBalancerClient loadBalancerClient,
 LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
 }
 /**
 *  添加攔截器具體方法。首先獲取當前攔截器集合(List)
 *  然后將 loadBalancerInterceptor 添加到當前集合中
 *  最后將新的集合放回到 restTemplate 中。 */
 @Bean
 @ConditionalOnMissingBean
 public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return new RestTemplateCustomizer() {
 @Override
 public void customize(RestTemplate restTemplate) {
 List ClientHttpRequestInterceptor  list = new ArrayList ( restTemplate.getInterceptors());
 list.add(loadBalancerInterceptor);
 restTemplate.setInterceptors(list);
 }
 };
 }
 }
}

至此知道了 ribbon 攔截請求的基本原理,接下來我們看看 Ribbon 是怎樣選取 server 的。

Ribbon 選取 server 原理概覽

通過上面的介紹我們知道了當發起請求時 ribbon 會用 LoadBalancerInterceptor 這個攔截器進行攔截。在該攔截器中會調用 LoadBalancerClient.execute()方法,該方法具體代碼如下:

@Override
public  T  T execute(String serviceId, LoadBalancerRequest T  request) throws IOException {
 /**
 * 創建 loadBalancer 的過程可以理解為組裝選取服務的規則(IRule)、 * 服務集群的列表 (ServerList)、檢驗服務是否存活(IPing) 等特性
 * 的過程(加載 RibbonClientConfiguration 這個配置類),需要注意
 * 的是這個過程并不是在啟動時進行的,而是當有請求到來時才會處理。 */
 ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
 /**
 *  根據 ILoadBalancer 來選取具體的一個 Server。 *  選取的過程是根據 IRule、IPing、ServerList
 *  作為參照。 */
 Server server = getServer(loadBalancer);
 if (server == null) { throw new IllegalStateException( No instances available for   + serviceId);
 }
 RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
 serviceId), serverIntrospector(serviceId).getMetadata(server));
 return execute(serviceId, ribbonServer, request);
}

通過代碼我們可知,首先創建一個 ILoadBalancer,這個 ILoadBalancer 是 Ribbon 的核心類。可以理解成它包含了選取服務的規則 (IRule)、服務集群的列表(ServerList)、檢驗服務是否存活(IPing) 等特性,同時它也具有了根據這些特性從服務集群中選取具體一個服務的能力。Server server = getServer(loadBalancer); 這行代碼就是選取舉一個具體 server。最終調用了內部的 execute 方法,該方法代碼如下(只保留了核心代碼):

@Override
public  T  T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest T  request) throws IOException {
 try {
 // 發起調用
 T returnVal = request.apply(serviceInstance);
 statsRecorder.recordStats(returnVal);
 return returnVal;
 }
 catch (IOException ex) { statsRecorder.recordStats(ex);
 throw ex;
 }
 catch (Exception ex) { statsRecorder.recordStats(ex);
 ReflectionUtils.rethrowRuntimeException(ex);
 }
 return null;
}

接下來看下 request.apply(serviceInstance)方法的具體做了那些事情(LoadBalancerRequestFactory 中):

@Override
public ClientHttpResponse apply(final ServiceInstance instance)
 throws Exception { HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
 // 省略部分代碼...
 /**
 *  發起真正請求。 */
 return execution.execute(serviceRequest, body);
}

看到這里整體流程的原理就說完了,接下來我們結合一張圖來回顧下整個過程:

首先獲取所有標識 @LoadBalanced 注解的 RestTemplate(可以理解成獲取那些開啟了 Ribbon 負載均衡功能的 RestTemplate),然后將 Ribbon 默認的攔截器 LoadBalancerInterceptor 添加到 RestTemplate 中,這樣當使用 RestTemplate 發起 http 請求時就會起到攔截的作用。當有請求發起時,ribbon 默認的攔截器首先會創建 ILoadBalancer(里面包含了選取服務的規則 (IRule)、服務集群的列表(ServerList)、檢驗服務是否存活(IPing) 等特性)。在代碼層面的含義是加載 RibbonClientConfiguration 配置類)。然后使用 ILoadBalancer 從服務集群中選擇一個服務,最后向這個服務發送請求。

Ribbon 負載均衡規則

參考資料:https://www.jianshu.com/p/79b9cf0d0519

Ribbon 默認負載均衡規則

根據上述 Ribbon 的原理,可以知道 IRule 接口負責負載均衡的實現,具體如下:

規則名稱特點 AvailabilityFilteringRule 過濾掉一直連接失敗的被標記為 circuit tripped 的后端 Server,并 過濾掉那些高并發的后端 Server 或者使用一個 AvailabilityPredicate 來包含過濾 server 的邏輯,其實就是檢查 status 里記錄的各個 server 的運行狀態 BestAvailableRule 選擇一個最小的并發請求的 server,逐個考察 server,如果 Server 被 tripped 了,則跳過 RandomRule 隨機選擇一個 ServerResponseTimeWeightedRule 已廢棄,作用同 WeightedResponseTimeRuleWeightedResponseTimeRule 權重根據響應時間加權,響應時間越長,權重越小,被選中的可能性越低 RetryRule 對選定的負載均衡策略加上重試機制,在一個配置時間段內當 選擇 Server 不成功,則一直嘗試使用 subRule 的方式選擇一個 可用的 ServerRoundRobinRule 輪詢選擇,輪詢 index,選擇 index 對應位置的 ServerZoneAvoidanceRule 默認的負載均衡策略,即復合判斷 Server 所在區域的性能和 Server 的可用性 選擇 Server,在沒有區域的環境下,類似于輪詢(RandomRule)

其中 RandomRule 表示隨機策略、RoundRobinRule 表示輪詢策略、WeightedResponseTimeRule 表示加權策略、BestAvailableRule 表示請求數最少策略等等

隨機源碼:

輪詢源碼:

修改默認的自定義規則

默認是輪詢 可以修改為任意的規則

修改為隨機算法

創建具有負載均衡功能的 RestTemplate 實例

[@Bean](https://my.oschina.net/bean)
@LoadBalanced
public RestTemplate restTemplate() { return new RestTemplate();
}

使用 RestTemplate 進行 rest 操作的時候,會自動使用負載均衡策略,它內部會在 RestTemplate 中加入 LoadBalancerInterceptor 這個攔截器,這個攔截器的作用就是使用負載均衡。

默認情況下會采用輪詢策略,如果希望采用其它策略,則指定 IRule 實現,如:

[@Bean](https://my.oschina.net/bean)
public IRule ribbonRule() { return new BestAvailableRule();
}

這種方式對 OpenFeign 也有效。

修改為按照 Nacos 配置的權重進行負載均衡

在 nacos 中對集群進行權重的配置

Ribbon 如何使用

Ribbon 如何使用

Ribbon 如何使用

在項目中,選擇使用 NacosRule

Ribbon 如何使用

Ribbon 實戰優化饑餓加載

Ribbon 默認懶加載,意味著只有在發起調用的時候才會創建客戶端

ribbon:
 eager-load:
 #  開啟 ribbon 饑餓加載
 enabled: true
 #  配置 user-center 使用 ribbon 饑餓加載,多個使用逗號分隔
 clients: user-center

參數調優

主要調整請求的超時時間,是否重試

如果業務沒有做冪等性的話建議把重試關掉:ribbon.MaxAutoRetriesNextServer=0

#  從注冊中心刷新 servelist 的時間   默認 30 秒,單位 ms
ribbon.ServerListRefreshInterval=15000
#  請求連接的超時時間   默認 1 秒,單位 ms
ribbon.ConnectTimeout=30000
#  請求處理的超時時間   默認 1 秒,單位 ms
ribbon.ReadTimeout=30000
#  對所有操作請求都進行重試, 不配置這個 MaxAutoRetries 不起作用   默認 false
#ribbon.OkToRetryOnAllOperations=true
#  對當前實例的重試次數   默認 0
# ribbon.MaxAutoRetries=1
#  切換實例的重試次數   默認 1
ribbon.MaxAutoRetriesNextServer=0

如果 MaxAutoRetries= 1 和 MaxAutoRetriesNextServer= 1 請求在 1s 內響應,超過 1 秒先同一個服務器上重試 1 次,如果還是超時或失敗,向其他服務上請求重試 1 次。

那么整個 ribbon 請求過程的超時時間為:ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1)

以上就是關于“Ribbon 如何使用”這篇文章的內容,相信大家都有了一定的了解,希望丸趣 TV 小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注丸趣 TV 行業資訊頻道。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-04發表,共計9268字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 大埔区| 永年县| 永兴县| 福鼎市| 松潘县| 南郑县| 福泉市| 蓬溪县| 新兴县| 尚义县| 呼和浩特市| 泌阳县| 淅川县| 柳河县| 施秉县| 闸北区| 密云县| 博兴县| 乌恰县| 沭阳县| 田林县| 万宁市| 道真| 长宁区| 万年县| 景洪市| 甘德县| 呼伦贝尔市| 济南市| 奉化市| 卢湾区| 拜城县| 黎平县| 湘乡市| 东辽县| 德钦县| 富锦市| 米泉市| 横峰县| 息烽县| 滨海县|