亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

小黑在開發(fā)中遇到個問題,我負責的模塊需要調(diào)用某個三方服務接口查詢信息,查詢結(jié)果直接影響后續(xù)業(yè)務邏輯的處理;

這個接口偶爾會因網(wǎng)絡問題出現(xiàn)超時,導致我的業(yè)務邏輯無法繼續(xù)處理;

這個問題該如何解決呢?,小黑首先想到的就是重試嘛,如果失敗了就再調(diào)用一次。

問題來了,如果又失敗了呢?接著重試嘛。我們循環(huán)處理,比如循環(huán)5次,全失敗則任務服務不可用,結(jié)束調(diào)用。

如果我又想著5次調(diào)用間隔一段時間呢?第一次先隔1秒,然后3秒,然后5秒呢?

小黑發(fā)現(xiàn)事情沒那么簡單,如果自己搞容易出BUG呀。

Guava Retryer輕松實現(xiàn)接口重試

 

轉(zhuǎn)念一想,這個常見挺常見,網(wǎng)上應該有輪子呀,找找看。一不小心就讓我給找著啦,哈哈。

Guava Retryer

This is a small extension to google’s Guava library to allow for the creation of configurable retrying strategies for an arbitrary function call, such as something that talks to a remote service with flaky uptime.

使用Guava Retryer你可以自定義來執(zhí)行重試,同時也可以監(jiān)控每次重試的結(jié)果和行為,最重要的基于 Guava 風格的重試方式真的很方便。

引入依賴

<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>2.0.0</version>
</dependency>

快速開始

Callable<Boolean> callable = new Callable<Boolean>() {
    public Boolean call() throws Exception {
        return true; // do something useful here
    }
};

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
    .retryIfResult(Predicates.<Boolean>isNull()) // callable返回null時重試
    .retryIfExceptionOfType(IOException.class) // callable拋出IOException重試
    .retryIfRuntimeException() // callable拋出RuntimeException重試
    .withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重試3次后停止
    .build();
try {
    retryer.call(callable);
} catch (RetryException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

在Callable的call()方法返回null,拋出IOException或者RuntimeException時會重試; 將在嘗試重試3次后停止,并拋出包含上次失敗嘗試信息的RetryException; 如果call()方法中彈出任何其他異常,它將被包裝并在ExecutionException中重新調(diào)用。

指數(shù)退避(Exponential Backoff)

根據(jù)wiki上對Exponential backoff的說明,指數(shù)補償是一種通過反饋,成倍地降低某個過程的速率,以逐漸找到合適速率的算法。

在以太網(wǎng)中,該算法通常用于沖突后的調(diào)度重傳。根據(jù)時隙和重傳嘗試次數(shù)來決定延遲重傳。

在c次碰撞后(比如請求失敗),會選擇0和2^c - 1之間的隨機值作為時隙的數(shù)量。

對于第1次碰撞來說,每個發(fā)送者將會等待0或1個時隙進行發(fā)送。 而在第2次碰撞后,發(fā)送者將會等待0到3( 由2^2 -1 計算得到)個時隙進行發(fā)送。 而在第3次碰撞后,發(fā)送者將會等待0到7( 由2^3 - 1 計算得到)個時隙進行發(fā)送。 以此類推……

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
        .retryIfExceptionOfType(IOException.class)
        .retryIfRuntimeException()
        .withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES)) // 指數(shù)退避
        .withStopStrategy(StopStrategies.neverStop()) // 永遠不停止重試
        .build();

創(chuàng)建一個永遠重試的重試器,在每次重試失敗后以指數(shù)級退避間隔遞增,直到最多5分鐘。5分鐘后,從那時起每隔5分鐘重試一次。

斐波那契退避(Fibonacci Backoff)

斐波那契數(shù)列指的是這樣一個數(shù)列:

0,1,1,2,3,5,8,13,21,34,55,89...

這個數(shù)列從第3項開始,每一項都等于前兩項之和。

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
        .retryIfExceptionOfType(IOException.class)
        .retryIfRuntimeException()
        .withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES)) // 斐波那契退避
        .withStopStrategy(StopStrategies.neverStop())
        .build();

創(chuàng)建一個永遠重試的重試器,在每次重試失敗后以增加斐波那契退避間隔的方式等待,直到最多2分鐘。2分鐘后,從那時起每隔2分鐘重試一次。

與指數(shù)退避策略類似,斐波那契退避策略遵循一種模式,即在每次嘗試失敗后等待的時間越來越長。

對于這兩種策略的性能英國利茲大學專門做過性能測試,相比指數(shù)退避策略,斐波那契退避策略可能性能更好,吞吐量可能也更好。

重試監(jiān)聽器

當重試發(fā)生時,如果需要額外做一些動作,比如發(fā)送郵件通知之類的,可以通過RetryListener,Guava Retryer在每次重試之后會自動回調(diào)監(jiān)聽器,并且支持注冊多個監(jiān)聽。

@Slf4j
class diyRetryListener<Boolean> implements RetryListener {
    @Override
    public <Boolean> void onRetry(Attempt<Boolean> attempt) {
        log.info("重試次數(shù):{}",attempt.getAttemptNumber());
        log.info("距離第一次重試的延遲:{}",attempt.getDelaySinceFirstAttempt());
        if(attempt.hasException()){
            log.error("異常原因:",attempt.getExceptionCause());
        }else {
            System.out.println("正常處理結(jié)果:{}" + attempt.getResult());
        }
    }
}

定義監(jiān)聽器之后,需要在Retryer中進行注冊。

        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                .retryIfResult(Predicates.<Boolean>isNull()) // callable返回null時重試
                .retryIfExceptionOfType(IOException.class) // callable拋出IOException重試
                .retryIfRuntimeException() // callable拋出RuntimeException重試
                .withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重試3次后停止
                .withRetryListener(new DiyRetryListener<Boolean>()) // 注冊監(jiān)聽器
                .build();

小結(jié)

Guava Retryer不光在重試策略上支持多種選擇,并且將業(yè)務邏輯的處理放在Callable中,和重試處理邏輯分開,實現(xiàn)了解耦,這比小黑自己去寫循環(huán)處理要優(yōu)秀太多啦,Guava確實強大。

分享到:
標簽:重試 接口
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定