SpringCloud Feign重試不生效問題排查

2020年9月28日16:22:07 發表評論 6,429 ℃

Feign重試不生效問題的發現,主要還是因為上篇文章《SpringCloud Zuul(Ribbon)重試配置不生效解決辦法》里面介紹的原因。當我解決了Zuul重試不生效的問題,測試發現只有如下場景:zuul-->訪問A1、A2,A服務返回超時,也就是說Api接口的第一級跨度超過zuul配置ribbon.ReadTimeout的值才會觸發ribbon重試。場景一如下圖:

SpringCloud Feign重試不生效問題排查

場景二如下圖,Api接口跨度多個服務的調用:

SpringCloud Feign重試不生效問題排查

此時ReadTimeout有兩種情況:

1、Zuul網關的ribbon.ReadTimeout>服務端feign.client.config.default.readTimeout。

比如:Zuul網關的ribbon.ReadTimeout=3000,服務端配置的feign.client.config.default.readTimeout=1000,當請求從Zuul網關進來,負載均衡到任意的A服務節點,比如A1,此時A1通過feign調用B服務和C服務的任意節點,比如B2和C1。此時分兩種情況:

a.當A1并發請求B2和C1,此時如果有一個接口超時,或者兩個接口都超時,那么ReadTime都是1s左右,而并沒有達到ribbon.ReadTimeout=3000,所以不會觸發網關的ribbon重試,所以此時接口沒有返回正常的結果。

b.當A1順序請求B2和C1,此時如果有一個接口超時,那么ReadTime為1s左右,如果是兩個接口都超時,那么ReadTime都是2s左右,而并沒有達到ribbon.ReadTimeout=3000,所以不會觸發網關的ribbon重試,所以此時接口沒有返回正常的結果。

所以只要A服務處理請求的時間沒有超過在Zuul配置ribbon.ReadTimeout的值,那么都不會觸發ribbon的重試。

2、Zuul網關的ribbon.ReadTimeout=服務端feign.client.config.default.readTimeout。

比如:Zuul網關的ribbon.ReadTimeout=1000,服務端配置的feign.client.config.default.readTimeout=1000,當請求從Zuul網關進來,負載均衡到任意的A服務節點,比如A2,此時A2通過feign調用B服務和C服務的任意節點,比如B1和C2。此時不管是調用B1或者C2超時,或者都超時,那么都會觸發Zuul網關的ribbon重試,重試次數主要由ribbon.MaxAutoRetries和ribbon.MaxAutoRetriesNextServer配置的值決定。

比如ribbon.MaxAutoRetries=0,ribbon.MaxAutoRetriesNextServer=1那么,Zuul會根據配置,重新調用A1進行重試,而A1也是通過feign調隨機用B服務和C服務的任意節點。

總結以上兩種情況,A服務調用調用B服務或者C服務任意節點超時,A服務都不會對B服務和C服務的當前或者其他節點進行重試。

那么怎么樣,才能讓服務A調用服務B超時的時候,進行重試呢?網上找了些資料,總結如下:

1、Feign組件默認使用Ribbon的重試機制并增加了根據狀態碼判斷重試機制,默認情況下是不啟用的。

2、Feign使用的是Spring Retry組件,需要引入依賴才能啟用,也就是網關ribbon重試那個組件。

  <dependency>
     <groupId>org.springframework.retry</groupId>
     <artifactId>spring-retry</artifactId>
 </dependency>

3、引入以后沒有正確配置ribbon,默認同一節點會重試5次,即使第一次訪問就觸發了Zuul網關已經返回超時,并且瀏覽器已經返回超時結果,Feign也會重試5次,如果剛好網關又觸發了重試,重試次數配置得也比較大的話,那么就會產生大量多余的請求,會對系統和服務性能造成一定的影響,哪怕沒有觸發網關的重試,出現一個節點某個服務故障的時候,也會產生多余的性能開銷。

4、根據網上找的資料服務端ribbon正確配置如下:

${spring.application.name}:  
  ribbon:
    MaxAutoRetries: 1
    MaxAutoRetriesNextServer: 1 
    OkToRetryOnAllOperations: false
    NFLoadBalancerRuleClassName: AvailabilityFilteringRule
feign:
  client:
    config:
      default:
        connectTimeout: 1000
        readTimeout: 1000

OkToRetryOnAllOperations建議不要設置為true,即使接口做了冪等,避免后續哪個接口忘記做冪等產生臟數據。

通過實際的測試,發現接入依賴以后,Feign的請求超時的確會觸發重試,但是實際上網關的ribbon.ReadTimeout、ribbon.MaxAutoRetries、ribbon.MaxAutoRetriesNextServer這些參數都會影響Feign的重試可能性和結果,下篇文章《SpringCloud Ribbon和Feign重試參數性能實測對比》詳細介紹實際測試結果。

【騰訊云】云服務器、云數據庫、COS、CDN、短信等云產品特惠熱賣中