首页 > 数据库 > 数据库开发技术 > OpenFeign重试组件Retryer原理

前言
前面三篇文章已经分析了Feign的通信Client组件,Client是Rpc框架中最核心关键的能力,通过Client发起远程通信。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
市面上的Rpc框架在核心通信能力的基础上,有很多服务治理的组件,OpenFeign也一样,今天主角是重试组件,我们看看OpenFeign是如何实现重试的。
OpenFeign执行远程请求是在feign.SynchronousMethodHandler#invoke,重试组件也是在这里嵌入的,我们看看具体实现
//调用远程入口public Object invoke(Object[] argv) throws Throwable {RequestTemplate template = this.buildTemplateFromArgs.create(argv);Request.Options options = this.findOptions(argv);Retryer retryer = this.retryer.clone();//死循环,如果成功或者重试结束就返回while(true) {try {//通过client发起通信return this.executeAndDecode(template, options);} catch (RetryableException var9) {//处理RetryableException异常RetryableException e = var9;try {//重试组件生效,判断是否重试retryer.continueOrPropagate(e);} catch (RetryableException var8) {Throwable cause = var8.getCause();if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {throw cause;}throw var8;}}}}
发起请求的地方捕获了RetryableException异常,并且执行了重试的逻辑。 Feign提供了两个重试实现
1、feign.Retryer.Default
2、feign.Retryer#NEVER_RETRY

OpenFeign默认使用不重试
从openfeign的装配类FeignClientsConfiguration我们可以看出 在OpenFeign中,默认使用的是NEVER_RETRY,不重试
public class FeignClientsConfiguration {public Retryer feignRetryer() {//默认配置不重试return Retryer.NEVER_RETRY;}}Retryer NEVER_RETRY = new Retryer() {public void continueOrPropagate(RetryableException e) {//异常往外抛,不重试处理throw e;}public Retryer clone() {return this;}};
OpenFeign默认重试组件实现分析
feign.Retryer.Default是OpenFeign实现了重试能力的重试组件,我们看下他源码是如何实现的
public static class Default implements Retryer {private final int maxAttempts;private final long period;private final long maxPeriod;int attempt;long sleptForMillis;public Default() {this(100L, TimeUnit.SECONDS.toMillis(1L), 5);}public Default(long period, long maxPeriod, int maxAttempts) {this.period = period;this.maxPeriod = maxPeriod;this.maxAttempts = maxAttempts;this.attempt = 1;}protected long currentTimeMillis() {return System.currentTimeMillis();}//重试逻辑public void continueOrPropagate(RetryableException e) {//已经超过最大重试次数,不重试了,异常往上抛//attempt默认是1if (this.attempt++ >= this.maxAttempts) {throw e;} else {long interval;//根据上次重试时间计算间隔时间if (e.retryAfter() != null) {interval = e.retryAfter().getTime() - this.currentTimeMillis();//间隔时间是否超过最大重试间隔时间if (interval > this.maxPeriod) {interval = this.maxPeriod;}if (interval < 0L) {return;}} else {//获取下次重试间隔时间interval = this.nextMaxInterval();}try {//睡眠重试间隔,再发起重试Thread.sleep(interval);} catch (InterruptedException var5) {Thread.currentThread().interrupt();throw e;}this.sleptForMillis += interval;}}long nextMaxInterval() {//计算下次重试间隔,按照1.5为底的指数递增long interval = (long)((double)this.period * Math.pow(1.5, (double)(this.attempt - 1)));return interval > this.maxPeriod ? this.maxPeriod : interval;}public Retryer clone() {return new Default(this.period, this.maxPeriod, this.maxAttempts);}}
1、默认重试是捕获RetryableException异常,如果是RetryableException异常则执行重试逻辑。
2、默认重试组件支持配置重试间隔和最大重试次数
3、每次重试间隔按照底数是1.5的,指数为重试次数级递增, 比如 1.5的2次方 1.5的3次方
自定义重试组件
feign.Retryer接口,也可以使用OpenFeign自带的重试组件feign.Retryer.Default,假如我们使用自带的重试组件,我们只要定义一个配置类,配置Retryer的Bean,覆盖默认的Retryer.NEVER_RETRY;每次重试间隔是100ms,最大重试间隔是1s, 重试次数是2次public class CustomFeignConfig {public Integer retryPeriod = 100;public Integer retryMaxPeriod = 1000;public Integer maxRetryAttempts = 2;//自定义重试组件,覆盖OpenFeign默认的Retryer.NEVER_RETRY;public Retryer retryer() {return new Retryer.Default(retryPeriod, retryMaxPeriod, maxRetryAttempts);}}
总结
1、OpenFeign提供了重试组件,默认是不重试的
2、feign.Retryer.Default的实际重试次数是maxAttempts-1
OpenFeign重试组件分析完了,对你有没有帮助呢?
后面将继续分析OpenFeign的其他组件能力。
哈哈都看到这里了,关注我一起学习吧!!
原文作者:服务端技术栈;如有侵权,请联系管理员删除。