一、問題產生
自定義重試次數,實現如下
@ConditionalOnProperty(prefix = "feign.client", name = "enable", havingValue = "true")
@Configuration
public class FeignConfig {@Beanpublic FeignInterceptor feignInterceptor() {return new FeignInterceptor();}@Beanpublic ErrorDecoder errorDecoder() {return new FeignErrorDecoder();}@Beanpublic Retryer feignRetryer() {return new Retryer.Default(500, TimeUnit.SECONDS.toMillis(1L), 3);}
}
Application.yml配置如下:
feign:client:enable: trueconfig:default:connectTimeout: 30000readTimeout: 30000#retryer: feign.Retryer.Defaultfile-service: # 為個別服務設置不同的超時時間connectTimeout: 6 # 為了方便測試超時重試readTimeout: 6 # 為了方便測試超時重試
?上述調用完后,發現不對,配置了3次,實際重試了6次,注冊中心有2個被調服務實例
二、?問題根源?
您的重試次數異常(配置3次實際觸發6次)是由于 ?Feign 與 Ribbon 的重試策略疊加?,且 ?Eureka 注冊的多個服務實例觸發 Ribbon 的實例切換重試? 導致的。具體原因如下:
-
?Ribbon 默認重試機制?
Ribbon 的?MaxAutoRetriesNextServer
?默認值為?1
,當服務注冊多個實例時,Ribbon 會在首次請求失敗后 ?切換實例重試 1 次??。此時總重試次數計算公式為:總請求次數 = (1 + MaxAutoRetries) * (1 + MaxAutoRetriesNextServer) * Feign重試次數
例如:若?
MaxAutoRetries=0
(默認)、MaxAutoRetriesNextServer=1
(默認)、Feign?maxAttempts=3
,則總次數為:(1+0) * (1+1) * 3 = 6次
-
?Eureka 多實例觸發切換?
當兩個服務實例注冊到 Eureka 時,Ribbon 的?MaxAutoRetriesNextServer=1
?會嘗試 ?切換實例重試?,導致每個實例被調用?Feign重試次數 × (1 + MaxAutoRetriesNextServer)
?次?。
三、?解決方案?
關閉 Ribbon 實例切換重試?
在?application.yml
?中顯式禁用 Ribbon 的實例切換重試:
ribbon:MaxAutoRetriesNextServer: 0 # 關閉切換實例重試?MaxAutoRetries: 0 # 關閉同一實例重試(默認已為0,可省略)OkToRetryOnAllOperations: false # 禁止非GET請求重試?
修改完成后,再次執行程序,控制臺輸出了超時
?可以看到文件服務重試了3次,如下圖所示