springboot的Retry重试方案

SpringBoot+Retry自动重试

Springboot重试机制解决方案

  • Spring-retry
  • guava-retry

一、spring-retry方案

  • Spring-Retry是Spring框架提供的重试机制,它可以对方法进行重试,当方法执行失败时,会自动重试,
    直到达到最大重试次数,或者达到设定的最大等待时间。
  • 参考:https://blog.csdn.net/qq_35913663/article/details/125284726
1、添加依赖
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>2.0.1</version>
</dependency>
4、功能实现
  • 重试策略
    • SimpleRetryPolicy 固定次数重试策略,默认重试最大次数为3次,RetryTemplate默认使用的策略
    • CircuitBreakerRetryPolicy 有熔断功能的重试策略,需设置3个参数openTimeout、resetTimeout和delegate:
      • 1.openTimeout 接口执行时间超时多久后开启熔断,单位ms
      • 2.resetTimeout 熔断持续时间,单位ms
      • 3.熔断代表着其他请求过来时将不会执行
    • ExceptionClassifierRetryPolicy 设置不同异常的重试策略,类似组合重试策略,区别在于这里只区分不同异常的重试
    • InterceptorRetryPolicy 尚不理解
    • CompositeRetryPolicy 组合重试策略,有两种组合方式,乐观组合重试策略是指只要有一个策略允许即可以重试,悲观组合重试策略是指只要有一个策略不允许即可以重试,但不管哪种组合方式,组合中的每一个策略都会执行
    • NeverRetryPolicy 只允许调用RetryCallback一次,不允许重试
    • TimeoutRetryPolicy 超时时间重试策略,默认超时时间为1秒,在指定的超时时间内允许重试
  • 退避策略
    • ExponentialBackOffPolicy 指数退避策略,需设置参数sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠时间,默认100毫秒,maxInterval指定最大休眠时间,默认30秒,multiplier指定乘数,即下一次休眠时间为当前休眠时间*multiplier
    • ExponentialRandomBackOffPolicy 在 ExponentialBackOffPolicy 的策略基础上,在获取指针策略的等待时间后,再随机乘以一个随机数作为实际sleep时间
    • UniformRandomBackOffPolicy 随机时间退避策略,需设置sleeper、minBackOffPeriod和maxBackOffPeriod,该策略在[minBackOffPeriod,maxBackOffPeriod之间取一个随机休眠时间,minBackOffPeriod默认500毫秒,maxBackOffPeriod默认1500毫秒
    • NoBackOffPolicy 无退避,重试策略判定需要重试后立马重试
    • FixedBackOffPolicy 固定时间的退避策略,需设置参数sleeper和backOffPeriod,sleeper指定等待策略,默认是Thread.sleep,即线程休眠,backOffPeriod指定休眠时间,默认1秒
4.1 添加重试配置
@EnableRetry
public class RetryConfig{

}
4.2 注解方式业务方法实现重试
  • @Retryable注解
    • value 出发重试的异常
    • maxAttempts 最大重试次数
    • backoff 回避策略
  • @Backoff
    • delay 延迟时间,单位毫秒
    • multiplier 指定乘数
  • @Recover注解
@Slf4j
@Service
public class PayService {

    private final int totalNum = 100000;
    
    // 重试方法
    @Retryable(value = Exception.class, maxAttempts = 3,
            backoff = @Backoff(delay = 2000L, multiplier = 1.5))
    public int minGoodsnum(int num) {
        log.info("减库存开始" + LocalTime.now());
        try {
            int i = 1 / 0; //模拟产生异常
        } catch (Exception e) {
            log.error("illegal");
        }
        if (num <= 0) {
            throw new IllegalArgumentException("数量不对");
        }
        log.info("减库存执行结束" + LocalTime.now());
        return totalNum - num;
    }
    // 回避策略
    @Recover
    public int recover(Exception e) {
        //记日志到数据库
        log.warn("减库存失败!!!" + LocalTime.now());
        return totalNum;
    }
}
4.3 手动方式实现重试
4.3.1 添加重试策略配置类
@Configuration
public class TestBeanProvider {

    @Bean("simpleRetryTemplate")
    public RetryTemplate simpleRetryTemplate(){
        RetryTemplate retryTemplate = new RetryTemplate();
        SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        //默认3次,设置为5次
        simpleRetryPolicy.setMaxAttempts(5);
        retryTemplate.setRetryPolicy(simpleRetryPolicy);
        //固定等待时间 10s
        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(10000);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
        return retryTemplate;
    }
}
4.3.2 使用重试策略模板
public class RetryDemo{
  @Autowired
  @Qualifier("simpleRetryTemplate")
  private  RetryTemplate  retryTemplate;

  public void springRetryTest(){
    retryTemplate.execute(context ->{
      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
      log.info("这是第"+(context.getRetryCount()+1)+"次重试:"+sdf.format(new Date()));
      throw new RuntimeException();
    });
  }
}

二、guava-retrying

  • RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。
  • RetryerBuilder的重试源支持Exception异常对象 和自定义断言对象,通过retryIfException 和retryIfResult设置,同时支持多个且能兼容。
  • retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
  • retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。
  • retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException都属于runtime异常,也包括自定义的error
  • retryIfResult可以指定你的Callable方法在返回值的时候进行重试
  • StopStrategy:停止重试策略,提供三种:
    • StopAfterDelayStrategy 设定一个最长允许的执行时间;比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常RetryException。
    • NeverStopStrategy 不停止,用于需要一直轮训知道返回期望结果的情况。
  • StopAfterAttemptStrategy 设定最大重试次数,如果超出最大重试次数则停止重试,并返回重试异常。
  • WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长:
    • FixedWaitStrategy 固定等待时长策略。
    • RandomWaitStrategy 随机等待时长策略(可以提供一个最小和最大时长,等待时长为其区间随机值)。
    • IncrementingWaitStrategy 递增等待时长策略(提供一个初始值和步长,等待时间随重试次数增加而增加)。
    • ExponentialWaitStrategy 指数等待时长策略。
    • FibonacciWaitStrategy Fibonacci 等待时长策略。
    • ExceptionWaitStrategy 异常时长等待策略。
    • CompositeWaitStrategy 复合时长等待策略。
1、添加以来
<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>
2、添加配置项
2.1 添加配置类
@Configuration
public class RetryConfig {
    @Bean
    public Retryer retryer(){
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder().
            //如果异常会重试
            retryIfException().
            //如果结果为false会重试
            retryIfResult(Predicates.equalTo(false)).
            //重调策略
            withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS)).
            //尝试次数
            withStopStrategy(StopStrategies.stopAfterAttempt(3)).
            //注册监听
            withRetryListener(new MyRetryListener()).build();
        return retryer;
    }
}
2.2 配置监听器
//监听retry
public class MyRetryListener implements RetryListener {
    public <V> void onRetry(Attempt<V> attempt) {
        System.out.print("[retry]time=" + attempt.getAttemptNumber());
        // 距离第一次重试的延迟
        System.out.print(",delay=" + attempt.getDelaySinceFirstAttempt());
 
        // 重试结果: 是异常终止, 还是正常返回
        System.out.print(",hasException=" + attempt.hasException());
        System.out.print(",hasResult=" + attempt.hasResult());
 
        // 是什么原因导致异常
        if (attempt.hasException()) {
            System.out.print(",causeBy=" + attempt.getExceptionCause().toString());
        } else {
            // 正常返回时的结果
            System.out.print(",result=" + attempt.getResult());
        }
        System.out.println();
    }
 
}
4、业务调用重试机制实现
//调用重试业务
public class retryService{
	public static void main(String[] args) {
		try {
			retryer.call(()->false);
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
    @Resource
    private Retryer retryer;
    
    //调用重试
    public void doRetry(Runnable runnable){
         retryer.call(()->runnable);
    }   

}

三、alibaba分布式重试-easy-retry

  • 参考:
1、添加依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easy-retry-mybatis-starter</artifactId>
    <version>1.0.0.RC</version>
</dependency>
2、添加配置
spring:
  easyretry:
    mybatis:
      enabled: true
3、添加retry表
CREATE TABLE `easy_retry_task` (
    `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
    `gmt_modified` datetime NOT NULL COMMENT '修改时间',
    `sharding` varchar(64) NULL COMMENT '1',
    `biz_id` varchar(64) NULL COMMENT '2',
    `executor_name` varchar(512) NULL COMMENT '3',
    `executor_method_name` varchar(512) NULL COMMENT '4',
    `retry_status` tinyint NULL COMMENT '5',
    `args_str` varchar(3000) NULL COMMENT '6',
    `ext_attrs` varchar(3000) NULL COMMENT '7',
    PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET=utf8 AUTO_INCREMENT=0 COMMENT='easy_retry_task';
4、功能实现
public class MybatisUserService {
    @EasyRetryable
    public User getUserById(Long userId){
        return new User();
    }
}
其他方案

https://blog.csdn.net/qq_34905631/article/details/131187901

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值