Spring Cloud Eureka Ribbon
Spring Cloud基礎教程[Eureka叢集,Ribbon負載均衡]
Spring Cloud Ribbon
Spring Cloud Ribbon是一個基於HTTP和TCP的客戶端負載均衡工具,它基於Netflix Ribbon實現。通過Spring Cloud的封裝,可以讓我們輕鬆地將面向服務的REST模板請求自動轉換成客戶端負載均衡的服務呼叫。Spring Cloud Ribbon雖然只是一個工具類框架, 它不像服務註冊中心、配置中心、API閘道器那樣需要獨立部署,但是它幾乎存在於每一個 SpringCloud構建的微服務和基礎設施中。因為微服務間的呼叫,API閘道器的請求轉發等內容,實際上都是通過Ribbon來實現的,包括後續我們將要介紹的Feign,它也是基於Ribbon 實現的工具。所以,對Spring Cloud Ribbon的理解和使用,對於我們使用Spring Cloud來構建微服務非常重要。
在這一章中,我們將具體介紹如何使用Ribbon來實現客戶端的負錢均衡,並且通過原始碼分析來了解Ribbon實現客戶端負載均衡的基本原理.
客戶端負載均衡
負載均衡在系統架構中是一個非常重要,並且是不得不去實施的內容因為負載均衡是對系統的高可用、M絡壓力的緩解和處理能力擴容的重要手段之一。我們通常所說的負載均衡都指的是服務端負載均衡,其中分為硬體負載均衡和軟體負載均衡。硬體負載均衡主要通過在伺服器節點之間安裝專門用於負載均衡的裝置,比如F5等:而軟體負載均衡則是通過在伺服器上安裝一些具有均衡負載功能或模組的軟體來完成請求分發工作,比如Nginx等。不論採用硬體負載均衡還是軟體負載均衡,只要是服務端負載均衡都能以類似下圖的架構力+忒構建起來:
硬體負載均衡的裝置或是軟體負載均衡的軟體模組都會維護一個下掛可用的服務端清單,通過心跳檢測來剔除故障的服務端節點以保證清單中都是可以正常訪問的服務端節點,當客戶端傳送請求到負載均衡裝置的時候,該裝置按某種演算法(比如線性輪詢、按權審負我、按流最負載等)從維護的可用服務端清單中取出一臺服務端的地址,然後進行轉發。而客戶端負載均衡和眼務端負或均衡M大的不同點在於上面所提到的服務清單所儲存的位置。在客屍端負載均衡中,所有客戶端節點都維護著自己要訪問的服務端清單,而這服務端的清單來自於服務註冊中心,比如上一章我們介紹的Eureka服務端.同服務端負載均 衡的架構類似,在客戶端負載均衡中也需要心跳去維護服務端清單的健康性,只是這〜步騍需要與服務註冊中心配合完成。在Spring Cloudd實現服務治理框架中,預設會建立針對各 個服務'冶理框架的Ribbon自動化整合配置,比如Eureka中 的org.springframework. cloud.netflix. ribbon.eureka.RibbonEurekaAutoConfiguration,Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAuto-Configuration。在實際使用的時候,我們可以通過檢視這兩個類的實現,以找到它們 的配置詳情來幫助我們更好地使用它。通過Spring Cloud Ribbon的封裝,我們在微服務架構中使用客戶端負找均衡呼叫非常 簡單,只需要如下兩步:
• 服務提供者R潘要啟動多個服務例項並註冊到一個註冊中心或是多a相關聯的服務註冊中心。
• 服務消費者直接通過呼叫註解修飾過的 RcstTemplate來實現面 向服務的介面呼叫。
這樣,我們就可以將服務提供者的高可用以及服務消費者的負載均衡呼叫一起實現.
動手試一試 【Dalston版】
下面我們通過具體的例子來看看如何使用Spring Cloud Ribbon來實現服務的呼叫以及客戶端均衡負載。
下面的例子,我們將利用之前構建的eureka-server
作為服務註冊中心(3個節點)、springcloud-provider作為服務提供者作為基礎。而基於Spring Cloud Ribbon實現的消費者,我們可以根據springcloud-consumer
實現的內容進行簡單改在就能完成,具體步驟如下:
根據上一篇文章的基礎上進行直接負載均衡:https://blog.csdn.net/weixin_40470497/article/details/83588369 ,上一篇文章只是建立了一個提供者埠為:8080,在建立相同的服務提供者springcloud-provider2,在application.yml配置檔案中修改一下埠:8081
專案已上傳github:[email protected]:13849141963/spring-cloud.git
直接搭建客戶端進行負載均衡,客戶端為:springcloud-consumer,pom.xml檔案內容如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--eureka服務註冊中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!--ribbon基於客戶端的負載均衡器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
-
新增配置類:在
RestTemplate
增加@LoadBalanced
註解:
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced//基於客戶端的負載均衡器
public RestTemplate restTemplate() {
return new RestTemplate();
}
//將jackson轉化成fastjson
@Bean
public HttpMessageConverters fastJsonConfigure(){
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
//日期格式化
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
converter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(converter);
}
}
- 修改Controller。去掉原來通過
LoadBalancerClient
選取例項和拼接URL的步驟,直接通過RestTemplate發起請求。
@RestController
public class UserController {
//服務的應用名稱
private final String url = "http://springcloud-provider";
//使用restTemplate對rest介面進行呼叫 封裝的物件
//RestTemplate物件提供了多種便捷訪問遠端http服務的方法 是一種簡單便捷的restful服務模板類,是spring提供的用於訪問rest服務的客戶端模板類
@Autowired
private RestTemplate restTemplate;
//呼叫服務端的查詢所有的服務
@RequestMapping(value = "/queryAll")
public Object queryAll(){
System.out.println("==========進入訪問方法============");
List forObject = restTemplate.getForObject(url+"/queryAll", List.class);
return forObject;
}
}
通過位址列交替傳送GET請求服務的消費者:10.0.45.103:8989/spring-consumer/queryAll。可以在分別兩個服務的提供者控制上看到列印如下資訊,Roibbon輸出了當前客戶端維護的springcloud-provider服務列表情況,其中包含了兩個例項的位置,Ribbon就是按照此資訊進行輪詢訪問,已實現基於客戶端的負載均衡。另外還輸出以一些非常有用的訊息,如對各個例項的請求總數量,第一次連線資訊,上一次連線資訊,總的請求失敗數量等。如圖所示:
假如一臺伺服器宕機了,客戶端基於負載均衡訪問還是能輪詢到宕機的伺服器,因為註冊中心不能立刻發現服務宕機,預設30秒後就會發現,此時客戶端請求註冊中心就會出現一臺服務的地址,這種問題可以配合springcloud Hystrix熔斷器去做。
Ribbon負載均衡策略
1.BestAvailableRule 選擇一個最小的併發請求的server,逐個考察Server,如果Server被tripped了,則忽略,在選擇其中ActiveRequestsCount最小的server
2.AvailabilityFilteringRule 過濾掉那些因為一直連線失敗的被標記為circuit,tripped的後端server,並過濾掉那些高併發的的後端server(active connections 超過配置的閾值) 使用一個AvailabilityPredicate來包含過濾server的邏輯,其實就就是檢查status 裡記錄的各個server的執行狀態
3.WeightedResponseTimeRule 根據響應時間分配一個weight,響應時間越長,weight越小,被選中的可能性越低。一個後臺執行緒定期的從status裡面讀取評價響應時間,為每個server計算一個weight。Weight的計算也比較簡單responsetime 減去每個server自己平均的responsetime是server的權重。當剛開始執行,沒有形成status時,使用roubine策略選擇server。
4.RetryRule 對選定的負載均衡策略機上重試機制。在一個配置時間段內當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server
5.RoundRobinRule roundRobin方式輪詢選擇server,輪詢index,選擇index對應位置的server
6.RandomRule 隨機選擇一個server,在index上隨機,選擇index對應位置的server
7.ZoneAvoidanceRule 複合判斷server所在區域的效能和server的可用性選擇server,使用ZoneAvoidancePredicate和AvailabilityPredicate來判斷是否選擇某個server,前一個判斷判定一個zone的執行效能是否可用,剔除不可用的zone(的所有 server),AvailabilityPredicate用於過濾掉連線數過多的Server。
自定義策略
這裡我們隊客戶端ribbon模組進行修改:假定這次修改為隨機訪問RandomRule。
案例如下:
修改配置檔案
server:
port: 8989
tomcat:
uri-encoding: UTF-8
context-path: /springcloud-consumer
eureka:
client:
service-url:
defaultZone: http://peer1:1111/eureka/,http://peer3:3333/eureka/,http://peer2:2222/eureka/
spring:
application:
name: springcloud-consumer
http:
encoding:
enabled: true
charset: UTF-8
force: true
#自定義ribbon的負載均衡策略
client:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
在配置檔案中,我們指明瞭本專案springcloud-consumer服務要使用 com.netflix.loadbalancer.RandomRule
策略。
修改啟動類,加了例項化與配置檔案對應的策略類。
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced//基於客戶端的負載均衡器
public RestTemplate restTemplate() {
return new RestTemplate();
}
//將jackson轉化成fastjson
@Bean
public HttpMessageConverters fastJsonConfigure(){
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
//日期格式化
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
converter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(converter);
}
//自定義ribbon的負載均衡策略
@Bean
public IRule ribbonRule() {
return new RandomRule();//例項化與配置檔案對應的策略類
}
}
編寫controller
@RestController
public class UserController {
private final String url = "http://springcloud-provider";
//使用restTemplate對rest介面進行呼叫 封裝的物件
//RestTemplate物件提供了多種便捷訪問遠端http服務的方法 是一種簡單便捷的restful服務模板類,是spring提供的用於訪問rest服務的客戶端模板類
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
//呼叫服務端的查詢所有的服務
@RequestMapping(value = "/cs")
public Object cs(){
System.out.println("==========進入訪問方法============");
this.loadBalancerClient.choose("client");//隨機訪問策略
List forObject = restTemplate.getForObject(url+"/queryAll", List.class);
return forObject;
}
}
啟動測試通過服務的提供者springcloud-provider和springcloud-provider2的控制檯可以發現於隨機數與輪訓[預設]的方式有明顯的不同。總結一句:根據不同的業務需求選擇不同的負載均衡策略.
重試機制
大多數情況下,上面的實現沒有任何問題,但是總有一些意外發生,比如:有一個例項發生了故障而該情況還沒有被服務治理機制及時的發現和剔除,這時候客戶端訪問該節點的時候自然會失敗。所以,為了構建更為健壯的應用系統,我們希望當請求失敗的時候能夠有一定策略的重試機制,而不是直接返回失敗。這個時候就需要開發人員人工的來為上面的RestTemplate呼叫實現重試機制。
1、首先我們啟動eureka叢集
2、再啟動服務的提供者springcloud-provider,服務的提供者準備兩臺
3、通過配置客戶端ribbon負載均衡呼叫服務端,我們將一臺服務的提供者宕機,通過客戶端呼叫發現當呼叫到宕機的那臺服務提供者,客戶端就會丟擲異常資訊無法進行連線:Connection refused: connect
4、我們來配置下客戶端的重試機制,Spring Cloud整合了Spring Retry來實現重試邏輯,而對於開發者只需要做一些配置即可。
在客戶端新增如下配置:
spring.cloud.loadbalancer.retry.enabled=true
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
hello-service.ribbon.ConnectTimeout=250
hello-service.ribbon.ReadTimeout=1000
hello-service.ribbon.OkToRetryOnAllOperations=true
hello-service.ribbon.MaxAutoRetriesNextServer=2
hello-service.ribbon.MaxAutoRetries=1
各項引數說明:
1)、spring.cloud.loadbalancer.retry.enabled:該引數用來開啟重試機制,它預設是關閉的。這裡需要注意,官方文件中的配置引數少了enabled。
2)、hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:斷路器的超時時間需要大於ribbon的超時時間,不然不會觸發重試。
3)、hello-service.ribbon.ConnectTimeout:請求連線的超時時間
4)、hello-service.ribbon.ReadTimeout:請求處理的超時時間
5)、hello-service.ribbon.OkToRetryOnAllOperations:對所有操作請求都進行重試
6)、hello-service.ribbon.MaxAutoRetriesNextServer:切換例項的重試次數
7)、hello-service.ribbon.MaxAutoRetries:對當前例項的重試次數
5、根據如上配置,當訪問到服務提供者故障的時候,它會再嘗試訪問一次當前例項(次數由MaxAutoRetries
配置),如果不行,就換一個例項進行訪問,在這裡我只是模仿一臺提供者宕機。如果兩臺服務的提供者都宕機了,先進行訪問,訪問失敗再換一次例項訪問(更換次數由MaxAutoRetriesNextServer
配置),如果依然不行,返回失敗資訊。