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