前言
假設你的系統裏有100萬個使用者,然後你要輪詢重試的獲取每個使用者的身份資訊, 如果你還在使用SpringRetry和GuavaRetry 之類的這種單任務的同步重試框架,那你可能到猴年馬月也處理不完, 即使加再多的機器和執行緒也是杯水車薪, 而Fast-Retry正是為這種場景而生
Fast-Retry
一個高效能的多工重試框架,支持百萬級任務的異步重試、以及支持編程式和註解聲明式等多種使用方式、 也支持自訂結果重試邏輯。
What is this?
與主流的Spring-Retry, Guava-Retry等單任務同步重試框架不同,Fast-Retry是一個支持異步重試框架,支持異步任務的重試、超時等待、回呼。Spring-Retry, Guava-Retry均無法支持大批次任務的重試,即使加入執行緒池也無法解決,因為實際每個重試任務都是單獨的同步邏輯,然後會會占用過多執行緒資源導致大量任務在等待處理,隨著任務數的增加,系統吞吐量大大降低,效能指數級降低,而Fast-Retry在異步重試下的效能是前者的指數倍。下圖是三者的效能對比
測試執行緒池: 8個固定執行緒
單個任務邏輯: 輪詢5次,隔2秒重試一次,總耗時10秒
未測預計公式: 當我們使用執行緒池的時候, 一般執行緒池中 總任務處理耗時 = 任務數/並行度 x 單個任務重試耗時
可以看到即使是處理100萬個任務,Fast-Retry的效能也比Spring-Retry和Guava-Retry處理在50個任務時的效能還要快的多的多屬實降維打擊,這麽快的秘密在於除了是異步,重要的是當別人在重試間隔裏休息的時候,Fast-Retry還在不停忙命的工作著。即使拋開效能不談, SpringRetry使用繁瑣,不支持根據結果的進行重試,GuavaRetry雖然支持,但是又沒有提供註解聲明式的使用。
快速開始
引入依賴
xml復制程式碼 <dependency>
<groupId>io.github.burukeyou</groupId>
<artifactId>fast-retry-all</artifactId>
<version>0.2.0</version>
</dependency>
有以下三種方式去構建我們的重試任務
使用重試佇列
RetryTask就是可以配置我們重試任務的一些邏輯,比如怎麽重試,怎麽獲取重試結果,隔多久後重試,在什麽情況下重試。它可以幫助我們更加自由的去構建重試任務的邏輯。但如果只是簡單使用,強烈建議使用FastRetryBuilder 或者 @FastRetry註解 RetryQueue就是一個執行和排程我們重試任務的核心角色,其在使用上與執行緒池的API方法基本一致
ExecutorService executorService = Executors.newFixedThreadPool(8);
RetryQueue queue =newFastRetryQueue(executorService);
RetryTask<String> task =newRetryTask<String>() {
int result =0 ;
// 下一次重試的間隔
@Override
public long waitRetryTime() {
return2000;
}
// 執行重試,每次重試回呼此方法
@Override
public boolean retry() {
return++result <5;
}
// 獲取重試結果
@Override
publicStringgetResult() {
return result +"";
}
};
CompletableFuture<String> future = queue.submit(task);
log.info("任務結束 結果:{}",future.get());
使用FastRetryBuilder
底層還是使用的RetryQueue去處理, 只是幫我們簡化了構建RetryTask的邏輯
RetryResultPolicy<String> resultPolicy = result -> result.equals("444");
FastRetryer<String> retryer = FastRetryBuilder.<String>builder()
.attemptMaxTimes(3)
.waitRetryTime(3, TimeUnit.SECONDS)
.retryIfException(true)
.retryIfExceptionOfType(TimeoutException. class)
.exceptionRecover(true)
.resultPolicy(resultPolicy)
.build();
CompletableFuture<String> future = retryer.submit(() -> {
log.info("重試");
//throw new Exception("test");
//int i = 1/0;
if (0<10){
thrownewTimeoutException("test");
}
return"444";
});
String o = future.get();
log.info("結果{}", o);
使用@FastRetry註解
底層還是使用的RetryQueue去處理, 只是幫我們簡化了構建RetryTask的邏輯,並且與Spring進行整合能對Spring的bean標記了FastRetry註解的方法進行代理, 提供了重試任務註解聲明式的使用方式:
依賴Spring環境,所以需要在Spring配置類加上@EnableFastRetry註解啟用配置 , 這個@FastRetry註解的使用才會生效
如果將結果型別使用CompletableFuture包裝,自動進行異步輪詢返回,否則同步阻塞等待重試結果。(推薦)
下面定義等價於 RetryQueue.execute方法
// 如果發生異常,每隔兩秒重試一次
@FastRetry(retryWait = @RetryWait(delay =2))
publicStringretryTask(){
return"success";
}
下面定義等價於 RetryQueue.submit方法,支持異步輪詢
@FastRetry(retryWait = @RetryWait(delay =2))
public CompletableFuture<String>retryTask(){
return CompletableFuture.completedFuture("success");
}
自訂重試註解
如果不喜歡或者需要更加通用化的貼近業務的重試註解,提供一些預設的參數和處理邏輯,可以自行定義一個重試註解並標記上@FastRetry並指定factory,然後實作AnnotationRetryTaskFactory介面實作自己的構建重試任務的邏輯即可。@FastRetry預設實作就是:FastRetryAnnotationRetryTaskFactory
使用建議
無論是使用以上哪種方式去構建你的重試任務,都建議使用異步重試的方法,即返回結果是CompletableFuture的方法, 然後使用CompletableFuture的whenComplete方法去等待異步重試任務的執行結果。
其他
github計畫地址 :
https://github.com/burukeYou/fast-retry
具體使用案例見fast-retry-demo模組
maven倉庫地址:
https://central.sonatype.com/artifact/io.github.burukeyou/fast-retry-all
還在叠代中,第一個版本主要專註於多重試任務的處理, 還需要什麽好玩的功能和特征請留下你的意見感謝。覺得有用或者能學到點什麽可以star下哈哈
如喜歡本文,請點選右上角,把文章分享到朋友圈
如有想了解學習的技術點,請留言給若飛安排分享
因公眾號更改推播規則,請點「在看」並加「星標」 第一時間獲取精彩技術分享
·END·
相關閱讀:
作者:李白的手機
來源:https://juejin.cn/post/7337989768637939739
版權申明:內容來源網路,僅供學習研究,版權歸原創者所有。如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝!
架構師
我們都是架構師!
關註 架構師(JiaGouX),添加「星標」
獲取每天技術幹貨,一起成為牛逼架構師
技術群請 加若飛: 1321113940 進架構師群
投稿、合作、版權等信箱: [email protected]