對於feign的接口請求失敗的重試配置可經過以下自定義配置文件實現(通常不建議配置)java
@Configuration public class FeignConfig { @Bean public Retryer feignRetryer() { return new Retryer.Default(100, SECONDS.toMillis(1), 5); } }
固然,也可以使用默認的retry配置文件,下方是feign.Retryer的源碼spring
// 類的全路徑是feign.Retryer public Default() { // 默認是重試的間隔是100ms,最大重試間隔是1秒,最大重試次數是5次 this(100, SECONDS.toMillis(1), 5); } public Default(long period, long maxPeriod, int maxAttempts) { this.period = period; this.maxPeriod = maxPeriod; this.maxAttempts = maxAttempts; this.attempt = 1; } public void continueOrPropagate(RetryableException e) { // 若是重試的次數大於最大重試次數,拋異常 if (attempt++ >= maxAttempts) { throw e; } long interval; if (e.retryAfter() != null) { interval = e.retryAfter().getTime() - currentTimeMillis(); // 若是重試間隔大於最大間隔,則取最大間隔 if (interval > maxPeriod) { interval = maxPeriod; } if (interval < 0) { return; } } else { // 若是重試間隔沒有明確,則調用nextMaxInterval獲取 interval = nextMaxInterval(); } try { // sleep必定時間後再去重試 Thread.sleep(interval); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } // sleptForMillis變量是總的重試間隔 sleptForMillis += interval; } /** * 下一次重試的間隔,間隔時間每一次重試都是1.5倍遞增,直到最大間隔 **/ long nextMaxInterval() { long interval = (long) (period * Math.pow(1.5, attempt - 1)); return interval > maxPeriod ? maxPeriod : interval; }
spring cloud中的feign整合了ribbon,但feign和ribbon都有重試功能,springcloud統一了二者的行爲,將feign的重試策略設置成永不重試,若是要使用feign的重試功能,只須要設置ribbon的重試配置便可,因此通常不建議配置feign的重試策略
網絡
ribbon默認配置以下負載均衡
ribbon: # 同一實例最大重試次數,不包括首次調用。默認值爲0 MaxAutoRetries: 0 # 同一個微服務其餘實例的最大重試次數,不包括第一次調用的實例。默認值爲1 MaxAutoRetriesNextServer: 1 # 是否全部操做(GET、POST等)都容許重試。默認值爲false OkToRetryOnAllOperations: false
**默認狀況下,GET方式請求不管是鏈接異常仍是讀取異常,都會進行重試
非GET方式請求,只有鏈接異常時,纔會進行重試** 框架
如此看來,若是同一個微服務只有一個實例是不會進行重試的,但事實並不是如此
分析一下源碼,feign的重試是在org.springframework.retry.support.RetryTemplate中的doExecute方法中進行中微服務
protected <T, E extends Throwable> T doExecute(RetryCallback<T, E> retryCallback,RecoveryCallback<T> recoveryCallback, RetryState state) throws E, ExhaustedRetryException { ...... while (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) { try { if (this.logger.isDebugEnabled()) { this.logger.debug("Retry: count=" + context.getRetryCount()); } // Reset the last exception, so if we are successful // the close interceptors will not think we failed... lastException = null; return retryCallback.doWithRetry(context); } ...... }
上方的canRetry是關鍵 this
最後一行policy.canRetryNextServer是可否選擇下一個實例進行重試 spa
而lbContext.getRetryHandler().getMaxRetriesOnNextServer()就是變量retryNextServer debug
retryNextServer的值就是來源於MaxAutoRetriesNextServer,默認是1,因此canRetry在返回的是true,因此調用了二次
解決辦法就是要進行以下配置3d
ribbon: # 同一實例最大重試次數,不包括首次調用。默認值爲0 MaxAutoRetries: 0 # 同一個微服務其餘實例的最大重試次數,不包括第一次調用的實例。默認值爲1 MaxAutoRetriesNextServer: 0 # 是否全部操做(GET、POST等)都容許重試。默認值爲false OkToRetryOnAllOperations: false
FeignRibbonClient的自動配置類
能夠看出,其默認使用LoadBalancerFeignClient的配置
查看其DEFAULT_OPTIONS可知道默認鏈接超時時間是10s,讀取超時是6s
默認的網絡請求框架是HttpURLConnection
如要更換相應的網絡請求框架,只須要添加相應的pom依賴便可
查看負載均衡怎麼作的,查看executeWithLoadBalancer
查看其submit任務
其方法selectServer就是負載均衡的關鍵
Feign的流程以下