接口請(qǐng)求重試機(jī)制是保證系統(tǒng)穩(wěn)定性和容錯(cuò)能力的重要手段之一。當(dāng)接口請(qǐng)求發(fā)生失敗或暫時(shí)性錯(cuò)誤時(shí),通過(guò)重試機(jī)制可以提高請(qǐng)求的成功率。本文將詳細(xì)介紹接口請(qǐng)求重試機(jī)制的幾種常見(jiàn)方法。
它的基本思路是:
示例
public class Retry {private static final int MAX_RETRIES = 5;public static Response request() throws Exception { int retries = 0; while (true) { try { // 發(fā)送請(qǐng)求,返回響應(yīng) Response response = HttpClient.sendRequest(); // 請(qǐng)求成功則返回響應(yīng) if (response.isSuccess()) { return response; } } catch (Exception e) { // 請(qǐng)求失敗進(jìn)行重試 } // 判斷是否超過(guò)最大重試次數(shù) if (++retries >= MAX_RETRIES) { throw new Exception("Exceeded max retries"); } // 增加間隔后重試 int interval = (int) (Math.random() * 1000); Thread.sleep(interval); }}public static void main(String[] args) throws Exception { Response response = request(); // ...}}
使用 Spring Retry 庫(kù)可以很方便地實(shí)現(xiàn)接口請(qǐng)求的重試機(jī)制。
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> <version>1.3.1</version></dependency>
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 5000))public User getUser(String id) {// 遠(yuǎn)程調(diào)用接口}
@Retryable 定義了重試規(guī)則:- value - 重試的異常類型- maxAttempts - 最大重試次數(shù)- backoff - 重試等待策略
RetryTemplate template = new RetryTemplate();template.execute(context -> {// 可在此處自定義重試邏輯 return remoteClient.invoke();});
Spring Retry 為接口請(qǐng)求重試提供了完善和易用的解決方案,可以靈活控制各種重試參數(shù),適用于復(fù)雜系統(tǒng)的容錯(cuò)要求。
使用并發(fā)框架的異步請(qǐng)求方式可以較簡(jiǎn)單地實(shí)現(xiàn)接口請(qǐng)求的重試機(jī)制。以CompletableFuture為例:
2.3.1 發(fā)送請(qǐng)求使用CompletableFuture封裝:
CompletableFuture<Response> future = CompletableFuture.supplyAsync(() -> {return service.call();});
2.3.2 當(dāng)請(qǐng)求失敗時(shí),使用retryAsync自動(dòng)完成重試:
future = future.exceptionally(e -> {return service.retryAsync();});
2.3.3 可以鏈?zhǔn)秸{(diào)用,自定義重試邏輯:
future.exceptionally(e -> { // 處理異常}).thenApplyAsync(resp -> { // 處理響應(yīng)}).retryAsync(retryCount, delay);
主要優(yōu)點(diǎn)是:
使用并發(fā)框架可以便捷地實(shí)現(xiàn)異步重試機(jī)制,提高系統(tǒng)容錯(cuò)性。其他框架如RxJava也有類似的重試機(jī)制。
使用消息隊(duì)列可以實(shí)現(xiàn)接口請(qǐng)求的異步重試機(jī)制。
基本思路是:
主要步驟:
使用消息隊(duì)列進(jìn)行重試有利于:
示例
// 1. 創(chuàng)建隊(duì)列Queue retryQueue = new Queue("request.retry.queue");// 2. 請(qǐng)求失敗,發(fā)送重試消息 public void request() {try { // 調(diào)用接口 httpClient.post(url, payload);} catch (Exception e) { // 發(fā)送重試消息 Message msg = new Message(url, payload, maxRetries); retryQueue.send(msg);}}// 3. 消費(fèi)者線程進(jìn)行重試class RetryConsumer implements Runnable {public void run() { while (true) { Message msg = retryQueue.take(); for (int i = 0; i < msg.getMaxRetries(); i++) { try { // 重試請(qǐng)求 httpClient.post(msg.getUrl(), msg.getPayload()); // 請(qǐng)求成功,結(jié)束循環(huán) break; } catch (Exception e) { // 等待后繼續(xù)重試 } } // 重試完成后,確認(rèn)消息 retryQueue.confirm(msg); }}}
這就是使用消息隊(duì)列實(shí)現(xiàn)接口重試的基本流程,可以根據(jù)需求擴(kuò)展重試策略、異常處理等邏輯。
使用自定義的重試工具類來(lái)實(shí)現(xiàn)接口請(qǐng)求的重試機(jī)制,提高代碼的復(fù)用性和可維護(hù)性。
重試工具類的實(shí)現(xiàn)思路:
示例:
public class RetryUtil {public static <T> T retry(RetryCallable<T> callable, RetryPolicy policy) { int retries = 0; while(true) { try { return callable.call(); } catch(Exception e) { if (retries >= policy.maxRetries) { throw e; } // 等待 policy.delay(); // 重試次數(shù)加1 retries++; } }}}// 執(zhí)行請(qǐng)求的函數(shù)接口interface RetryCallable<T> {T call();}// 重試策略class RetryPolicy {int maxRetries;int delay;}// 使用示例RetryUtil.retry(() -> {// 接口請(qǐng)求return httpClient.get(url);}, policy);
這樣可以提高重試相關(guān)邏輯的復(fù)用性,避免寫(xiě)重復(fù)代碼。
使用遞歸結(jié)構(gòu)也可以實(shí)現(xiàn)接口請(qǐng)求的重試機(jī)制。
基本思路是設(shè)計(jì)一個(gè)遞歸函數(shù),在函數(shù)內(nèi)部發(fā)送請(qǐng)求,如果失敗則繼續(xù)遞歸調(diào)用自身再次重試。
示例:
public class RetryRequest {private static final int MAX_RETRIES = 3; public static Response request(int retries) { try { // 發(fā)送請(qǐng)求 Response response = HttpClient.get("http://example.com"); return response; } catch (Exception e) { // 處理異常 // 判斷是否需要重試 if (retries < MAX_RETRIES) { // 增加重試次數(shù) retries++; // 延遲1秒鐘 Thread.sleep(1000); // 遞歸調(diào)用自身進(jìn)行重試 return request(retries); } // 重試失敗 throw new RuntimeException("Request failed after " + MAX_RETRIES + " retries!"); }} public static void main(String[] args) { Response response = request(0); // 處理響應(yīng)}}
主要邏輯是通過(guò)遞歸不斷調(diào)用自身來(lái)實(shí)現(xiàn)重試。優(yōu)點(diǎn)是邏輯較簡(jiǎn)單清晰,缺點(diǎn)是遞歸層次過(guò)深時(shí)可能會(huì)導(dǎo)致堆棧溢出。需要合理設(shè)置最大遞歸深度,也可以通過(guò)循環(huán)改寫(xiě)遞歸來(lái)避免深層遞歸。
Resilience4j是一個(gè)很好的Java重試庫(kù),可以用它來(lái)實(shí)現(xiàn)接口請(qǐng)求的重試機(jī)制。
主要步驟:
2.7.1添加Resilience4j依賴
<dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-retry</artifactId></dependency>
2.7.2 定義重試邏輯
RetryConfig config = RetryConfig.custom().maxAttempts(3).waitDuration(Duration.ofMillis(500)).build();Retry retry = Retry.of("backend", config);
2.7.3 使用重試邏輯調(diào)用接口
String result = retry.executeSupplier(() -> {// 發(fā)送請(qǐng)求return backendService.callAPI();});
2.7.4 自定義重試異常predicate
RetryConfig config = RetryConfig.custom().retryOnException(e -> isRetryable(e)).build();
Resilience4j提供了線程安全的重試 decorator,可以通過(guò)配置靈活控制重試策略,很好地支持了接口請(qǐng)求重試。
我們常用的一些網(wǎng)絡(luò)工具來(lái)做重試
示例
public class RetryExample {private static final int MAX_RETRIES = 3;public static String request(String url) throws Exception { int retries = 0; while (true) { try { // 使用HttpClient發(fā)送請(qǐng)求 return HttpClientUtils.get(url); } catch (Exception e) { if (retries >= MAX_RETRIES) { throw e; } // 增加重試次數(shù) retries++; // 延遲1秒鐘 TimeUnit.SECONDS.sleep(1); } }} public static void main(String[] args) throws Exception { String result = request("http://example.com/api"); System.out.println(result);}}// 網(wǎng)絡(luò)工具類class HttpClientUtils {public static String get(String url) throws IOException { // 發(fā)送GET請(qǐng)求并返回結(jié)果}}
主要通過(guò)循環(huán)和網(wǎng)絡(luò)工具類來(lái)實(shí)現(xiàn)重試邏輯,延時(shí)控制也可以用Random來(lái)實(shí)現(xiàn)指數(shù)退避。這種 utilities + 循環(huán) 的組合可以實(shí)現(xiàn)靈活可復(fù)用的重試機(jī)制。
圖片
接口請(qǐng)求重試時(shí)需要注意以下幾點(diǎn):
3.1 冪等性接口需要是冪等的,多次調(diào)用結(jié)果相同,避免重復(fù)執(zhí)行帶來(lái)副作用。
3.2 資源競(jìng)爭(zhēng)重試可能對(duì)服務(wù)端造成更大壓力,需要考慮限流等措施。
3.3 超時(shí)設(shè)置合理設(shè)置重試最大次數(shù)和總超時(shí)時(shí)間,避免長(zhǎng)時(shí)間等待。
3.4 重試條件明確哪些異常情況下需要重試,不能無(wú)腦重試所有錯(cuò)誤。
3.5 數(shù)據(jù)一致性請(qǐng)求成功后要冪等更新?tīng)顟B(tài),避免重復(fù)數(shù)據(jù)。
3.6 異步機(jī)制重試過(guò)程不要阻塞主業(yè)務(wù)線程。
3.7 退避策略失敗后延遲一段時(shí)間再重試,可選避免集群重試。
3.8 日志記錄記錄重試的次數(shù)、錯(cuò)誤原因等信息,方便排查問(wèn)題。
3.9 容錯(cuò)機(jī)制重試失敗后的降級(jí)處理,避免級(jí)聯(lián)失敗。
接口請(qǐng)求重試機(jī)制對(duì)保證系統(tǒng)高可用非常關(guān)鍵,需要根據(jù)業(yè)務(wù)需求選擇合適的重試策略。常用的組合策略包括帶最大次數(shù)的定時(shí)/指數(shù)退避重試、故障轉(zhuǎn)移重試等。重試機(jī)制需要綜合設(shè)置以達(dá)到容錯(cuò)效果 又避免產(chǎn)生過(guò)大的系統(tǒng)負(fù)載。
本文鏈接:http://www.tebozhan.com/showinfo-26-17165-0.html聊聊接口重試機(jī)制的幾種解決方案
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
下一篇: 如何釋放React?Hooks的力量