一猪半、定義
重試機(jī)制可以保護(hù)系統(tǒng)減少因網(wǎng)絡(luò)波動(dòng)兔朦、依賴服務(wù)短暫性不可用帶來的影響,讓系統(tǒng)能更穩(wěn)定的運(yùn)行的一種保護(hù)機(jī)制磨确。
二沽甥、實(shí)現(xiàn)
因?yàn)間uava-retrying是基于Google的核心類庫guava的重試機(jī)制實(shí)現(xiàn),所以需要依賴guava的包乏奥,這里記得引入下摆舟。例子如下:
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfException()
.retryIfResult(aBoolean -> Objects.equals(aBoolean, false))
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(10, TimeUnit.SECONDS, Executors.newCachedThreadPool()))
.withWaitStrategy(WaitStrategies.fixedWait(5, TimeUnit.SECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(5))
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
System.out.print("retry time=" + attempt.getAttemptNumber());
}
}).build();
try {
retryer.call(() -> {
// 邏輯處理
return null;
});
} catch (Exception e) {
System.out.println("exception:" + e);
}
這就是一個(gè)重試機(jī)制的實(shí)現(xiàn)了,比較簡(jiǎn)單邓了,我們來看下具體接口及相應(yīng)的策咯恨诱。
- newBuilder:創(chuàng)建RetryerBuilder對(duì)象,通過該類進(jìn)行構(gòu)建各種重試策咯骗炉;
- retryIfException:拋出異常時(shí)重試照宝,但拋出error不會(huì)重試;另外該方法還包含一個(gè)重載的方法句葵,可以自定義針對(duì)異常的實(shí)現(xiàn)厕鹃;
- retryIfRuntimeException:見名知義,拋出RuntimeException時(shí)重試笼呆;
- retryIfExceptionOfType:拋出指定異常類型時(shí)重試熊响;
- retryIfResult:根據(jù)具體的返回值選擇重試;
- withRetryListener:在重試的時(shí)候進(jìn)行事件監(jiān)聽诗赌,這中間我們可以記錄下錯(cuò)誤日志什么的汗茄;可以注冊(cè)多個(gè)事件監(jiān)聽器,會(huì)按照注冊(cè)順序依次調(diào)用铭若;
- withWaitStrategy:重試等待策略洪碳,核心策咯之一;
- withStopStrategy:重試停止策略叼屠,核心策咯之一瞳腌;
- withBlockStrategy:重試阻塞策略,也就是兩次重試的時(shí)間間隔的實(shí)現(xiàn)方式镜雨;
- withAttemptTimeLimiter:?jiǎn)未稳蝿?wù)執(zhí)行時(shí)長(zhǎng)限制(如果單次任務(wù)執(zhí)行超時(shí)嫂侍,則終止執(zhí)行當(dāng)前任務(wù));
- build:通過newBuilder構(gòu)建了各種重試策咯荚坞,構(gòu)建完成挑宠,還需要通過build方法借助Retryer來執(zhí)行;
接下來颓影,我們來看一下主要的幾個(gè)策咯及核心類各淀。
1. WaitStrategies 重試等待策略
1.1 ExponentialWaitStrategy 指數(shù)等待策略
指數(shù)補(bǔ)償 算法 Exponential Backoff
.withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES))
創(chuàng)建一個(gè)永久重試的重試器,每次重試失敗時(shí)以遞增的指數(shù)時(shí)間等待诡挂,直到最多5分鐘碎浇。 5分鐘后临谱,每隔5分鐘重試一次。對(duì)該例而言:
第一次失敗后奴璃,依次等待時(shí)長(zhǎng):2^1 * 100;2^2 * 100悉默;2^3 * 100;...
在ExponentialWaitStrategy中,根據(jù)重試次數(shù)計(jì)算等待時(shí)長(zhǎng)的源碼我們可以關(guān)注下:
@Override
public long computeSleepTime(Attempt failedAttempt) {
double exp = Math.pow(2, failedAttempt.getAttemptNumber());
long result = Math.round(multiplier * exp);
if (result > maximumWait) {
result = maximumWait;
}
return result >= 0L ? result : 0L;
}
如果以后有類似的需求溺健,我們可以自己寫下這些算法麦牺,而有關(guān)更多指數(shù)補(bǔ)償 算法 Exponential Backoff,可以參考:http://en.wikipedia.org/wiki/Exponential_backoff
1.2 FibonacciWaitStrategy 斐波那契等待策略
Fibonacci Backoff 斐波那契補(bǔ)償算法
.withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES))
創(chuàng)建一個(gè)永久重試的重試器鞭缭,每次重試失敗時(shí)以斐波那契數(shù)列來計(jì)算等待時(shí)間剖膳,直到最多2分鐘;2分鐘后岭辣,每隔2分鐘重試一次吱晒;對(duì)該例而言:
第一次失敗后,依次等待時(shí)長(zhǎng):1*100;1*100沦童;2*100仑濒;3*100;5*100偷遗;...
1.3 FixedWaitStrategy 固定時(shí)長(zhǎng)等待策略
withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
固定時(shí)長(zhǎng)等待策略墩瞳,失敗后,將等待固定的時(shí)長(zhǎng)進(jìn)行重試氏豌;
1.4 RandomWaitStrategy 隨機(jī)時(shí)長(zhǎng)等待策略
withWaitStrategy(WaitStrategies.randomWait(10, TimeUnit.SECONDS));
withWaitStrategy(WaitStrategies.randomWait(1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS));
隨機(jī)時(shí)長(zhǎng)等待策略喉酌,可以設(shè)置一個(gè)隨機(jī)等待的最大時(shí)長(zhǎng),也可以設(shè)置一個(gè)隨機(jī)等待的時(shí)長(zhǎng)區(qū)間泵喘。
1.5 IncrementingWaitStrategy 遞增等待策略
withWaitStrategy(WaitStrategies.incrementingWait(1, TimeUnit.SECONDS, 5, TimeUnit.SECONDS))
遞增等待策略泪电,根據(jù)初始值和遞增值,等待時(shí)長(zhǎng)依次遞增纪铺。就本例而言:
第一次失敗后相速,將依次等待1s;6s(1+5)鲜锚;11(1+5+5)s突诬;16(1+5+5+5)s;...
1.6 ExceptionWaitStrategy 異常等待策略
withWaitStrategy(WaitStrategies.exceptionWait(ArithmeticException.class, e -> 1000L))
根據(jù)所發(fā)生的異常指定重試的等待時(shí)長(zhǎng)芜繁;如果異常不匹配攒霹,則等待時(shí)長(zhǎng)為0;
1.7 CompositeWaitStrategy 復(fù)合等待策略
.withWaitStrategy(WaitStrategies.join(WaitStrategies.exceptionWait(ArithmeticException.class, e -> 1000L),WaitStrategies.fixedWait(5, TimeUnit.SECONDS)))
復(fù)合等待策略;如果所執(zhí)行的程序滿足一個(gè)或多個(gè)等待策略吼野,那么等待時(shí)間為所有等待策略時(shí)間的總和跨嘉。
2. StopStrategies 重試停止策略
2.1 NeverStopStrategy
withStopStrategy(StopStrategies.neverStop())
一直不停止,一直需要重試短条。
2.2 StopAfterAttemptStrategy
withStopStrategy(StopStrategies.stopAfterAttempt(3))
在重試次數(shù)達(dá)到最大次數(shù)之后剑辫,終止任務(wù)阱飘。
2.3 StopAfterDelayStrategy
withStopStrategy(StopStrategies.stopAfterDelay(3, TimeUnit.MINUTES))
在重試任務(wù)達(dá)到設(shè)置的最長(zhǎng)時(shí)長(zhǎng)之后摘昌,無論任務(wù)執(zhí)行次數(shù)速妖,都終止任務(wù)。
3. BlockStrategies 阻塞策略
阻塞策略默認(rèn)提供的只有一種:ThreadSleepStrategy聪黎,實(shí)現(xiàn)方式是通過Thread.sleep(sleepTime)
來實(shí)現(xiàn)罕容;不過這也給了我們極大的發(fā)揮空間,我們可以自己實(shí)現(xiàn)阻塞策略稿饰。
4. AttemptTimeLimiters 任務(wù)執(zhí)行時(shí)長(zhǎng)限制
這個(gè)表示單次任務(wù)執(zhí)行時(shí)間限制(如果單次任務(wù)執(zhí)行超時(shí)锦秒,則終止執(zhí)行當(dāng)前任務(wù));
4.1 NoAttemptTimeLimit 無時(shí)長(zhǎng)限制
.withAttemptTimeLimiter(AttemptTimeLimiters.noTimeLimit())
顧名思義喉镰,不限制執(zhí)行時(shí)長(zhǎng)旅择;每次都是等執(zhí)行任務(wù)執(zhí)行完成之后,才進(jìn)行后續(xù)的重試策咯侣姆。
4.2 FixedAttemptTimeLimit
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(10, TimeUnit.SECONDS));
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(10, TimeUnit.SECONDS, Executors.newCachedThreadPool()));
可以指定任務(wù)的執(zhí)行時(shí)長(zhǎng)限制生真,并且為了控制線程管理,最好指定相應(yīng)的線程池捺宗。
轉(zhuǎn)自:http://www.reibang.com/p/a289dde63043