如何配置 OpenFeign 超时重试机制?

本篇文章的代码 demo 是Nacos + OpenFeign:微服务中的服务注册、发现与调用 - 掘金 (juejin.cn)这一篇的,建议先阅读上一篇。

1.OpenFeign 的超时重试机制

在微服务架构中,服务之间是通过网络进行通信的,所以有的时候会经历网络异常或者服务响应超时。这时我们就需要给 OpenFeign 配置超时重试机制。OpenFeign 提供了一个 Retryer 接口,用于定义重试的逻辑和参数,例如重试的次数、间隔时间、最大间隔时间等。

1.1 配置超时时间

在模块consumer的配置文件中添加:

yml 复制代码
spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            connect-timeout: 1000 # 连接超时时间 1s
            read-timeout: 1000 # 读取超时时间 1s

1.2 配置重试机制

在配置类中定义一个RetryerBean

java 复制代码
@Configuration
public class RetryerConfig {
    @Bean
    public Retryer retryer(){
        return new Retryer.Default(
                1000, 		//重试间隔时间
                1000,       //最大重试间隔时间
                3           //最大重试次数
        );
    }
}

1.3 测试超时重试机制

在生产者模块pro_1中:

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/getname")
    public String getNameById(Integer id) throws InterruptedException {
        System.out.println("---------超时重试中ing------------" + LocalDateTime.now());
        //睡眠 1.5s 模拟超时
        Thread.sleep(1500);
        return "lishi-"+id+"-pro_1";
    }
}

消费者consumer调用pro_1中的"/user/getname"接口:

service:

java 复制代码
@Service
@FeignClient("nacosRegisterDemo1") //表示调用 nacos 中的 nacosRegisterDemo1 服务
public interface UserService {

    /**
     * 调用"/user/getname接口"
     * @param id
     * @return
     */
    @RequestMapping("/user/getname" )
    String getNameById(@RequestParam("id") Integer id);
}

Controller:

java 复制代码
@RestController
public class BusinessController {

    @Autowired
    private UserService userService;

    @RequestMapping("/getnamebyid")
    public String getNameById(Integer id){
        return userService.getNameById(id);
    }
}

访问"/getnamebyid"

显然访问失败。因为在pro_1我们设置睡眠1.5s,超过了read-timeout(读取超时时间)1s。这时会启动重试机制,不断尝试读取,可惜的是每次都将会超时,当重复最大重试次数过后还是超时的话就直接报错。

pro_1的日志:

重试了 3 次(第一次也算进重试次数),也印证了超时重试机制启动成功。

2.自定义超时重试机制

除了使用自带的超时重试机制,还可以自定义超时重试机制。

2.1 自定义超时重试类

实现 Retryer 接口,重写 continueOrPropagate 方法。

java 复制代码
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;
    }

    public CustomRetryer(int maxAttempts, long backoff) {
        this.maxAttempts = maxAttempts;
        this.backoff = backoff;
        this.attempt = 0;
    }

    
    @Override
    public void continueOrPropagate(RetryableException e) {
        if(attempt++ >= maxAttempts){
            throw e;
        }
        long interval = this.backoff; //重试间隔时间
        try {
            Thread.sleep(interval * attempt); //间隔时间线性增加
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public Retryer clone() {
        return new CustomRetryer();
    }
}

continueOrPropagate 方法是 Retryer 接口中最重要的方法,它接受一个 RetryableException 作为参数,没有返回值。当执行这个方法时,它要么抛出一个异常,要么成功退出(通常是在休眠一段时间后)。如果它没有抛出异常,Feign 将继续重试调用。如果抛出异常,它将被传播,从而有效地以错误结束调用。

Feign 客户端创建一个新的调用时,它会调用 clone 方法来获取一个新的 Retryer 实例,以避免重试状态的混乱。

这里的超时重试策略就是线性增加(每次增加 1s )。还有其它的常见策略:

  1. 固定间隔:每次重试之间的时间间隔固定不变。
  2. 指数间隔:每次重试之间的时间间隔按指数递增。
  3. 随机间隔:每次重试之间的时间间隔是随机的。

2.2 设置配置文件

yml 复制代码
spring:
  application:
    name: nacosRegisterDemo1
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        register-enabled: false # 不需要注册到注册中心
    openfeign:
      client:
        config:
          default:
            connect-timeout: 1000 # 连接超时时间 1s
            read-timeout: 1000 # 读取超时时间
            retryer: com.example.consumer.config.CustomRetryer # 设置自定义重试类

必须得指定该重试类才能生效。

2.3 测试自定义超时重试机制

根据时间变化可以看出我们自定义的超时重试机制生效了。

相关推荐
技术无疆10 分钟前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
罗政3 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
架构文摘JGWZ3 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
拾光师4 小时前
spring获取当前request
java·后端·spring
aPurpleBerry4 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
我是苏苏4 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
xujinwei_gingko4 小时前
Spring IOC容器Bean对象管理-Java Config方式
java·spring
2301_789985944 小时前
Java语言程序设计基础篇_编程练习题*18.29(某个目录下的文件数目)
java·开发语言·学习
IT学长编程4 小时前
计算机毕业设计 教师科研信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·毕业设计·springboot·毕业论文·计算机毕业设计选题·计算机毕业设计开题报告·教师科研管理系统
m0_571957584 小时前
Java | Leetcode Java题解之第406题根据身高重建队列
java·leetcode·题解