超时重试是一种用于网络通信的常用策略,目的是在请求未能在规定时间内获得响应或响应超时的情况下,重新发送请求。具体来说,当发起请求后,如果在设定的时间内未能收到预期的响应,就会启动超时重试机制,重新发送该请求。超时重试的主要目标是提高请求的可靠性和稳定性,以应对网络不稳定、服务不可用、响应延迟等情况。
简单来说,超时重试就像是给网络请求设置了一个"保底方案"。假设你在网上购物时提交了一个订单请求,但由于网络原因,这个请求没有及时得到响应。超时重试机制就会在一定时间内再次发送这个请求,直到成功或者达到最大重试次数为止。
举个例子,想象一下你正在给朋友发信息,但发出去后没有收到“已读”回执,你可能会等一会儿再重新发送这条信息。超时重试机制就是这样一个过程,但它是自动完成的,不需要人工干预。这个机制能提高请求的成功率,确保在网络不稳定或者服务暂时不可用时,系统仍能保持较高的可靠性和稳定性。
通过这种方式,即使网络出现短暂的问题,用户的请求也能在多次尝试后最终成功,大大提升了用户体验和系统的健壮性。
在微服务架构中,服务之间通过网络进行通信,而网络环境往往具有复杂性和不稳定性。因此,在调用服务时可能会出现失败或超时的情况。为了解决这些问题,Spring Cloud OpenFeign 提供了超时重试机制。
OpenFeign 超时重试步骤
1. 设置OpenFeign超时时间 (设置完才能实现超时功能, 有了超时功能才能完成重试操作)
- 请求最大连接时间
- 读取时间
2. 进行重试操作.(重试功能)
- 重试次数
- 重试间隔时间
- 最大间隔时间
前文示例回顾
以上文项目示例为例, 项目中有两个模块, 一个是生产者 provider, 一个是消费者 consumer.
生产者 provider 提供了 getnamebyid 服务, 该服务对于 consumer 来说是一个远程服务(多模块, 微服务), 也就是该接口是一个远程接口.
消费者 consumer 则使用 OpenFeign + Loadbalancer + Nacos 进行调用:
在 consumer 里面会有一个 service, 在 service 里面使用了 OpenFeign 调用了 nacos-discovery-demo 的服务, 在服务中请求了远程接口 /user/getnamebyid, 得到了一个响应结果, 然后对它进行展示.
OpenFeign 超时重试配置
OpenFeign 默认情况下是不会自动开启超时重试的,所以想要开启超时重试,需要通过以下 2 步来实现:
- 配置超时重试
- 覆盖 Retryer 对象
配置服务消费者超时时间
spring:
application:
name: nacos-consumer-demo
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
register-enabled: false
openfeign:
client:
config:
default:
connect-timeout: 1000 # 连接超时时间
read-timeout: 1000 # 读取超时时间
server:
port: 8080
开启超时重试
在IoC容器注入Retry对象, 使用的时候new即可.
package org.example.consumer.config;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RetryConfig {
@Bean
public Retryer retryer() {
return new Retryer.Default(
1000, // 重试间隔时间
1000, // 最大重试间隔时间
3 // 最大重试次数
);
}
}
示例代码
在provider中加入, 使服务超时的代码:
在消费者中配置超时重试:
启动生产者与消费者, 然后访问 getnamebyid 接口, 可以看到超时异常:
自定义超时重试机制
自定义超时重试机制的实现分为以下两步:
- 自定义超时重试类(实现 Retryer 接口,并重写 continueOrPropagate 方法)
- 设置配置文件。
创建一个超时重传的类
实现 Retryer 接口并重写 continueOrPropagate 方法
package org.example.consumer.config;
import feign.RetryableException;
import feign.Retryer;
import java.time.LocalDateTime;
public class CustomRetryer implements Retryer {
private final int maxAttempts; // 最大尝试次数
private final long backoff; // 超时间隔时间
int attempt; // 当前尝试次数
public CustomRetryer() {
this.maxAttempts = 3;
this.backoff = 1000L;
this.attempt = 0;
}
@Override
public void continueOrPropagate(RetryableException e) {
if (attempt++ >= maxAttempts) {
throw e;
}
long interval = this.backoff;
System.out.println(LocalDateTime.now() + " | 执行一次重试: " + interval);
try {
Thread.sleep(interval * attempt);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
@Override
public Retryer clone() {
return new CustomRetryer();
}
}
将自定义类设置到配置文件中
将自定义超时重传类设置到配置文件 OpenFeign... retryer 属性中
就可以运行查看效果了.