最近開發(fā)在解決Api接口超時(shí)問(wèn)題時(shí),發(fā)現(xiàn)我們的網(wǎng)關(guān)重試機(jī)制沒有生效,網(wǎng)關(guān)配置如下:
spring: cloud: loadbalancer: retry: enabled: true ribbon: ConnectTimeout: 1000 ReadTimeout: 1000 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1 OkToRetryOnAllOperations: false hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 4000 zuul: ignored-services: '*' semaphore: max-semaphores: 500 routes: blog_atang: path: /atang/** serviceId: blog-atang sensitiveHeaders: "*"
我聽到?jīng)]生效也比較詫異,因?yàn)閰?shù)都是正確的,至少實(shí)際使用過(guò)程中已經(jīng)證明超時(shí)參數(shù)已經(jīng)生效了,然而和開發(fā)再次一起測(cè)試,果然沒有觸發(fā)重試。又網(wǎng)上查了一些資料,總結(jié)網(wǎng)上的各種文檔一共有3個(gè)重試開關(guān)和一種重試策略。
第一個(gè)開關(guān):ribbon.restclient.enabled=true ,這個(gè)不知道是不是SpringBoot版本的問(wèn)題,我們加了以后也沒有觸發(fā)重試(我們的版本是SpringCloud Edgware.SR6,SpringBoot 1.5.22),但網(wǎng)上有篇文章使用的SpringCloud Greenwich.SR2,SpringBoot 2.1.3.RELEASE,開啟以后可以正常重試。
第二個(gè)開關(guān):spring.cloud.loadbalancer.retry.enabled=true,有文章說(shuō)這個(gè)參數(shù)可以開啟重試機(jī)制(默認(rèn)值為false),但實(shí)際上我們默認(rèn)就配置為true了,為了測(cè)試這個(gè)參數(shù)的效果,改成false以后,接口直接無(wú)法訪問(wèn)了,此次問(wèn)題主要是解決重試,所以就沒有去查看源碼深入研究此參數(shù)了。
第三個(gè)開關(guān):zuul.retryable=true,這個(gè)開關(guān)需要引入spring-retry依賴才能使用:
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
但是很多文章雖然說(shuō)了要引入此依賴,但是并沒有說(shuō)配置zuul.retryable=true(默認(rèn)為false),所以即使引入了依賴,超時(shí)路由也不會(huì)重試。
還支持只開啟指定路由重試,配置為:zuul.routes.<routename>.retryable=true。
還有一種重試方案就是采用ribbon的重試策略,配置為:ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RetryRule,實(shí)際測(cè)試并沒有觸發(fā)重試。關(guān)于Ribbon的負(fù)載均衡策略,可以參考如下介紹:
1、BestAvailabl
選擇一個(gè)最小的并發(fā)請(qǐng)求的 Server,逐個(gè)考察 Server,如果 Server 被標(biāo)記為錯(cuò)誤,則跳過(guò),然后再選擇 ActiveRequestCount 中最小的 Server。
2、AvailabilityFilteringRule
過(guò)濾掉那些一直連接失敗的且被標(biāo)記為 circuit tripped 的后端 Server,并過(guò)濾掉那些高并發(fā)的后端 Server 或者使用一個(gè) AvailabilityPredicate 來(lái)包含過(guò)濾 Server 的邏輯。其實(shí)就是檢查 Status 里記錄的各個(gè) Server 的運(yùn)行狀態(tài)。
3、ZoneAvoidanceRule
使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 來(lái)判斷是否選擇某個(gè) Server,前一個(gè)判斷判定一個(gè) Zone 的運(yùn)行性能是否可用,剔除不可用的 Zone(的所有 Server),AvailabilityPredicate 用于過(guò)濾掉連接數(shù)過(guò)多的 Server。
4、RandomRule
隨機(jī)選擇一個(gè) Server。
5、RoundRobinRule
輪詢選擇(默認(rèn)策略),輪詢 index,選擇 index 對(duì)應(yīng)位置的 Server。
6、RetryRule
對(duì)選定的負(fù)載均衡策略機(jī)上重試機(jī)制,也就是說(shuō)當(dāng)選定了某個(gè)策略進(jìn)行請(qǐng)求負(fù)載時(shí)在一個(gè)配置時(shí)間段內(nèi)若選擇 Server 不成功,則一直嘗試使用 subRule 的方式選擇一個(gè)可用的 Server。
7、ResponseTimeWeightedRule
作用同 WeightedResponseTimeRule,ResponseTime-Weighted Rule 后來(lái)改名為 WeightedResponseTimeRule。
8、WeightedResponseTimeRule
根據(jù)響應(yīng)時(shí)間分配一個(gè) Weight(權(quán)重),響應(yīng)時(shí)間越長(zhǎng),Weight 越小,被選中的可能性越低。
總結(jié),SpringCloud 版本為Edgware.x,SpringBoot 版本為1.5.x時(shí),需要引入spring-retry,然后配置文件里面配置zuul.retryable=true,ribbon的重試參數(shù)才會(huì)生效。至于SpringBoot 2.x版本,按照網(wǎng)上有些文檔說(shuō)明設(shè)置ribbon.restclient.enabled=true就會(huì)開啟重試,這個(gè)有待實(shí)測(cè)。經(jīng)過(guò)此次問(wèn)題,更加說(shuō)明了不能太相信網(wǎng)上的文檔,而且搜索出來(lái)的文檔質(zhì)量越來(lái)越差了,千篇一律;大多數(shù)情況只要有一篇原創(chuàng)發(fā)布,過(guò)幾天就會(huì)有很多相似的文檔就出來(lái)了,大部分是平臺(tái)采集,加上沒有實(shí)際測(cè)試的復(fù)制粘貼。所以阿湯博客運(yùn)維文檔和其他技術(shù)文檔都是經(jīng)過(guò)實(shí)際測(cè)試或者親身經(jīng)歷的問(wèn)題總結(jié),如果有不全面的地方,可以留言討論。原創(chuàng)不易,復(fù)制請(qǐng)注明出處,謝謝。