如何配置 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 测试自定义超时重试机制

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

相关推荐
JustHappy3 小时前
古法编程秘籍(七):互联网到底是什么?把两台电脑怎么说话搞懂就够了
前端·后端·网络协议
yaoxin5211233 小时前
434. Java 日期时间 API - Period 基于日期的时间段
java·开发语言·python
Hommy883 小时前
【剪映小助手】添加图片接口(Add Images)
后端·github·剪映小助手·视频剪辑自动化
GetcharZp4 小时前
别再盲目用 OpenCV 读图了,这才是 CV 预处理的终极杀手锏!
后端
何极光4 小时前
IDEA集成Maven
java·maven·intellij-idea
程序员二叉4 小时前
【JUC】ThreadLocal底层原理|内存泄漏|弱引用|跨线程传递方案
java·开发语言·面试·职场和发展·juc
程序员二叉4 小时前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
老马识途2.05 小时前
在AI的帮助下理解spring的启动过程
java·前端·spring
青山木5 小时前
Hot 100 --- 轮转数组
java·数据结构·算法
Qt程序员5 小时前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言