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

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

開(kāi)發(fā) 前端
這篇文章跟大家一起聊聊接口重試的8種常用方案,希望對(duì)你會(huì)有所幫助。?

2025年某電商平臺(tái)深夜故障,因重試策略不當(dāng)導(dǎo)致銀行退款接口被調(diào)用82次,引發(fā)重復(fù)退款126萬(wàn)元!

復(fù)盤(pán)發(fā)現(xiàn):80%的開(kāi)發(fā)者認(rèn)為重試就是for循環(huán)+Thread.sleep(),卻忽略了重試風(fēng)暴、冪等性缺失、資源雪崩等致命問(wèn)題。

這篇文章跟大家一起聊聊接口重試的8種常用方案,希望對(duì)你會(huì)有所幫助。

一、重試機(jī)制的原因

1.為什么需要重試?

臨時(shí)性故障占比超70%,合理重試可將成功率提升至99%以上。

2.重試的三大陷阱

  • 重試風(fēng)暴:固定間隔重試引發(fā)請(qǐng)求洪峰(如萬(wàn)次重試壓垮服務(wù))
  • 數(shù)據(jù)不一致:非冪等操作導(dǎo)致重復(fù)生效(如重復(fù)扣款)
  • 鏈路阻塞:長(zhǎng)時(shí)重試耗盡線程資源(如數(shù)據(jù)庫(kù)連接池枯竭)

二、基礎(chǔ)重試方案

1.暴力輪回法(青銅)

問(wèn)題代碼:

// 危險(xiǎn)!切勿直接用于生產(chǎn)!
public void sendSms(String phone) {
    int retry = 0;
    while (retry < 5) {
        try {
            smsClient.send(phone);
            break;
        } catch (Exception e) {
            retry++;
            Thread.sleep(1000); // 固定1秒間隔
        }
    }
}

事故案例:某平臺(tái)短信接口重試風(fēng)暴,觸發(fā)第三方熔斷封禁。

優(yōu)化方向:增加隨機(jī)抖動(dòng) + 異常過(guò)濾。

2.Spring Retry(黃金)

聲明式注解控制重試:

@Retryable(
    value = {TimeoutException.class}, // 僅重試超時(shí)異常
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000, multiplier = 2) // 指數(shù)退避:1s→2s→4s
)
public boolean queryOrder(String orderId) {
    return httpClient.get("/order/" + orderId);
}

@Recover // 兜底降級(jí)
public boolean fallback(TimeoutException e) {
    return false; 
}

優(yōu)勢(shì):

  • 注解驅(qū)動(dòng),業(yè)務(wù)零侵入
  • 支持指數(shù)退避策略
  • 無(wú)縫集成熔斷器@CircuitBreaker

三、高階重試方案

1.Resilience4j(白金)

應(yīng)對(duì)高并發(fā)場(chǎng)景的重試+熔斷組合拳:

// 重試配置:指數(shù)退避+隨機(jī)抖動(dòng)
RetryConfig retryConfig = RetryConfig.custom()
    .maxAttempts(3)
    .intervalFunction(IntervalFunction.ofExponentialRandomBackoff(
        1000L, 2.0, 0.3// 初始1s,指數(shù)倍率2,抖動(dòng)率30%
    ))
    .retryOnException(e -> e instanceof TimeoutException)
    .build();

// 熔斷配置:錯(cuò)誤率超50%觸發(fā)熔斷
CircuitBreakerConfig cbConfig = CircuitBreakerConfig.custom()
    .slidingWindow(10, 10, COUNT_BASED) 
    .failureRateThreshold(50)
    .build();

// 組合裝飾
Supplier<Boolean> supplier = () -> paymentService.pay();
Supplier<Boolean> decorated = Decorators.ofSupplier(supplier)
    .withRetry(Retry.of("payment", retryConfig))
    .withCircuitBreaker(CircuitBreaker.of("payment", cbConfig))
    .decorate();

效果:某支付系統(tǒng)接入后超時(shí)率下降60%,熔斷觸發(fā)率降低90%

2.Guava-Retrying(鉆石)

靈活定制復(fù)雜重試邏輯:

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
    .retryIfResult(Predicates.equalTo(false)) // 返回false重試
    .retryIfExceptionOfType(IOException.class)
    .withWaitStrategy(WaitStrategies.exponentialWait(1000, 30, TimeUnit.SECONDS))
    .withStopStrategy(StopStrategies.stopAfterAttempt(5))
    .build();

retryer.call(() -> uploadService.upload(file)); // 執(zhí)行

核心能力:

  • 支持結(jié)果/異常雙模式觸發(fā)
  • 提供7種等待策略(隨機(jī)、指數(shù)、遞增等)
  • 可監(jiān)聽(tīng)每次重試事件

四、分布式重試方案

1.MQ延時(shí)隊(duì)列(星耀Ⅰ)

適用場(chǎng)景:異步解耦的高并發(fā)系統(tǒng)(如物流狀態(tài)同步)

架構(gòu)原理:

RocketMQ實(shí)現(xiàn):

// 生產(chǎn)者發(fā)送延時(shí)消息
Message msg = new Message();
msg.setBody(orderData);
msg.setDelayTimeLevel(3); // RocketMQ預(yù)設(shè)10秒延遲
rocketMQTemplate.send(msg);

// 消費(fèi)者
@RocketMQMessageListener(topic = "RETRY_TOPIC")
publicclass RetryConsumer {
    public void consume(Message msg) {
        try {
            process(msg);
        } catch (Exception e) {
            // 提升延遲級(jí)別重發(fā)
            msg.setDelayTimeLevel(5); 
            resend(msg);
        }
    }
}

優(yōu)勢(shì):

  • 重試與業(yè)務(wù)邏輯解耦
  • 天然支持梯度延時(shí)
  • 死信隊(duì)列兜底人工處理

2.定時(shí)任務(wù)補(bǔ)償(星耀Ⅱ)

適用場(chǎng)景:允許延遲的批處理任務(wù)(如文件導(dǎo)入)

@Scheduled(cron = "0 0/5 * * * ?") // 每5分鐘執(zhí)行
public void retryFailedTasks() {
    List<FailedTask> tasks = taskDao.findFailed(MAX_RETRY);
    tasks.forEach(task -> {
        if (retry(task)) {
            task.markSuccess();
        } else {
            task.incrRetryCount();
        }
        taskDao.update(task);
    });
}

關(guān)鍵點(diǎn):

  • 數(shù)據(jù)庫(kù)記錄失敗任務(wù)
  • 低峰期批量處理
  • 獨(dú)立線程池隔離資源

3.兩階段提交(王者Ⅰ)

金融級(jí)一致性保障(如轉(zhuǎn)賬):

@Transactional
public void transfer(TransferRequest req) {
    // 階段1:持久化操作流水
    TransferRecord record = recordDao.create(req, PENDING);
    
    // 階段2:調(diào)用銀行接口
    boolean success = bankClient.transfer(req);
    
    // 更新?tīng)顟B(tài)
    recordDao.updateStatus(record.getId(), success ? SUCCESS : FAILED);
    
    if (!success) {
        mqTemplate.send("TRANSFER_RETRY_QUEUE", req); // 觸發(fā)異步重試
    }
}

// 補(bǔ)償任務(wù)(掃描掛起流水)
@Scheduled(fixedRate = 30000)
public void compensate() {
    List<TransferRecord> pendings = recordDao.findPending(30);
    pendings.forEach(this::retryTransfer);
}

核心思想:操作前先留痕,任何失敗可追溯

4.分布式鎖重試(王者Ⅱ)

防重復(fù)提交終極方案(如秒殺):

public boolean retryWithLock(String key, int maxRetry) {
    String lockKey = "RETRY_LOCK:" + key;
    for (int i = 0; i < maxRetry; i++) {
        if (redis.setIfAbsent(lockKey, "1", 30, SECONDS)) {
            try {
                return callApi(); // 持有鎖時(shí)執(zhí)行
            } finally {
                redis.delete(lockKey);
            }
        }
        Thread.sleep(1000 * (i + 1)); // 等待鎖釋放
    }
    return false;
}

適用場(chǎng)景:

  • 多實(shí)例部署環(huán)境
  • 高競(jìng)爭(zhēng)資源訪問(wèn)
  • 等冪性要求極高業(yè)務(wù)

五、響應(yīng)式重試:Spring WebFlux方案

1.響應(yīng)式重試操作符

Mono<String> remoteCall = Mono.fromCallable(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("模擬失敗");
    return "Success";
});

remoteCall.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))
          .doBeforeRetry(signal -> log.warn("第{}次重試", signal.totalRetries()))
          .subscribe();

策略支持:

  • 指數(shù)退避:Retry.backoff(maxAttempts, firstBackoff)
  • 隨機(jī)抖動(dòng):.jitter(0.5)
  • 條件過(guò)濾:.filter(ex -> ex instanceof TimeoutException)

六、重試的避坑指南

1.必須實(shí)現(xiàn)的三大防護(hù)

防護(hù)類(lèi)型

目的

實(shí)現(xiàn)方案

冪等性防護(hù)

防止重復(fù)生效

唯一ID+狀態(tài)機(jī)

重試風(fēng)暴防護(hù)

避免洪峰沖擊

指數(shù)退避+隨機(jī)抖動(dòng)

資源隔離

保護(hù)主鏈路資源

線程池隔離/熔斷器

2.經(jīng)典踩坑案例

  • 坑1:無(wú)限制重試→ 某系統(tǒng)因未設(shè)重試上限,線程池爆滿(mǎn)導(dǎo)致集群雪崩
  • 解法maxAttempts=3 + 熔斷降級(jí)
  • 坑2:忽略錯(cuò)誤類(lèi)型→ 參數(shù)錯(cuò)誤(4xx)被反復(fù)重試,放大無(wú)效流量
  • 解法:retryOnException(e -> e instanceof TimeoutException)
  • 坑3:上下文丟失→ 異步重試后丟失用戶(hù)會(huì)話(huà)信息
  • 解法:重試前快照關(guān)鍵上下文(如userId、requestId)

七、方案選型參考圖

總結(jié)

  • 敬畏每一次重試:重試不是暴力補(bǔ)救,而是精密流量控制。
  • 面向失敗設(shè)計(jì):假設(shè)網(wǎng)絡(luò)不可靠、服務(wù)會(huì)宕機(jī)、資源終將枯竭。
  • 分層防御體系

a.代碼層:冪等性 + 超時(shí)控制

b.框架層:退避策略 + 熔斷降級(jí)

c.架構(gòu)層:異步解耦 + 持久化補(bǔ)償

  • 沒(méi)有銀彈:秒殺場(chǎng)景用分布式鎖,支付系統(tǒng)用兩階段提交,IoT設(shè)備用MQTT重試機(jī)制。

正如分布式系統(tǒng)大師Leslie Lamport所言:“重試是分布式系統(tǒng)的成人禮”。

掌握這8種方案,你將擁有讓系統(tǒng)“起死回生”的魔法!

責(zé)任編輯:姜華 來(lái)源: 蘇三說(shuō)技術(shù)
相關(guān)推薦

2025-03-11 08:20:58

2022-12-12 08:14:47

2024-11-12 08:20:31

2025-05-30 08:20:54

2025-04-08 08:20:33

2024-10-24 08:21:33

2025-03-06 08:21:02

判空entity對(duì)象

2024-12-02 00:59:30

Spring

2025-04-22 08:20:51

2025-02-28 08:21:00

2020-11-03 16:00:33

API接口微服務(wù)框架編程語(yǔ)言

2020-11-17 09:34:31

API接口后端

2022-06-10 13:03:44

接口重試while

2015-09-24 09:22:16

nodejs頁(yè)面始末

2017-11-12 21:32:52

戴爾

2016-01-08 09:49:19

DockerDocker案例云應(yīng)用開(kāi)發(fā)

2017-09-22 13:22:59

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

2023-12-30 20:04:51

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

2021-07-14 06:31:08

京東互聯(lián)網(wǎng)加薪

2021-01-20 05:42:27

RabbitMQMQ vhost
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)