1、重试

        重试机制在网络服务中非常的重要,由于网路可能存在延迟,网络抖动,网络不稳定的情况。同时在分布式服务中网络的请求的高度密集,有些服务不一定能在规定的时间内完成访问。应该请求服务需要重试几次。以保证服务请求成功

2.springboot 实现retry机制

方式1:普通使用方式(RetryTemplate)

pom.xm文件引入重试框架

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.1.5.RELEASE</version>
        </dependency>
    </dependencies>

普通方式是使用RetryTemplate方式实现,所以我们需要创建RetryTemplate并且将方法放到RetryTemplate中执行需要重试的方法

@Bean
    RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        // 设置重试回退操作策略,主要设置重试间隔时间
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(1000l);

        Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
        exceptionMap.put(Exception.class, true);
        // 设置重试策略,主要设置重试次数
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(100, exceptionMap);

        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        return retryTemplate;
    }
}
@RestController
@Slf4j
public class RetryController {

    private boolean isRetry = false;

    @Autowired
    RetryTemplate retryTemplate;

    @GetMapping("/setparam")
    public void setParma(@RequestParam Integer integer, @RequestParam Boolean isRetry) {
        this.isRetry = isRetry;
        Boolean execute = retryTemplate.execute(
                //RetryCallback 重试方法
                retryContext -> {
                    retyrMethod(integer);
                    return true;
                },
                retryContext -> {
                    //RecoveryCallback 达到最大值的方法
                    log.info("已达到最大重试次数或抛出了不重试的异常~~~");
                    return false;
                }
        );
    }

    public void retyrMethod(Integer integer) {
        try {
            log.info("isRetry=" + isRetry + ";integer=" + integer);
            if (isRetry) {
                int ii = 1 / 0;
            }
        } catch (Exception ex) {
            log.error("retyrMethod:" + ex);
            throw ex;
        }
    }
}
  • RetryTemplate 承担了重试执行者的角色,它可以设置SimpleRetryPolicy(重试策略,设置重试上限,重试的根源实体),FixedBackOffPolicy(固定的回退策略,设置执行重试回退的时间间隔)。
  • RetryTemplate通过execute提交执行操作,需要准备RetryCallback 和RecoveryCallback 两个类实例,前者对应的就是重试回调逻辑实例,包装正常的功能操作,RecoveryCallback实现的是整个执行操作结束的恢复操作实例
  • 只有在调用的时候抛出了异常,并且异常是在exceptionMap中配置的异常,才会执行重试操作,否则就调用到excute方法的第二个执行方法RecoveryCallback中

在Spring Boot中使用Retrofit spring boot retry_ci

 

 

重试策略: 

NeverRetryPolicy: 只允许调用RetryCallback一次,不允许重试

AlwaysRetryPolicy: 允许无限重试,直到成功,此方式逻辑不当会导致死循环

SimpleRetryPolicy: 固定次数重试策略,默认重试最大次数为3次,RetryTemplate默认使用的策略

TimeoutRetryPolicy: 超时时间重试策略,默认超时时间为1秒,在指定的超时时间内允许重试

ExceptionClassifierRetryPolicy: 设置不同异常的重试策略,类似组合重试策略,区别在于这里只区分不同异常的重试

CircuitBreakerRetryPolicy: 有熔断功能的重试策略,需设置3个参数openTimeout、resetTimeout和delegate

CompositeRetryPolicy: 组合重试策略,有两种组合方式,乐观组合重试策略是指只要有一个策略允许即可以重试,悲观组合重试策略是指只要有一个策略不允许即可以重试,但不管哪种组合方式,组合中的每一个策略都会执行

  重试回退策略:

        重试回退策略,指的是每次重试是立即重试还是等待一段时间后重试。默认情况下是立即重试,如果需要配置等待一段时间后重试则需要指定回退策略BackoffRetryPolicy。 

NoBackOffPolicy: 无退避算法策略,每次重试时立即重试

FixedBackOffPolicy: 固定时间的退避策略,需设置参数sleeper和backOffPeriod,sleeper指定等待策略,默认是Thread.sleep,即线程休眠,backOffPeriod指定休眠时间,默认1秒

UniformRandomBackOffPolicy: 随机时间退避策略,需设置sleeper、minBackOffPeriod和maxBackOffPeriod,该策略在minBackOffPeriod,maxBackOffPeriod之间取一个随机休眠时间,minBackOffPeriod默认500毫秒,maxBackOffPeriod默认1500毫秒

ExponentialBackOffPolicy: 指数退避策略,需设置参数sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠时间,默认100毫秒,maxInterval指定最大休眠时间,默认30秒,multiplier指定乘数,即下一次休眠时间为当前休眠时间*multiplier

ExponentialRandomBackOffPolicy: 随机指数退避策略,引入随机乘数可以实现随机乘数回退

方式2:Spring-Retry注解式(推荐)

spring-retry注解形式依赖于AOP所以需要引入aspect框架

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

1. 首先开启@EnableRetry

表示是否开始重试组件

2. 配置@Retryable

标注此注解的方法在发送异常时会进行重试

属性

类型

默认值

说明

interceptor

String

“”

将interceptor的bean名称应用到retryable(),和其他的属性互斥

include

Class[]

{}

哪些异常可以触发重试 ,默认为空

exclude

Class[]

{}

哪些异常将不会触发重试,默认为空,如果和include属性同时为空,则所有的异常都将会触发重试

value

Class[]

{}

可重试的异常类型

label

String

“”

统计报告的唯—标签。如果没有提供,调用者可以选择忽略它,或者提供默认值

maxAttempts

int

3

尝试的最大次数(包括第一次失败),默认为3次

backoff

@Backoff

@Backoff()

@Backoff @Backoff()指定用于重试此操作的backoff属性。默认为

3.配置重试时间@Backoff 

属性

类型

默认值

说明

delay

long

0

如果不设置则默认使用1000 ms等待重试,和value同义词

maxDelay

long

0

最大重试等待时间

multiplier

long

0

用于计算下一个延迟延迟的乘数(大于0生效)

random

boolean

FALSE

随机重试等待时间

4. @Recover 

作为恢复处理程序的方法调用的注释。重试方法最终会调用标注了@Recover 的方法。

@Recover声明的方法和@Retryable 方法相同类型的返回值,Throwable 第一个参数是可选的(但是,如果没有其他参数匹配,则不带该参数的方法将被调用)。从失败方法的参数列表中依次填充后续参数。

@RestController
@Slf4j
public class Retry_ZJ_Controller {

    private boolean isRetry = false;

    @Autowired
    ApplicationContext applicationContext;

    @GetMapping("/setparam")
    public void setParma(@RequestParam Integer integer, @RequestParam Boolean isRetry) {
        this.isRetry = isRetry;
        Retry_ZJ_Controller controller = applicationContext.getBean(Retry_ZJ_Controller.class);
        controller.retyrMethod(integer);
    }

    @Retryable(maxAttempts = 4, backoff = @Backoff(delay = 2000l))
    public void retyrMethod(Integer integer) {
        try {
            log.info("isRetry=" + isRetry + ";integer=" + integer);
            if (isRetry) {
                int ii = 1 / 0;
            }
        } catch (Exception ex) {
            log.error("retyrMethod:" + ex);
            throw ex;
        }
    }

    @Recover
    public void retryComplete(Exception e) {
        log.error("达到最大重试次数,或抛出了一个没有指定进行重试的异常:");
    }
}

注意:

1.由于是基于AOP实现,所以不支持类里自调用方法
2.如果重试失败需要给@Recover注解的方法做后续处理,那这个重试的方法不能有返回值,只能是void
3.方法内不能使用try catch,只能往外抛异常
4.@Recover注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。

3.监听重试过程 

  • 通过实现RetryListener接口,重写open、close、onError这三个方法,既可以完成对重试过程的追踪,也可以添加额外的处理逻辑;
  • 通过继承RetryListenerSupport,也可以从open、close、onError这三个方法中,选择性的重写