Java重试机制
重试作用:
对于重试是有场景限制的,不是什么场景都适合重试,比如参数校验不合法、写操作等(要考虑写是否幂等)都不适合重试。
远程调用超时、网络突然中断可以重试。在微服务治理框架中,通常都有自己的重试与超时配置,比如dubbo可以设置retries=1,timeout=500调用失败只重试1次,超过500ms调用仍未返回则调用失败。
比如外部 RPC 调用,或者数据入库等操作,如果一次操作失败,可以进行多次重试,提高调用成功的可能性。
优雅的重试机制要具备几点:
- 无侵入:这个好理解,不改动当前的业务逻辑,对于需要重试的地方,可以很简单的实现
- 可配置:包括重试次数,重试的间隔时间,是否使用异步方式等
- 通用性:最好是无改动(或者很小改动)的支持绝大部分的场景,拿过来直接可用
优雅重试共性和原理:
- 正常和重试优雅解耦,重试断言条件实例或逻辑异常实例是两者沟通的媒介。
- 约定重试间隔,差异性重试策略,设置重试超时时间,进一步保证重试有效性以及重试流程稳定性。
- 都使用了命令设计模式,通过委托重试对象完成相应的逻辑操作,同时内部封装实现重试逻辑。
- Spring-tryer和guava-tryer工具都是线程安全的重试,能够支持并发业务场景的重试逻辑正确性。
优雅重试适用场景:
- 功能逻辑中存在不稳定依赖场景,需要使用重试获取预期结果或者尝试重新执行逻辑不立即结束。比如远程接口访问,数据加载访问,数据上传校验等等。
- 对于异常场景存在需要重试场景,同时希望把正常逻辑和重试逻辑解耦。
- 对于需要基于数据媒介交互,希望通过重试轮询检测执行逻辑场景也可以考虑重试方案。
优雅重试解决思路:
切面方式
这个思路比较清晰,在需要添加重试的方法上添加一个用于重试的自定义注解,然后在切面中实现重试的逻辑,主要的配置参数则根据注解中的选项来初始化
优点:
- 真正的无侵入
缺点:
- 某些方法无法被切面拦截的场景无法覆盖(如spring-aop无法切私有方法,final方法)
- 直接使用aspecj则有些小复杂;如果用spring-aop,则只能切被spring容器管理的bean
消息总线方式
这个也比较容易理解,在需要重试的方法中,发送一个消息,并将业务逻辑作为回调方法传入;由一个订阅了重试消息的consumer来执行重试的业务逻辑
优点:
- 重试机制不受任何限制,即在任何地方你都可以使用
- 利用
EventBus
框架,可以非常容易把框架搭起来
缺点:
- 业务侵入,需要在重试的业务处,主动发起一条重试消息
- 调试理解复杂(消息总线方式的最大优点和缺点,就是过于灵活了,你可能都不知道什么地方处理这个消息,特别是新的童鞋来维护这段代码时)
- 如果要获取返回结果,不太好处理, 上下文参数不好处理
模板方式
优点:
- 简单(依赖简单:引入一个类就可以了; 使用简单:实现抽象类,讲业务逻辑填充即可;)
- 灵活(这个是真正的灵活了,你想怎么干都可以,完全由你控制)
缺点:
- 强侵入
- 代码臃肿
把这个单独捞出来,主要是某些时候我就一两个地方要用到重试,简单的实现下就好了,也没有必用用到上面这么重的方式;而且我希望可以针对代码快进行重试
这个的设计还是非常简单的,基本上代码都可以直接贴出来,一目了然:
public abstract class RetryTemplate { private static final int DEFAULT_RETRY_TIME = 1;
private int retryTime = DEFAULT_RETRY_TIME;
private int sleepTime = 0;// 重试的睡眠时间 public int getSleepTime() {
return sleepTime;
} public RetryTemplate setSleepTime(int sleepTime) {
if(sleepTime < 0) {
throw new IllegalArgumentException("sleepTime should equal or bigger than 0");
}
this.sleepTime = sleepTime;
return this;
} public int getRetryTime() {
return retryTime;
} public RetryTemplate setRetryTime(int retryTime) {
if (retryTime <= 0) {
throw new IllegalArgumentException("retryTime should bigger than 0");
}
this.retryTime = retryTime;
return this;
} /**
* 重试的业务执行代码
* 失败时请抛出一个异常
*
* todo 确定返回的封装类,根据返回结果的状态来判定是否需要重试
*
* @return
*/
protected abstract Object doBiz() throws Exception; //预留一个doBiz方法由业务方来实现,在其中书写需要重试的业务代码,然后执行即可 public Object execute() throws InterruptedException {
for (int i = 0; i < retryTime; i++) {
try {
return doBiz();
} catch (Exception e) {
log.error("业务执行出现异常,e: {}", e);
Thread.sleep(sleepTime);
}
}
return null;
} public Object submit(ExecutorService executorService) {
if (executorService == null) {
throw new IllegalArgumentException("please choose executorService!");
}
return executorService.submit((Callable) () -> execute());
}
}
使用示例:
public void retryDemo() throws InterruptedException {
Object ans = new RetryTemplate() {
@Override
protected Object doBiz() throws Exception {
int temp = (int) (Math.random() * 10);
System.out.println(temp);
if (temp > 3) {
throw new Exception("generate value bigger then 3! need retry");
}
return temp;
}
}.setRetryTime(10).setSleepTime(10).execute();
System.out.println(ans);
}
Java重试机制的更多相关文章
- Java之Retry重试机制详解
应用中需要实现一个功能: 需要将数据上传到远程存储服务,同时在返回处理成功情况下做其他操作.这个功能不复杂,分为两个步骤:第一步调用远程的Rest服务上传数据后对返回的结果进行处理:第二步拿到第一步结 ...
- 转 : 深入解析Java锁机制
深入解析Java锁机制 https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw%3D%3D&mid=2247485524&idx=1&s ...
- Volley超时重试机制
基础用法 Volley为开发者提供了可配置的超时重试机制,我们在使用时只需要为我们的Request设置自定义的RetryPolicy即可. 参考设置代码如下: int DEFAULT_TIMEOUT_ ...
- Rocket重试机制,消息模式,刷盘方式
一.Consumer 批量消费(推模式) 可以通过 consumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 这里需要分为2种情况 Consumer端先 ...
- Spring Cloud重试机制与各组件的重试总结
SpringCloud重试机制配置 首先声明一点,这里的重试并不是报错以后的重试,而是负载均衡客户端发现远程请求实例不可到达后,去重试其他实例. ? 1 2 3 4 5 6 7 8 @Bean @Lo ...
- spring-retry 重试机制
业务场景 应用中需要实现一个功能: 需要将数据上传到远程存储服务,同时在返回处理成功情况下做其他操作.这个功能不复杂,分为两个步骤:第一步调用远程的Rest服务逻辑包装给处理方法返回处理结果:第二步拿 ...
- Spring Cloud Gateway重试机制
前言 重试,我相信大家并不陌生.在我们调用Http接口的时候,总会因为某种原因调用失败,这个时候我们可以通过重试的方式,来重新请求接口. 生活中这样的事例很多,比如打电话,对方正在通话中啊,信号不好啊 ...
- spring-retry 重试机制的使用
场景:由于网络抖动原因,或者其他原因,需要对代码重新执行,这个就需要重试了. import org.springframework.context.annotation.Configuration; ...
- RocketMQ重试机制和消息幂等
一.重试机制 由于MQ经常处于复杂的分布式系统中,考虑网络波动,服务宕机,程序异常因素,很有可能出现消息发送或者消费失败的问题.因此,消息的重试就是所有MQ中间件必须考虑到的一个关键点.如果没有消息重 ...
随机推荐
- 微信小程序开发——使用第三方插件生成二维码
需求场景: 小程序中指定页面需要根据列表数据生成多张二维码. 实现方案: 鉴于需要生成多张二维码,可以将生成二维码的功能封装到组件中,直接在页面列表循环中调用就好了.也可以给组件添加slot,在页面调 ...
- Hadoop,Spark,Flink 相关KB
Hive: https://stackoverflow.com/questions/17038414/difference-between-hive-internal-tables-and-exter ...
- 最新 北森java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.北森等10家互联网公司的校招Offer,因为某些自身原因最终选择了北森.6.7月主要是做系统复习.项目复盘.LeetCode ...
- docker安装+docker-compose
1.docker安装 yum install -y yum-utils device-mapper-persistent-data yum-config-manager --add-repo http ...
- Django框架4——form表单
HTML表单一直是交互性网站的支柱,使用form组件对用户通过表单提交的数据进行访问.有效性检查以及其他处理 从Request对象中获取数据 URL相关信息 属性/方法 说明 举例 request.p ...
- 爬虫请求库之requests库
一.介绍 介绍:使用requests可以模拟浏览器的请求,比之前的urllib库使用更加方便 注意:requests库发送请求将网页内容下载下来之后,并不会执行js代码,这需要我们自己分析目标站点然后 ...
- linux shell程序常用功能
一.循环读取文件 循环读取文件方式有多种,推荐下列方法 while read line;do local include=$(echo ${line} | grep "filter" ...
- golang 执行命令行(二)--修改进程启动用户
继续上文所述,有时候我们需要设置进程的启动用户,操作与设置进程组的方式类似,不多说直接上代码: // 修改进程的执行用户 func withUserAttr(cmd *exec.Cmd, name s ...
- L2R 三:常用工具包介绍之 XGBoost与LightGBM
L2R最常用的包就是XGBoost 和LightGBM,xgboost因为其性能及快速处理能力,在机器学习比赛中成为常用的开源工具包, 2016年微软开源了旗下的lightgbm(插句题外话:微软的人 ...
- Oracle数据库常用语法
基本 --新建表:create table table1( id varchar(300) primary key, name varchar(200) not null); --插入数据 inser ...