解決FeignClient重試機制造成的接口冪等性

FeignClient重試機制造成的接口冪等性

Feign源碼分析,其實現類在 SynchronousMethodHandler,實現方法是public Object invoke(Object[] argv) ,它的代碼分析如下:

1.構造請求數據,將對象轉換為json:

RequestTemplate template = buildTemplateFromArgs.create(argv);

2.發送請求進行執行(執行成功會解碼響應數據):

executeAndDecode(template, options);

3. 執行請求會有重試機制:

Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        return executeAndDecode(template, options);
      } catch (RetryableException e) {
        try {
          retryer.continueOrPropagate(e);
        } catch (RetryableException th) {
          Throwable cause = th.getCause();
           // 重試結束 或則 不允許重試,則通過拋異常的形式終止 
          if (propagationPolicy == UNWRAP && cause != null) {
            throw cause;
          } else {
            throw th;
          }
        }
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }

4. Retryer是重試器,其實現方法有兩種

第一種是系統默認實現方式,第二種是可以自定義重試器,一般少用,通過默認實現重試類Default可以看到其構造函數中的重試次數為5。

    public Default() {
      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;
    }

因此解決Feign調用的冪等性問題最簡單也就最常用的就是讓Feign不重試。

為FeignClient增加請求重試機制

spring cloud通過feign client進行服務之間調用的時候,默認不會進行重試,這樣會有一個問題,比如你的服務在滾動升級重啟的時候,feign的調用將直接失敗,但其實我是滾動重啟,重啟瞭一個服務實例,還有另外一個服務實例是可用的,應該允許自動均衡策略重試請求發送到另外一個可用的服務實例上去。

要啟用重試機制,首先必須引入spring-retry依賴:

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

然後通過註冊一個bean:

  /**
     *
     * 註冊一個重試Bean
     * 默認FeignClient不會進行重試,使用的是{@link feign.Retryer#NEVER_RETRY}
     *
     * @see FeignClientsConfiguration#feignRetryer()
     */
    @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default();
    }

大功告成。

不過還有個前提就是,你的遠程調用接口方法的必須是冪等的(比如GET方法認為是冪等的,調用多少次結果都一樣,而POST方法有可能有重復提交問題),不然還是不會重試的,因為其他HttpMethod被認為是非冪等的,不能重復執行,因此不能被重試

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: