偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

瞧瞧別人家的接口重試,那叫一個優(yōu)雅!

開發(fā) 前端
對于有些需要自定義退避算法、熔斷策略和多層防護的大中型系統(tǒng)(如支付核心接口),我們可以使用 Resilience4j。

前言

記得五年前的一個深夜,某個電商平臺的訂單退款接口突發(fā)異常,因為銀行系統(tǒng)網絡抖動,退款請求連續(xù)失敗。

原本技術團隊只是想“好心重試幾次”,結果開發(fā)小哥寫的重試代碼竟瘋狂調用了銀行的退款接口 82次!

最終導致用戶賬戶重復退款,平臺損失過百萬。

老板在復盤會上質問:“接口重試這么基礎的事,為什么還能捅出大簍子?”

大家啞口無言,因為所有人都以為只要加個 for 循環(huán),再睡幾秒就完事了……

這篇文章跟大家一起聊聊重試的7種常用方案,希望對你會有所幫助。

1.暴力輪回法

問題場景

某實習生寫的用戶注冊短信發(fā)送接口。

在一個while循環(huán)中,重復調用第三方的發(fā)短信接口給用戶發(fā)送短信。

代碼如下:

public void sendSms(String phone) {
    int retry = 0;
    while (retry < 5) { // 無腦循環(huán)
        try {
            smsClient.send(phone);
            break;
        } catch (Exception e) {
            retry++;
            Thread.sleep(1000); // 固定1秒睡眠
        }
    }
}

事故現(xiàn)場

某次短信服務器出現(xiàn)了過載問題,導致所有請求都延遲了3秒。

這個暴力循環(huán)的代碼在 0.5秒內同時發(fā)起數(shù)萬次重試,直接打爆短信平臺,觸發(fā)了 熔斷封禁,連正常請求也被拒絕。

教訓

  • ?? 不做延遲間隔調整:固定間隔導致重試請求集中爆發(fā)
  • ?? 無視異常類型:非臨時性錯誤(如參數(shù)錯誤)也嘗試重試
  • ?? 修復方案:加上隨機的重試間隔,并過濾不可重試的異常

2.Spring Retry

應用場景

Spring Retry適用于中小項目,通過注解快速實現(xiàn)基本重試和熔斷(如訂單狀態(tài)查詢接口)。

通過聲明@Retryable注解,來實現(xiàn)接口重試的功能。

配置示例

@Retryable(
    value = {TimeoutException.class}, // 只重試超時異常
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000, multiplier = 2) // 1秒→2秒→4秒
)
public boolean queryOrderStatus(String orderId) {
    return httpClient.get("/order/" + orderId);
}

@Recover // 兜底回退方法
public boolean fallback() {
    return false; 
}

優(yōu)勢

  • 聲明式注解:代碼簡潔,與業(yè)務邏輯解耦
  • 指數(shù)退避:自動拉長重試間隔
  • 熔斷集成:結合 @CircuitBreaker 可快速阻斷異常流量

3.Resilience4j

高階場景

對于有些需要自定義退避算法、熔斷策略和多層防護的大中型系統(tǒng)(如支付核心接口),我們可以使用 Resilience4j。

核心代碼如下:

// 1. 重試配置:指數(shù)退避 + 隨機抖動
RetryConfig retryConfig = RetryConfig.custom()
    .maxAttempts(3)
    .intervalFunction(IntervalFunction.ofExponentialRandomBackoff(
        1000L, // 初始間隔1秒
        2.0,   // 指數(shù)倍數(shù)
        0.3    // 隨機抖動系數(shù)
    ))
    .retryOnException(e -> e instanceof TimeoutException)
    .build();

// 2. 熔斷配置:錯誤率超50%時熔斷
CircuitBreakerConfig cbConfig = CircuitBreakerConfig.custom()
    .slidingWindow(10, 10, CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) 
    .failureRateThreshold(50)
    .build();

// 組合使用
Retry retry = Retry.of("payment", retryConfig);
CircuitBreaker cb = CircuitBreaker.of("payment", cbConfig);

// 執(zhí)行業(yè)務邏輯
Supplier<Boolean> supplier = () -> paymentService.pay();
Supplier<Boolean> decorated = Decorators.ofSupplier(supplier)
    .withRetry(retry)
    .withCircuitBreaker(cb)
    .decorate();

效果

某電商大廠上線此方案后,支付接口 超時率下降60% ,且熔斷觸發(fā)頻率降低近 90%

真正做到了“打不還手,罵不還口”。

4.MQ隊列

適用場景

高并發(fā)、允許延時的異步場景(如物流狀態(tài)同步)。

實現(xiàn)原理

  1. 首次請求失敗后,將消息投遞至 延時隊列
  2. 隊列根據(jù)預設的延時時間(如5秒、30秒、1分鐘)重試消費
  3. 若達到最大重試次數(shù),則轉存至 死信隊列(人工處理)

RocketMQ代碼片段如下:

// 生產者發(fā)送延時消息
Message<String> message = new Message();
message.setBody("訂單數(shù)據(jù)");
message.setDelayTimeLevel(3); // RocketMQ預設的10秒延遲級別
rocketMQTemplate.send(message);

// 消費者重試
@RocketMQMessageListener(topic = "DELAY_TOPIC")
public class DelayConsumer {
    @Override
    public void handleMessage(Message message) {
        try {
            syncLogistics(message);
        } catch (Exception e) {
            // 重試次數(shù) + 1,并重新發(fā)送到更高延遲級別
            resendWithDelay(message, retryCount + 1);
        }
    }
}

如何RocketMQ的消費者消費失敗,會自動發(fā)起重試。

5.定時任務

適用場景

對于有些不需要實時反饋,允許批量處理的任務(如文件導入)的業(yè)務場景,我們可以使用定時任務。

在這里以Quartz為例。

具體代碼如下:

@Scheduled(cron = "0 0/5 * * * ?") // 每5分鐘執(zhí)行
public void retryFailedTasks() {
    List<FailedTask> list = failedTaskDao.listUnprocessed(5); // 查失敗任務
    list.forEach(task -> {
        try {
            retryTask(task);
            task.markSuccess();
        } catch (Exception e) {
            task.incrRetryCount();
        }
        failedTaskDao.update(task);
    });
}

6.兩階段提交

適用場景

對于嚴格保證數(shù)據(jù)一致性的場景(如資金轉賬),我們可以使用兩階段提交機制。

關鍵實現(xiàn)

  1. 第一階段:記錄操作流水到數(shù)據(jù)庫(狀態(tài)為“進行中”)
  2. 第二階段:調用遠程接口,并根據(jù)結果更新流水狀態(tài)
  3. 定時補償:掃描超時的“進行中”流水重新提交

大致代碼如下:

@Transactional
public void transfer(TransferRequest req) {
    // 1. 記錄流水
    transferRecordDao.create(req, PENDING);
    
    // 2. 調用銀行接口
    boolean success = bankClient.transfer(req);
    
    // 3. 更新流水狀態(tài)
    transferRecordDao.updateStatus(req.getId(), success ? SUCCESS : FAILED);
    
    // 4. 失敗轉異步重試
    if (!success) {
        mqTemplate.send("TRANSFER_RETRY_QUEUE", req);
    }
}

7.分布式鎖

應用場景

對于一些多服務實例、多線程環(huán)境的防重復提交(如秒殺)的業(yè)務場景,我們可以使用分布式鎖。

這里以Redis + Lua的分布式鎖為例。

代碼如下:

public boolean retryWithLock(String key, int maxRetry) {
    String lockKey = "api_retry_lock:" + key;
    for (int i = 0; i < maxRetry; i++) {
        // 嘗試獲取分布式鎖
        if (redis.setnx(lockKey, "1", 30, TimeUnit.SECONDS)) {
            try {
                return callApi();
            } finally {
                redis.delete(lockKey);
            }
        }
        Thread.sleep(1000 * (i + 1)); // 等待釋放鎖
    }
    return false;
}

總結

重試就像機房里的滅火器——永遠不希望用到它,但必須保證關鍵時刻能救命。

我們工作中選擇哪種方案?

別只看技術潮流,而要看業(yè)務的長矛和盾牌,需要哪種配合。

最后送大家一句話:系統(tǒng)穩(wěn)定的秘訣,是永遠對重試保持敬畏。

責任編輯:武曉燕 來源: 蘇三說技術
相關推薦

2025-07-14 00:00:00

接口重試MQTT冪等性

2022-12-12 08:14:47

2025-05-30 08:20:54

2024-11-12 08:20:31

2025-04-08 08:20:33

2024-10-24 08:21:33

2024-12-02 00:59:30

Spring

2025-04-22 08:20:51

2025-03-06 08:21:02

判空entity對象

2025-02-28 08:21:00

2025-08-19 10:01:43

2020-11-03 16:00:33

API接口微服務框架編程語言

2020-11-17 09:34:31

API接口后端

2022-06-10 13:03:44

接口重試while

2015-09-24 09:22:16

nodejs頁面始末

2017-11-12 21:32:52

戴爾

2016-01-08 09:49:19

DockerDocker案例云應用開發(fā)

2017-09-22 13:22:59

大數(shù)據(jù)南京大學宿舍

2023-12-30 20:04:51

MyBatis框架數(shù)據(jù)

2021-07-14 06:31:08

京東互聯(lián)網加薪
點贊
收藏

51CTO技術棧公眾號