什麼是Spring Cloud Ribbon
Spring cloud ribbon 是一個基于 HTTP 和 TCP 的用戶端負載均衡工具,它基于Netflix Ribbon 實作。通過Spring Cloud 的封裝,可以輕松的将面向服務的REST子產品請求自動轉換為用戶端負載均衡的服務調用。
Spring Cloud Ribbon 存在于每一個Spring Cloud 建構的微服務和基礎設施中。微服務間的調用,API網關的請求轉發等内容,實際上都是通過 Ribbon 來實作的,包括後續要介紹的 Feign,它也是基于Ribbon實作的工具。
一、用戶端負載均衡
負載均衡在系統架構中是一個非常重要,并且不得不去實施的内容。因為負載均衡是對系統的高可用、網絡壓力的緩解和處理能力擴容的重要手段之一。
通常說的負載均衡都指的是服務端負載均衡,其中分為硬體負載均衡和軟體負載均衡。
硬體負載均衡主要是通過在伺服器節點之間安裝專門用于負載均衡的裝置,比如F5等;(小梵阿裡雲slb是硬體負載均衡)
軟體負載均衡則是通過在伺服器上安裝一些具有負載均衡功能或子產品的軟體來完成請求分發工作,比如Nginx等。(中證報項目用過Nginx負載均衡)
硬體負載均衡的裝置或是軟體負載均衡的軟體子產品都會維護一個下挂可用的服務端清單,通過心跳監測來剔除故障的服務端節點以保證清單中都是可以正常通路的服務端節點。當用戶端發送請求到負載均衡裝置的時候,該裝置按某種算法(比如線性輪詢、按權重負載、按流量負載等)從維護的可用服務端清單中取出一台服務端的位址,然後進行轉發。
用戶端的負載均衡和服務端的負載均衡最大的不同點在于服務清單所存儲的位置。
在用戶端負載均衡中,所有用戶端節點都維護着自己要通路的服務端清單,而這些服務端的清單來自于服務注冊中心,在用戶端負載均衡中也需要心跳去維護服務端清單的健康性,這個步驟需要與服務注冊中心配合完成。
通過 Spring Cloud Ribbon 的封裝,在微服務架構中使用用戶端負載均衡調用非常簡單,需要如下兩步:
1.服務提供者隻需要啟動多個服務執行個體并注冊到一個注冊中心或是多個相關聯的服務注冊中心。
2.服務消費者直接通過調用被 @LoadBalanced 注解修飾過的 RestTemplate 來實作面向服務的接口調用。
二、RestTemplate 詳解
1、GET請求
兩種:
getForEntity:
RestTemplate restTemplate = new RestTemplate ();
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/index?name={1}",String.class,"didi");
String body = responseEntity.getBody();
getForObject:
RestTemplate restTemplate = new RestTemplate ();
String body = restTemplate .getForObject(url, String.class);
2、POST請求
三種:
postForEntity:
使用方法和 getForEntity 函數類似
postForObject :
使用方法和 getForObject 函數類似
postForLocation:
使用方法和上述類似
3、PUT請求、DELETE請求
put 、delete 作為方法名,使用方法和上述類似。
以上都有三種重載:
getForObject(String url, Class responseType, Object… uriVariables)
getForObject(String url, Class responseType, Map<String, ?> uriVariables)
getForObject(URI url, Class responseType)
三、源碼分析
Ribbon通過LoadBalacerInerceptor攔截器對RestTemplate的請求進行攔截,并利用SpringCloud的負載均衡器LoadBalancerClient将以邏輯服務名為host的URI轉換成具體的服務執行個體位址的過程。
負載均衡器
雖然Spring Cloud 中定義了LoadBalancerClient作為負載均衡器的通用接口,并且針對Ribbon實作了RibbonLoadBalancerClient,但是它在具體實作用戶端負載均衡時,是通過Ribbon的ILoadBalancer接口實作的。
負載均衡政策
Ribbon中實作了非常多的選擇政策。
IRule接口的實作:
四、配置詳解
1、自動化配置
引入依賴後,能自動化建構以下接口:
IClientConfig:Ribbon的用戶端配置
IRule:Ribbon的負載均衡政策,該政策能夠在多區域環境下選出最佳區域的執行個體進行通路。
IPing:Ribbon的執行個體檢查政策,該檢查政策是一個特殊的實作,實際上它并不會檢查執行個體是否可用,而是始終傳回true,預設認為所有服務執行個體都是可用的。
ServerList:服務執行個體清單的維護機制
ServerListFilter:服務執行個體清單過濾機制,該政策能夠優先過濾出與請求調用方處于同區域的服務執行個體。
ILoadBalancer:負載均衡器,它具備了區域感覺的能力。
上面這些自動化配置内容僅在沒有引入Spring Cloud Eureka等服務治理架構時如此,在同時引入Eureka和Ribbon依賴時,自動化配置會有一些不同。
針對一些個性化需求,也可以替換上面的預設實作。隻需要在Spring Boot應用中建立對應的實作執行個體就能覆寫這些預設的配置實作。
@Configuration
public class MyRibbonCconfiguration{
@Bean
public IPing ribbonPing(IClientConfig config){
return new PingUrl();
}
}
也可以通過使用@RibbonClient注解來實作更細粒度的用戶端配置
@Configuration
@RibbonClient(name="hello-service",configuration=HelloServiceConfiguration.class)
public class RibbonConfiguration{
}
2、Camden版本對RibbonClient配置的優化
在Camden版本中,Sping Cloud Ribbon對RibbonClient定義個性化配置的方法做了進一步優化。可以直接通過.ribbon.=的形式進行配置。
hello-service.ribbon.NFLoadBalancePingClassName=com.netflix.loadbalancer.PingUrl
3、參數配置
Ribbon的參數配置通常有兩種方式:全局配置以及指定用戶端配置。
全局配置方式隻需ribbon.=格式進行配置即可。
其中,代表了Ribbon用戶端配置的參數名,則代表了對應參數的值。比如。
我們可以向下面這樣全局配置Ribbon建立連接配接的逾時時間:
ribbon.ConnetcTimeout=250
指定用戶端的配置方式采用.ribbon.=的格式進行配置。
hello-service.ribbon.listOfServers=localhost:8001,localhost:8002,localhost:8003
4、與Eureka結合
當在Spring Cloud的應用中同時引入Spring Cloud Ribbon和Spring Cloud Eureka依賴時,會觸發Eureka中實作的對Ribbon的自動化配置。
服務清單清單由Eureka的服務治理機制來進行維護。
由于Spring Cloud Ribbon預設實作了區域親和政策,是以,可以通過Eureka執行個體的中繼資料配置來實作區域化的執行個體配置方案。比如,可以将處于不同機房的執行個體配置成不同區域值,以作為跨區域的容錯機制實作。隻需要在服務執行個體的中繼資料中增加zone參數來指定自己所在的區域:
eureka.instance.metadataMap.zone=shanghai
在Spring Cloud Ribbon與Spring Cloud Enreka結合的工程中,我們也可以通過參數配置的方式來禁用Eureka對Ribbon服務執行個體的維護實作。在配置中加如下參數,對于服務執行個體的維護就又回到了.ribbon.listOfServers參數配置的方式來實作了。
ribbon.eureka.enabled=false
五、重試機制
由于Spring Cloud Eureka實作的服務治理機制強調了CAP原理中的AP,即可用性與可靠性,它與ZooKeeper這類強調CP(一緻性、可靠性)的服務治理架構最大的差別就是,Eureka為了實作更高的服務可用性,犧牲了一定的一緻性,在極端情況下它甯願接受故障執行個體也不要丢掉“健康”執行個體。
由于Spring Cloud Eureka在可用性與一緻性上的取舍,我們還是希望能夠增強對這類問題的容錯。是以,我們在實作服務調用的時候通常會加入一些重試機制。
Spring Cloud整合了Spring Retry來增強RestTemplate的重試能力
可以在配置檔案中增加如下内容:
spring.cloud.loadbalancer.retry.enabled=true
hystrix.command.default.execution.isolation.thread.timeoutInMillseconds=10000
hello-service.ribbon.ConnetTimeout=250
hello-service.ribbon.ReadTimeout=1000
hello-service.ribbion.OkToRetryOnAllOperations=true
hello-service.ribbon.MaxAuto.RetriesNextServer=2
hello-service.ribbon.MaxAutoRetries=1
spring.cloud.loadbalancer.retry.enabled:該參數用來開啟重試機制,它預設是關閉的。
hystrix.command.default.execution.isolation.thread.timeoutInMillseconds:斷路器的逾時時間需要大于Ribbon的逾時時間,不然不會觸發重試。
hello-service.ribbon.ConnectTimeout:請求連接配接的逾時時間。
hello-service.ribbon.ReadTimeout:請求處理的逾時時間。
hello-service.ribbon.OkToRetryOnAllOperations:對所有操作請求都進行重試。
hello-service.ribbon.MaxAutoRetriesNextServer:切換執行個體的重試次數。
hello-service.ribbon.MaxAutoRetries:對目前執行個體的重試次數。
當通路到故障請求的時候,它會載嘗試通路一次目前執行個體次數(次數由MaxAutoRetries配置),如果不行,就換一個執行個體進行通路,如果還不行,再換一次執行個體通路(更換次數由MaxAutoRetriesNextServer配置),如果依然不行,傳回失敗資訊。