Feign重試不生效問題的發(fā)現(xiàn),主要還是因?yàn)樯掀恼隆?a href="http://www.zhongjima.net/wp-content/themes/begin/inc/go.php?url=http://www.zhongjima.net/atang_4466.html" target="_blank">SpringCloud Zuul(Ribbon)重試配置不生效解決辦法》里面介紹的原因。當(dāng)我解決了Zuul重試不生效的問題,測(cè)試發(fā)現(xiàn)只有如下場(chǎng)景:zuul-->訪問A1、A2,A服務(wù)返回超時(shí),也就是說Api接口的第一級(jí)跨度超過zuul配置ribbon.ReadTimeout的值才會(huì)觸發(fā)ribbon重試。場(chǎng)景一如下圖:
場(chǎng)景二如下圖,Api接口跨度多個(gè)服務(wù)的調(diào)用:
此時(shí)ReadTimeout有兩種情況:
1、Zuul網(wǎng)關(guān)的ribbon.ReadTimeout>服務(wù)端feign.client.config.default.readTimeout。
比如:Zuul網(wǎng)關(guān)的ribbon.ReadTimeout=3000,服務(wù)端配置的feign.client.config.default.readTimeout=1000,當(dāng)請(qǐng)求從Zuul網(wǎng)關(guān)進(jìn)來,負(fù)載均衡到任意的A服務(wù)節(jié)點(diǎn),比如A1,此時(shí)A1通過feign調(diào)用B服務(wù)和C服務(wù)的任意節(jié)點(diǎn),比如B2和C1。此時(shí)分兩種情況:
a.當(dāng)A1并發(fā)請(qǐng)求B2和C1,此時(shí)如果有一個(gè)接口超時(shí),或者兩個(gè)接口都超時(shí),那么ReadTime都是1s左右,而并沒有達(dá)到ribbon.ReadTimeout=3000,所以不會(huì)觸發(fā)網(wǎng)關(guān)的ribbon重試,所以此時(shí)接口沒有返回正常的結(jié)果。
b.當(dāng)A1順序請(qǐng)求B2和C1,此時(shí)如果有一個(gè)接口超時(shí),那么ReadTime為1s左右,如果是兩個(gè)接口都超時(shí),那么ReadTime都是2s左右,而并沒有達(dá)到ribbon.ReadTimeout=3000,所以不會(huì)觸發(fā)網(wǎng)關(guān)的ribbon重試,所以此時(shí)接口沒有返回正常的結(jié)果。
所以只要A服務(wù)處理請(qǐng)求的時(shí)間沒有超過在Zuul配置ribbon.ReadTimeout的值,那么都不會(huì)觸發(fā)ribbon的重試。
2、Zuul網(wǎng)關(guān)的ribbon.ReadTimeout=服務(wù)端feign.client.config.default.readTimeout。
比如:Zuul網(wǎng)關(guān)的ribbon.ReadTimeout=1000,服務(wù)端配置的feign.client.config.default.readTimeout=1000,當(dāng)請(qǐng)求從Zuul網(wǎng)關(guān)進(jìn)來,負(fù)載均衡到任意的A服務(wù)節(jié)點(diǎn),比如A2,此時(shí)A2通過feign調(diào)用B服務(wù)和C服務(wù)的任意節(jié)點(diǎn),比如B1和C2。此時(shí)不管是調(diào)用B1或者C2超時(shí),或者都超時(shí),那么都會(huì)觸發(fā)Zuul網(wǎng)關(guān)的ribbon重試,重試次數(shù)主要由ribbon.MaxAutoRetries和ribbon.MaxAutoRetriesNextServer配置的值決定。
比如ribbon.MaxAutoRetries=0,ribbon.MaxAutoRetriesNextServer=1那么,Zuul會(huì)根據(jù)配置,重新調(diào)用A1進(jìn)行重試,而A1也是通過feign調(diào)隨機(jī)用B服務(wù)和C服務(wù)的任意節(jié)點(diǎn)。
總結(jié)以上兩種情況,A服務(wù)調(diào)用調(diào)用B服務(wù)或者C服務(wù)任意節(jié)點(diǎn)超時(shí),A服務(wù)都不會(huì)對(duì)B服務(wù)和C服務(wù)的當(dāng)前或者其他節(jié)點(diǎn)進(jìn)行重試。
那么怎么樣,才能讓服務(wù)A調(diào)用服務(wù)B超時(shí)的時(shí)候,進(jìn)行重試呢?網(wǎng)上找了些資料,總結(jié)如下:
1、Feign組件默認(rèn)使用Ribbon的重試機(jī)制并增加了根據(jù)狀態(tài)碼判斷重試機(jī)制,默認(rèn)情況下是不啟用的。
2、Feign使用的是Spring Retry組件,需要引入依賴才能啟用,也就是網(wǎng)關(guān)ribbon重試那個(gè)組件。
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
3、引入以后沒有正確配置ribbon,默認(rèn)同一節(jié)點(diǎn)會(huì)重試5次,即使第一次訪問就觸發(fā)了Zuul網(wǎng)關(guān)已經(jīng)返回超時(shí),并且瀏覽器已經(jīng)返回超時(shí)結(jié)果,F(xiàn)eign也會(huì)重試5次,如果剛好網(wǎng)關(guān)又觸發(fā)了重試,重試次數(shù)配置得也比較大的話,那么就會(huì)產(chǎn)生大量多余的請(qǐng)求,會(huì)對(duì)系統(tǒng)和服務(wù)性能造成一定的影響,哪怕沒有觸發(fā)網(wǎng)關(guān)的重試,出現(xiàn)一個(gè)節(jié)點(diǎn)某個(gè)服務(wù)故障的時(shí)候,也會(huì)產(chǎn)生多余的性能開銷。
4、根據(jù)網(wǎng)上找的資料服務(wù)端ribbon正確配置如下:
${spring.application.name}: ribbon: MaxAutoRetries: 1 MaxAutoRetriesNextServer: 1 OkToRetryOnAllOperations: false NFLoadBalancerRuleClassName: AvailabilityFilteringRule feign: client: config: default: connectTimeout: 1000 readTimeout: 1000
OkToRetryOnAllOperations建議不要設(shè)置為true,即使接口做了冪等,避免后續(xù)哪個(gè)接口忘記做冪等產(chǎn)生臟數(shù)據(jù)。
通過實(shí)際的測(cè)試,發(fā)現(xiàn)接入依賴以后,F(xiàn)eign的請(qǐng)求超時(shí)的確會(huì)觸發(fā)重試,但是實(shí)際上網(wǎng)關(guān)的ribbon.ReadTimeout、ribbon.MaxAutoRetries、ribbon.MaxAutoRetriesNextServer這些參數(shù)都會(huì)影響Feign的重試可能性和結(jié)果,下篇文章《SpringCloud Ribbon和Feign重試參數(shù)性能實(shí)測(cè)對(duì)比》詳細(xì)介紹實(shí)際測(cè)試結(jié)果。