Ribbon
Spring Cloud Ribbon是一個基於HTTP和TCP的客戶端負載均衡工具,它基於Netflix Ribbon實現。通過Spring Cloud的封裝,可以讓我們輕松地將面向服務的REST模版請求自動轉換成客戶端負載均衡的服務調用。它不像服務注冊中心、配置中心、API網關那樣需要獨立部署,但是它幾乎存在於每一個spring could構建的微服務和基礎設施中。因為微服務間的調用,API網關的請求轉發等內容,實際上都是通過Ribbon來實現的。
Ribbon是什么?
ribbon是一個http客戶端,它具備了負載均衡、失敗重試、ping等功能。比如httpclient就是一個http客戶端,它就是用來發送http請求的,但是Ribbon在httpclient上做了更多的封裝,滿足更好的使用,當然,也可以使用其他的http客戶端。所以,Ribbon並不是很多人說的負載均衡工具,而是一個具有負載均衡等功能的http客戶端。
Ribbon基本須知配置
(1)IClientConfig clientConfig:用於配置負載均衡客戶端,默認實現類是DefaultClientConfigImpl。
(2)IRule rule:用於配置負載均衡的策略,默認使用的是RoundRobinRule策略,也就是輪詢策略。
(3)IPing ping:用於檢查當前服務是否有響應,從而判斷當前服務是否可用,默認實現類是DummyPing,該實現類的isAlive()方法返回值是true,默認所有服務實例都是可用的。
(4)ServerList serverList: 用於獲取所有Server注冊列表信息。通過跟蹤源碼會發現,ServerList的實現類是DiscoveryEnabledNIWSServerList,該類定義的obtainServersViaDiscovery()方法是根據eurekaClientProvider.get()方法獲取EurekaClient,再根據EurekaClient獲取服務注冊列表信息。EurekaClient的實現類是DiscoveryClient,DiscoveryClient具有服務注冊、獲取服務注冊列表等功能。
(5)ServerListFilter filter:定義了根據配置過濾或者動態獲取符合條件的服務列表,默認實現類是ZonePreferenceServerListFilter,該策略能夠優先過濾出與請求調用方處於同區域的服務實例。
ribbon基本配置
1. 禁用 Eureka
當我們在 RestTemplate 上添加 @LoadBalanced 注解后,就可以用服務名稱來調用接口了,當有多個服務的時候,還能做負載均衡。
這是因為 Eureka 中的服務信息已經被拉取到了客戶端本地,如果我們不想和 Eureka 集成,可以通過下面的配置方法將其禁用。
# 禁用 Eureka
ribbon.eureka.enabled=false
當我們禁用了 Eureka 之后,就不能使用服務名稱去調用接口了,必須指定服務地址。
2. 配置接口地址列表
上面我們講了可以禁用 Eureka,禁用之后就需要手動配置調用的服務地址了,配置如下:
# 禁用 Eureka 后手動配置服務地址
ribbon-config-demo.ribbon.listOfServers=localhost:8081,localhost:8083
這個配置是針對具體服務的,前綴就是服務名稱,配置完之后就可以和之前一樣使用服務名稱來調用接口了。
3. 配置負載均衡策略
Ribbon 默認的策略是輪詢,從我們前面講解的例子輸出的結果就可以看出來,Ribbon 中提供了很多的策略,這個在后面會進行講解。我們通過配置可以指定服務使用哪種策略來進行負載操作。
4. 超時時間
Ribbon 中有兩種和時間相關的設置,分別是請求連接的超時時間和請求處理的超時時間,設置規則如下:
# 請求連接的超時時間
ribbon.ConnectTimeout=2000
# 請求處理的超時時間
ribbon.ReadTimeout=5000
#也可以為每個Ribbon客戶端設置不同的超時時間, 通過服務名稱進行指定:
ribbon-config-demo.ribbon.ConnectTimeout=2000
ribbon-config-demo.ribbon.ReadTimeout=5000
5. 並發參數
# 最大連接數
ribbon.MaxTotalConnections=500
# 每個host最大連接數
ribbon.MaxConnectionsPerHost=500
代碼配置 Ribbon
配置 Ribbon 最簡單的方式就是通過配置文件實現。當然我們也可以通過代碼的方式來配置。
通過代碼方式來配置之前自定義的負載策略,首先需要創建一個配置類,初始化自定義的策略,代碼如下所示。
@Configurationpublic class BeanConfiguration { @Bean public MyRule rule() { return new MyRule(); }}
創建一個 Ribbon 客戶端的配置類,關聯 BeanConfiguration,用 name 來指定調用的服務名稱,代碼如下所示。
純文本復制
@RibbonClient(name = "ribbon-config-demo", configuration = BeanConfiguration.class)public class RibbonClientConfig {}
重試機制
在集群環境中,用多個節點來提供服務,難免會有某個節點出現故障。用 Nginx 做負載均衡的時候,如果你的應用是無狀態的、可以滾動發布的,也就是需要一台台去重啟應用,這樣對用戶的影響其實是比較小的,因為 Nginx 在轉發請求失敗后會重新將該請求轉發到別的實例上去。
由於 Eureka 是基於 AP 原則構建的,犧牲了數據的一致性,每個 Eureka 服務都會保存注冊的服務信息,當注冊的客戶端與 Eureka 的心跳無法保持時,有可能是網絡原因,也有可能是服務掛掉了。
在這種情況下,Eureka 中還會在一段時間內保存注冊信息。這個時候客戶端就有可能拿到已經掛掉了的服務信息,故 Ribbon 就有可能拿到已經失效了的服務信息,這樣就會導致發生失敗的請求。
這種問題我們可以利用重試機制來避免。重試機制就是當 Ribbon 發現請求的服務不可到達時,重新請求另外的服務。
1. RetryRule 重試
解決上述問題,最簡單的方法就是利用 Ribbon 自帶的重試策略進行重試,此時只需要指定某個服務的負載策略為重試策略即可:
ribbon-config-demo.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RetryRule
2. Spring Retry 重試
除了使用 Ribbon 自帶的重試策略,我們還可以通過集成 Spring Retry 來進行重試操作。
在 pom.xml 中添加 Spring Retry 的依賴,代碼如下所示。
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
配置重試次數等信息:
# 對當前實例的重試次數
ribbon.maxAutoRetries=1
# 切換實例的重試次數
ribbon.maxAutoRetriesNextServer=3
# 對所有操作請求都進行重試
ribbon.okToRetryOnAllOperations=true
# 對Http響應碼進行重試
ribbon.retryableStatusCodes=500,404,502
Feign
Feign是一個聲明式WebService客戶端。使用Feign能讓編寫Web Service客戶端更加簡單, 它的使用方法是定義一個接口,然后在上面添加注解,同時也支持JAX-RS標准的注解。Feign也支持可拔插式的編碼器和解碼器。SpringCloud對Feign進行了封裝,使其支持了Spring MVC標准注解和HttpMessageConverters。Feign可以與Eureka和Ribbon組合使用以支持負載均衡。
Feign能干什么
Feign旨在是編寫Java Http客戶端變得更加容易。
- Feign 是聲明式的web service客戶端,它讓微服務之間的調用變得更加簡單了
- SpringCloud集成了Ribbon和Eureka,可在使用Feign時提供負載均衡的http客戶端
- 使用起來也比ribbon方便很多,只需要創建接口,然后使用注解@FeignClient("服務名")即可
Feign的用途
- 因為在實際開發中,由於對服務依賴的調用可能不止一處,往往一個接口會被多處調用,所以通常都會針對每個微服務自行封裝一些客戶端類來包裝這些依賴服務的調用,Feign在此基礎上進行了進一步的封裝,由他來幫助我們定義和實現依賴服務接口的定義
- 在Feign的是線下,我們只需要創建一個接口並使用注解的方式來裝配它@FeignClient("服務名"),即可完成對服務提供方的接口綁定,簡化了Ribbon自動封裝服務調用客戶端的開發量
Feign與Ribbon的關系
- Feign集成了Ribbon
- Feign利用了Ribbon維護了服務列表信息,並且通過輪詢的方式實現了客戶端的負載均衡,而與Ribbon不同的是,通過Feign只需要定義服務綁定接口且以聲明式的方法,更加簡單的實現了服務的調用
Feign實現遠程調用流程圖:
Feign解決什么問題
Feign旨在是編寫java http客戶端變得更加容易,Feign簡化了RestTemplate代碼,實現了Ribbon負載均衡,使代碼變得更加簡潔,也少了客戶端調用的代碼,使用Feign實現負載均衡是首先方案。只需要你創建一個接口,然后在上面添加注解即可。
Feign是聲明式服務調用組件,其核心就是:像調用本地方法一樣調用遠程方法,無感知遠程HTTP請求。
-
它解決了讓開發者調用遠程接口就跟調用本地方法一樣的體驗,開發者完全感知不到這是遠程方法,更感知不到這是HTTP請求。無需關注與遠程的交互細節,更無需關注分布式環境開發。
-
它像Dubbo一樣,Consumer直接調用Provider接口方法,而不需要通過常規的Http Client構造請求再解析返回數據。
Feign vs OpenFeign
-
OpenFeign是Spring Cloud在Feign的基礎上支持了SpringMVC的注解,如果@RequstMapping、@Pathvariable等等。
-
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,並通過動態代理的方式產生實效類,實效類中做負載均衡並調用服務。