Ribbon單獨使用,配置自動重試,實現(xiàn)負(fù)載均衡和高可用方式
一、前言
1.1 實現(xiàn)目標(biāo)
服務(wù)A調(diào)用服務(wù)B1和B2(B1和B2提供同種服務(wù)),當(dāng)服務(wù)B1/B2在停止和重新發(fā)布階段,或B1/B2有一個服務(wù)故障時,
- 需保證服務(wù)A正常調(diào)用B服務(wù),達到無感知發(fā)布的效果(服務(wù)B高可用)
- 需保證服務(wù)A的請求負(fù)載均衡,避免某個B服務(wù)節(jié)點壓力過大(服務(wù)B負(fù)載均衡)
說明:這里是獨立使用Ribbon,不依賴于Eureka、Zookeeper等任何服務(wù)注冊發(fā)現(xiàn)組件。
1.2 環(huán)境
JDK 1.8,SpringCloud Greenwich.SR2,SpringBoot 2.1.3.RELEASE
二、實現(xiàn)
本文示例,CONSUMER-SERVICE服務(wù)調(diào)用PRODUCER-SERVICE服務(wù)。在進行以下步驟前,請先啟動兩個普通的SpringBoot服務(wù)PRODUCER-SERVICE。
2.1 pom依賴
因為這里獨立使用Ribbon,所以CONSUMER-SERVICE只需要spring-cloud-starter-netflix-ribbon,啟動主類也無需更多的注解,如
@EnableEurekaClient、@EnableDiscoveryClient、@EnableCircuitBreaker等,只需保留@SpringBootApplication即可。
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2.2 RestTemplate配置
Ribbon是對RestTemplate的加強,需要為RestTemplate添加注解@LoadBalanced,使之具有負(fù)載均衡能力。如下:
@Bean @LoadBalanced public RestTemplate restTemplate(ClientHttpRequestFactory factory) { ? ? RestTemplate restTemplate = new RestTemplate(factory); ? ? restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); ? ? return restTemplate; }
2.3 Ribbon配置
注意:網(wǎng)上和書上很多教程都沒有提到ribbon.restclient.enabled這一配置,導(dǎo)致再怎么嘗試都無法成功自動重試。
spring.application.name=CONSUMER-SERVICE server.port=8801 ? ribbon.restclient.enabled=true #開啟重試機制 spring.cloud.loadbalancer.retry.enabled=true #請求連接的超時時間 PRODUCER-SERVICE.ribbon.ConnectTimeout=250 #請求處理的超時時間 PRODUCER-SERVICE.ribbon.ReadTimeout=1000 #對所有操作請求都進行重試,默認(rèn)false,只有GET請求會重試;這是防止POST等對數(shù)據(jù)有影響的請求在重試后因為接口未做冪等性導(dǎo)致數(shù)據(jù)異常,影響較大 PRODUCER-SERVICE.ribbon.OkToRetryOnAllOperations=true #指定請求重試開關(guān),經(jīng)調(diào)試源碼該屬性未被使用,疑似bug,導(dǎo)致不論怎么設(shè)置,都是只有服務(wù)提供者的Get請求可以被自動重試 #PRODUCER-SERVICE.ribbon.RequestSpecificRetryOn=true #切換實例的重試次數(shù) PRODUCER-SERVICE.ribbon.MaxAutoRetriesNextServer=2 #對當(dāng)前實例的重試次數(shù) PRODUCER-SERVICE.ribbon.MaxAutoRetries=1 ? #服務(wù)PRODUCER-SERVICE的地址 PRODUCER-SERVICE.ribbon.listOfServers=localhost:8080,localhost:8083
2.4 Ribbon調(diào)用服務(wù)
在Controller中,注入RestTemplate,使用服務(wù)名(即spring.application.name)的方式,調(diào)用PRODUCER-SERVICE服務(wù)的GET接口,如下:
@Controller @RequestMapping("consumer/api") public class ConsumerController { ? ? @Autowired ? ? private RestTemplate restTemplate; ? ? ? @GetMapping("/test") ? ? @ResponseBody ? ? public String test() { ? ? ? ? ResponseEntity<String> entity = restTemplate ? ? ? ? ? ? ? ? .getForEntity("http://PRODUCER-SERVICE/outer/data?res=3&msgKey=token123", String.class); ? ? ? ? return entity.getBody(); ? ? } }
三、測試運行
3.1 負(fù)載均衡測試
啟動一個消費者服務(wù)CONSUMER-SERVICE,多次訪問/consumer/api/test,可以通過給PRODECER-SERVICE服務(wù)的/outer/data接口添加調(diào)試日志的打印,來確認(rèn)默認(rèn)使用了輪詢的負(fù)載均衡策略。
3.2 高可用測試
停止其中一個PRODECER-SERVICE服務(wù)實例,確認(rèn)輪詢到已停止的服務(wù)時,可以成功地在未停止的服務(wù)上自動重試請求。
四、無法成功自動重試的幾種情況
本人在單獨使用Ribbon的過程中,碰到以下幾種無法自動重試其他服務(wù)節(jié)點的情況:
4.1 ribbon.restclient.enabled
遇到Ribbon的問題,網(wǎng)上一搜,千篇一律,也不知道作者們是否親自實踐證明可用,就隨意發(fā)篇文章。言歸正傳,若不設(shè)置ribbon.restclient.enabled=true,在本人的實驗環(huán)境中是無法自動重試的。
4.2 Maven打包有警告
在SpringCloud生態(tài)的開發(fā)中,各組件往往自動依賴了很多其他的jar包,如果向Maven本地倉庫下載的過程中,網(wǎng)絡(luò)不好,就會下載到一份不完整的jar包或pom文件,最終可能會導(dǎo)致打包出錯。下面是在使用Maven打包項目時,比較常見下面的警告:
[WARNING] The POM for com.sun.jersey:jersey-core:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available
[WARNING] The POM for com.sun.jersey:jersey-client:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available
...
可以看出來,提示我們傳遞依賴將失效,所以有可能整個打包過程是SUCCESS的,但是最后啟動jar包時,卻可能報NoClassDef等缺少jar包的錯誤。因此,我們需要在打包時加上參數(shù) -X 以查看具體原因:
[WARNING] The POM for com.sun.jersey:jersey-core:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for com.sun.jersey:jersey-core:[unknown-version]
[FATAL] Non-parseable POM E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom: processing instruction can not have PITarget with reserved xml name (position: END_TAG seen ...</properties>\n\n</project>\n<?xml ... @627:7) @ E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom, line 627, column 7
[WARNING] The POM for com.sun.jersey:jersey-client:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for com.sun.jersey:jersey-client:[unknown-version]
[FATAL] Non-parseable POM E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom: processing instruction can not have PITarget with reserved xml name (position: END_TAG seen ...</properties>\n\n</project>\n<?xml ... @627:7) @ E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom, line 627, column 7
[WARNING] The POM for com.sun.jersey.contribs:jersey-apache-client4:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for com.sun.jersey.contribs:jersey-apache-client4:[unknown-version]
[FATAL] Non-parseable POM E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom: processing instruction can not have PITarget with reserved xml name (position: END_TAG seen ...</properties>\n\n</project>\n<?xml ... @627:7) @ E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom, line 627, column 7
特別注意FATAL這個最嚴(yán)重的日志級別的信息, 日志提醒我們本地倉庫的pom文件E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom解析出錯,然后我們?nèi)ゴ四夸浵拢梢园l(fā)現(xiàn)這個文件未被下載完整。
最后的解決方式是刪除此文件的父目錄,重新打包,則會自動下載一份完整的pom文件,警告消失,打包成功。
4.3 OkToRetryOnAllOperations和RequestSpecificRetryOn失效
在上文的例子中,消費者服務(wù)調(diào)用的生產(chǎn)者服務(wù)接口是GET類型,自動重試沒有任何問題。
接著,本人嘗試讓消費者調(diào)用生產(chǎn)者服務(wù)的POST接口,同時仍然設(shè)置了ribbon.OkToRetryOnAllOperations=true,結(jié)果無法成功重試,然后去調(diào)試ribbon源碼,查看自動重試機制,經(jīng)查,OkToRetryOnAllOperations和RequestSpecificRetryOn屬性可以成功獲取到,但RequestSpecificRetryOn并未被獲取出來使用,疑似Ribbon的bug。
這里記錄一下調(diào)試的重要部分,
(1)Ribbon配置屬性類com.netflix.client.config.CommonClientConfigKey;
(2)Ribbon判斷是否重試:
所以,單獨使用Ribbon需謹(jǐn)慎!
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
FluentMybatis實現(xiàn)mybatis動態(tài)sql拼裝和fluent api語法
本文主要介紹了FluentMybatis實現(xiàn)mybatis動態(tài)sql拼裝和fluent api語法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08mybatis的insert語句插入數(shù)據(jù)時的返回值的實現(xiàn)
這篇文章主要介紹了mybatis的insert語句插入數(shù)據(jù)時的返回值的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10詳解Spring Cloud微服務(wù)架構(gòu)下的WebSocket解決方案
這篇文章主要介紹了詳解Spring Cloud微服務(wù)架構(gòu)下的WebSocket解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12SpringCloud整合分布式服務(wù)跟蹤zipkin的實現(xiàn)
這篇文章主要介紹了SpringCloud整合分布式服務(wù)跟蹤zipkin的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Java Map 按key排序和按Value排序的實現(xiàn)方法
下面小編就為大家?guī)硪黄狫ava Map 按key排序和按Value排序的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08Java中的volatile實現(xiàn)機制詳細(xì)解析
這篇文章主要介紹了Java中的volatile實現(xiàn)機制詳細(xì)解析,本文的主要內(nèi)容就在于要理解volatile的緩存的一致性協(xié)議導(dǎo)致的共享變量可見性,以及volatile在解析成為匯編語言的時候?qū)ψ兞考渔i兩塊理論內(nèi)容,需要的朋友可以參考下2024-01-01