您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

聊聊接口重试机制的几种解决方案

时间:2023-11-06 14:57:25  来源:微信公众号  作者:架构殿堂

1.前言

接口请求重试机制是保证系统稳定性和容错能力的重要手段之一。当接口请求发生失败或暂时性错误时,通过重试机制可以提高请求的成功率。本文将详细介绍接口请求重试机制的几种常见方法。


 

2.几种方法

聊聊接口重试机制的几种解决方案

2.1循环重试

它的基本思路是:

  1. 定义重试次数,如最大重试5次

  2. 发送请求,如果失败则进入重试逻辑

  3. 在循环内部,记录当前已重试次数,如当前已重试2次

  4. 判断当前重试次数是否达到最大次数,如果达到则终止循环,否则进行重试

  5. 在循环内部,可以添加定时重试间隔,也可以使用指数退避算法

  6. 发送重试请求,重复判断是否成功,直到成功、达到最大次数或其他终止条件

 

示例

public class Retry {

private static final int MAX_RETRIES = 5;

public static Response request() throws Exception {
  int retries = 0;
  while (true) {
    try {
      // 发送请求,返回响应
      Response response = HttpClient.sendRequest();

      // 请求成功则返回响应
      if (response.isSuccess()) {
        return response;
      }

    } catch (Exception e) {
      // 请求失败进行重试
    }

    // 判断是否超过最大重试次数
    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();
  // ...
}

}

 

2.2 使用Spring Retry库

使用 Spring Retry 库可以很方便地实现接口请求的重试机制。

 

2.2.1 添加 Maven 依赖
<dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
  <version>1.3.1</version>
</dependency>

 

2.2.2 添加 @EnableRetry 注解启用重试功能

 

2.2.3 在需要重试的方法上添加 @Retryable 注解
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 5000))
public User getUser(String id) {
// 远程调用接口
}

@Retryable 定义了重试规则:- value - 重试的异常类型- maxAttempts - 最大重试次数- backoff - 重试等待策略

 

2.2.4. 还可以自定义 RetryTemplate 进行更复杂的重试控制
RetryTemplate template = new RetryTemplate();

template.execute(context -> {
// 可在此处自定义重试逻辑
 
return remoteClient.invoke();
});

Spring Retry 为接口请求重试提供了完善和易用的解决方案,可以灵活控制各种重试参数,适用于复杂系统的容错要求。

 

2.3 并发框架异步重试

使用并发框架的异步请求方式可以较简单地实现接口请求的重试机制。以CompletableFuture为例:

 

2.3.1 发送请求使用CompletableFuture封装:

CompletableFuture<Response> future = CompletableFuture.supplyAsync(() -> {
return service.call();
});

 

2.3.2 当请求失败时,使用retryAsync自动完成重试:

future = future.exceptionally(e -> {
return service.retryAsync();
});

 

2.3.3 可以链式调用,自定义重试逻辑:

future
.exceptionally(e -> {
    // 处理异常
})
.thenApplyAsync(resp -> {
    // 处理响应
})
.retryAsync(retryCount, delay);

主要优点是:

  • 线程安全的异步请求

  • 自动重试失败任务

  • 简洁的链式编程方式

  • 避免阻塞主线程

 

使用并发框架可以便捷地实现异步重试机制,提高系统容错性。其他框架如RxJAVA也有类似的重试机制。

 

2.4 消息队列重试

使用消息队列可以实现接口请求的异步重试机制。

基本思路是:

  1. 接口请求发送失败后,将请求信息封装为消息,发送到请求重试的队列中。

  2. 消息消费者从队列中获取失败的请求,根据策略进行重试。

  3. 重复重试直到成功、重试次数用尽或其他终止条件。

  4. 成功后将消息移除队列,失败则保留消息供再次重试。

     

主要步骤:

  1. 创建请求重试队列,如“request.retry.queue”

  2. 接口请求失败后,生成重试消息,发送到队列

  3. 消费者启动线程从队列中取消息重试

  4. 根据重试策略进行定时重试或最大重试数

  5. 成功则确认消息,失败则重新入队

     

使用消息队列进行重试有利于:

  • 异步重试,不阻塞主线程

  • 可靠地完成重试任务

  • 灵活控制重试策略

 

示例

// 1. 创建队列
Queue retryQueue = new Queue("request.retry.queue");

// 2. 请求失败,发送重试消息  
public void request() {
try {
  // 调用接口
  httpClient.post(url, payload);
} catch (Exception e) {
  // 发送重试消息
  Message msg = new Message(url, payload, maxRetries);
  retryQueue.send(msg);
}
}

// 3. 消费者线程进行重试
class RetryConsumer implements Runnable {

public void run() {
  while (true) {
    Message msg = retryQueue.take();
     
    for (int i = 0; i < msg.getMaxRetries(); i++) {
      try {
        // 重试请求
        httpClient.post(msg.getUrl(), msg.getPayload());
        // 请求成功,结束循环
        break;
      } catch (Exception e) {
        // 等待后继续重试
      }  
    }
     
    // 重试完成后,确认消息
    retryQueue.confirm(msg);
  }
}
}

这就是使用消息队列实现接口重试的基本流程,可以根据需求扩展重试策略、异常处理等逻辑。

 

2.5 自定义重试工具类

使用自定义的重试工具类来实现接口请求的重试机制,提高代码的复用性和可维护性。

 

重试工具类的实现思路:

  1. 提供重试方法,参数包括请求函数、重试策略等

  2. 在重试方法内部执行循环请求

  3. 每次请求失败时,根据策略等待一段时间

  4. 记录当前重试次数,与最大次数比较

  5. 请求成功或者达到最大重试次数则结束循环

 

示例:

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();
      // 重试次数加1
      retries++;
    }
  }
}

}

// 执行请求的函数接口
interface RetryCallable<T> {
T call();
}

// 重试策略
class RetryPolicy {
int maxRetries;
int delay;
}

// 使用示例
RetryUtil.retry(() -> {
// 接口请求
return httpClient.get(url);
}, policy);

这样可以提高重试相关逻辑的复用性,避免写重复代码。

 

2.6 使用递归结构

使用递归结构也可以实现接口请求的重试机制。

 

基本思路是设计一个递归函数,在函数内部发送请求,如果失败则继续递归调用自身再次重试。

示例:

public class RetryRequest {

private static final int MAX_RETRIES = 3;
 
public static Response request(int retries) {
   
  try {
    // 发送请求
    Response response = HttpClient.get("http://example.com");
    return response;
     
  } catch (Exception e) {
     
    // 处理异常
     
    // 判断是否需要重试
    if (retries < MAX_RETRIES) {
      // 增加重试次数
      retries++;
      // 延迟1秒钟
      Thread.sleep(1000);
      // 递归调用自身进行重试
      return request(retries);
    }
     
    // 重试失败
    throw new RuntimeException("Request failed after " + MAX_RETRIES + " retries!");
     
  }
}
 
public static void main(String[] args) {  
  Response response = request(0);
  // 处理响应
}

}

 

主要逻辑是通过递归不断调用自身来实现重试。优点是逻辑较简单清晰,缺点是递归层次过深时可能会导致堆栈溢出。需要合理设置最大递归深度,也可以通过循环改写递归来避免深层递归。

 

2.7 使用Resilience4j

Resilience4j是一个很好的Java重试库,可以用它来实现接口请求的重试机制。

 

主要步骤:

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 使用重试逻辑调用接口

String result = retry.executeSupplier(() -> {

// 发送请求
return backendService.callAPI();

});

2.7.4 自定义重试异常predicate

RetryConfig config = RetryConfig.custom()
.retryOnException(e -> isRetryable(e))
.build();

Resilience4j提供了线程安全的重试 decorator,可以通过配置灵活控制重试策略,很好地支持了接口请求重试。

 

2.8 使用网络工具重试

我们常用的一些网络工具来做重试

 

示例

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发送请求
      return HttpClientUtils.get(url);
       
    } catch (Exception e) {

      if (retries >= MAX_RETRIES) {
        throw e;
      }
       
      // 增加重试次数
      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);
}

}

// 网络工具类
class HttpClientUtils {

public static String get(String url) throws IOException {
  // 发送GET请求并返回结果
}

}

 

主要通过循环和网络工具类来实现重试逻辑,延时控制也可以用Random来实现指数退避。这种 utilities + 循环 的组合可以实现灵活可复用的重试机制。

 


 

3.注意事项

聊聊接口重试机制的几种解决方案

接口请求重试时需要注意以下几点:

3.1 幂等性接口需要是幂等的,多次调用结果相同,避免重复执行带来副作用。

3.2 资源竞争重试可能对服务端造成更大压力,需要考虑限流等措施。

3.3 超时设置合理设置重试最大次数和总超时时间,避免长时间等待。

3.4 重试条件明确哪些异常情况下需要重试,不能无脑重试所有错误。

3.5 数据一致性请求成功后要幂等更新状态,避免重复数据。

3.6 异步机制重试过程不要阻塞主业务线程。

3.7 退避策略失败后延迟一段时间再重试,可选避免集群重试。

3.8 日志记录记录重试的次数、错误原因等信息,方便排查问题。

3.9 容错机制重试失败后的降级处理,避免级联失败。

 

总结

接口请求重试机制对保证系统高可用非常关键,需要根据业务需求选择合适的重试策略。常用的组合策略包括带最大次数的定时/指数退避重试、故障转移重试等。重试机制需要综合设置以达到容错效果 又避免产生过大的系统负载。



Tags:接口   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
马斯克脑机接口再造奇迹:瘫痪小伙意念玩赛车击败正常人
马斯克脑机接口公司的首位志愿者,又给我们展现了一段“绝活”:  肩部以下全无知觉的他,只靠脑中的一块芯片,就打起了马里奥赛车游戏。  只见赛车前进、转弯,控制得相当灵活。...【详细内容】
2024-03-26  Search: 接口  点击:(22)  评论:(0)  加入收藏
中国移动董事长杨杰谈脑机接口:假若真能实现,将真正实现人的永生
每经记者:杨卉 每经编辑:梁枭今日(3月21日)晚间,中国移动(SH600941,股价102.68元,市值2.2万亿元)披露了2023年业绩数据。公司营业收入突破万亿元大关,其中通信服务收入8635亿元,同比增...【详细内容】
2024-03-22  Search: 接口  点击:(12)  评论:(0)  加入收藏
瘫痪8年小哥植入马斯克脑机接口,狂打8小时「文明6」!Neuralink首个人类植入者直播来了
一名因潜水事故导致肩部以下瘫痪八年的 29 岁男子,正在借助脑机接口设备重温在线国际象棋和杀时间大作游戏《文明 6》。这是脑机接口公司 Neuralink 最新一场直播的内容,迅速...【详细内容】
2024-03-21  Search: 接口  点击:(23)  评论:(0)  加入收藏
脑机接口将为人类带来什么
◎实习记者 蒋 捷 实习生 杨茜茹怎样才能突破身体的限制,用意识与万物相连?在《西游记》中,孙悟空拥有凭借意念隔空取物的超能力。如今,脑机接口技术可以建立大脑与外部设备的直...【详细内容】
2024-02-29  Search: 接口  点击:(29)  评论:(0)  加入收藏
马斯克:首位脑机接口受试者可通过意念控制鼠标
当地时间周一(19日)晚上的一次活动中,马斯克透露了旗下的脑机接口公司Neuralink首位人类受试者的最新进展。他表示,该受试者已经完全康复,并可以通过大脑控制电脑鼠标。在社交媒...【详细内容】
2024-02-21  Search: 接口  点击:(32)  评论:(0)  加入收藏
如何防止被恶意刷接口?
前言在面试时,经常会被问一个问题:如何防止别人恶意刷接口?这是一个非常有意思的问题,防范措施挺多的。今天这篇文章专门跟大家一起聊聊,希望对你会有所帮助。图片1 防火墙防火墙...【详细内容】
2024-02-19  Search: 接口  点击:(38)  评论:(0)  加入收藏
芯片植入人脑待长期评估,马斯克脑机接口终极目标:人与AI共生
&middot;伦敦国王学院植入式医疗设备教授认为,Neuralink在与参与者一起训练系统前,要给参与者时间恢复。真正的成功需要长期评估脑机接口的稳定性和对参与者的好处。&middot;...【详细内容】
2024-02-01  Search: 接口  点击:(84)  评论:(0)  加入收藏
双头Type-C接口:解析充电方向的奥秘
随着科技的飞速发展,电子设备之间的连接与充电方式也在不断地革新。其中,Type-C接口以其高效、便捷的特性,逐渐成为了主流。特别是双头Type-C线,更是为用户带来了前所未有的便利...【详细内容】
2024-01-02  Search: 接口  点击:(147)  评论:(0)  加入收藏
光纤跳线接口型号有哪些
光纤跳线接口型号通常包括SC、LC、FC、ST、MT-RJ、MU、CWDM、DWDM等多种类型。以下是一些常见的光纤跳线接口型号: SC接口:SC接口是一种常用的短距离连接器接口,通常用于光纤到...【详细内容】
2023-12-15  Search: 接口  点击:(102)  评论:(0)  加入收藏
Spring6提供的四种远程接口调用神器!你知道那种?
1. 介绍Spring 6是一个非常强大的框架,它提供了许多工具和接口来简化远程接口调用。其中,WebClient、RestTemplate、HTTP Interface和RestClient是四种方式。WebClient是Sprin...【详细内容】
2023-12-11  Search: 接口  点击:(191)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条