重试机制是什么?
网络重试机制是用于在网络通信中处理失败的请求。接口重试可以在一定的时间间隔内多次尝试发送相同的请求,直到请求成功或达到最大重试次数为止。
为什么要重试?
1. 提高请求的成功率:网络通信中可能会出现各种问题,如网络延迟、连接超时、服务器错误等。通过接口重试机制,可以尝试多次发送请求,增加请求成功的可能性。
2. 处理瞬时故障:有时候,请求失败是由于短暂的网络故障或服务器负载过高等瞬时问题引起的。通过接口重试,可以在稍后的尝试中成功发送请求,而无需手动干预。
3. 自动化处理:接口重试可以自动处理请求失败的情况,无需手动干预。这样可以减少开发人员的工作量,并提高系统的稳定性和可靠性。
注意:接口重试并不是万能的解决方案,有时候请求失败可能是由于永久性的问题,如无效的请求参数或者权限不足等。在设计接口重试机制时,需要考虑到这些情况,并设置合理的重试策略和最大重试次数。
重试的场景有哪些?
网络不稳定导致请求失败;
服务端繁忙,导致响应时间过长;
服务端出现故障,导致请求失败;
传参错误等错误,导致请求失败;
第三方接口调用失败,例如:钉钉、微信、权限等。
如何进行重试?
①、固定次数重试
设置一个固定的重试次数,在每次请求失败时都重新发送请求,直到达到最大重试次数或请求成功为止。
②、spring-retry
spring提供的请求重试组件,根据配置的重试策略进行重试
- <dependency>
- <groupId>org.springframework.retry</groupId>
- <artifactId>spring-retry</artifactId>
- </dependency>
开启重试功能:
在启动类或者配置类上添加 @EnableRetry 注解

在需要重试的方法上添加 @Retryable 注解:标志当前方法使用重试机制
@Backoff:等待多久开始重试(指定重试的次数、时间间隔)
默认重试次数是3次,重试间隔是1s
@Retryable(maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 2))
@Recover:当重试达到指定次数之后,会调用指定的方法来进行日志记录等操作
- @Recover
- public void recover(RuntimeException e){
- System.out.println("达到最大重试次数"+e);
- }
注意:@Recover 注解标记的方法必须和被 @Retryable 标记的方法在同一个类中
代码演示:
- @Service
- public class SpringRetryServiceImpl {
- @Autowired
- private LoginServiceImpl loginService;
-
-
- @Retryable(maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 2))
- public String getUserInfo(String id) throws Exception {
- System.out.println("开始时间"+System.currentTimeMillis());
-
- JSONObject bodyJson = loginService.getUserService(id);
- if (!bodyJson.get("code").equals(200)) {
- throw new Exception("失败");
- }
- return "调用成功";
- }
-
- @Recover
- public void recover(Exception e){
- System.out.println("达到最大重试次数"+e);
- }
- }
③、guava-retry
能够根据 返回值 来判断是否需要重试
- @Service
- public class GuavaImpl {
- @Autowired
- private LoginServiceImpl loginService;
-
- public String getUserInfo(String id) throws Exception {
-
- Callable<String> task = new Callable<String>() {
- @Override
- public String call() throws Exception {
- JSONObject bodyJson = loginService.getUserService(id);
- if (!bodyJson.get("code").equals(200)) {
- throw new Exception("失败");
- }
- return "调用成功";
- }
- };
-
- Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
- //无论出现什么异常,都进行重试
- .retryIfException()
- //返回结果为 error时,进行重试
- .retryIfResult(result -> Objects.equals(result, "error"))
- //重试等待策略:等待 2s 后再进行重试
- .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
- //重试停止策略:重试达到 3 次
- .withStopStrategy(StopStrategies.stopAfterAttempt(3))
- .withRetryListener(new RetryListener() {
- @Override
- public <V> void onRetry(Attempt<V> attempt) {
- System.out.println("RetryListener: 第" + attempt.getAttemptNumber() + "次调用");
- }
- })
- .build();
- try {
- retryer.call(task);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return "调用成功";
- }
- }
超时:服务不要一直在服务端进行堆积(影响新请求处理/系统崩溃),请求超过设置时间没有被处理就取消或抛异常
重试:和超时绑定,多次发送相同