文档章节

微服务常用技能之优雅的重试

稻草鸟人
 稻草鸟人
发布于 2017/04/08 15:04
字数 976
阅读 3205
收藏 190

一般从事软件开发工作的同时通常需要调用远程服务,但是即使是亚马逊、阿里巴巴、腾讯这些巨头提供的服务也可能因为网络或者服务高可用方面的一些问题,或许会遇到超时等异常情况,这时候我们就必需要考虑到异常情况下我们的应用如何能处变不惊处理这些异常,是直接抛出异常还是说可以自动进行一些处理呢? 通常情况下我们首先想到的解决方案一定是重试对吧。

我看过很多代码,他们都怎么写的呢,如下

public String invoke(int times) {
    for(int i = 0; i < times; i ++) {
        try{
            // do some thing
            // return
        }catch(Exception e) {
            return invoke(i);
        }
    }
}

上面的代码意思是首先传入一个次数参数,假设我们传递的是3,那么当遇到异常的时候,重新调用当前方法,次数变为2…

你有没有发现如果调用外部服务很多的时候,这样的for循环写的让人不舒服,因为都是重复的代码,而且显的很啰嗦呢,spring boot给我们带来了一些福音,我们看看spring boot框架下如何进行重试

1、 首先引入JAR包

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

2、使用注解 @EnableRetry @Retryable 下面先给出代码,然后我们再讲注解的含义

@SpringBootApplication
@EnableRetry
public class LeaningNotesApplication {

public static void main(String[] args) {
    SpringApplication.run(LeaningNotesApplication.class, args);
}
}
@Service
public class BookService {

private Random random = new Random();

@Retryable(include = RuntimeException.class, maxAttempts = 3)
public String readingList() {
    int randomInt= random.nextInt(10) ;
    if(randomInt < 8){  //模拟调用失败情况
        System.out.println("调用失败发生异常");
        throw new RuntimeException("call dependency service fail.");
    }else{
        System.out.println("调用成功");
        return "调用成功 ;number:"+randomInt;
    }
}

@Recover
public String reliable() {
    return "Cloud Native Java (O'Reilly)";
}


3、我们再写一个接口,通过浏览器来访问这个接口,看看上面的代码帮我们进行了几次重试,另外如果重试了几次都失败,他又执行了什么方法

@RestController
public class BookController {

@Autowired
private BookService bookService;

@GetMapping("/book")
public String book() {
    return bookService.readingList();
}
}

上面的这个代码就比较简单了,我们可以通过http://localhost:8080/book 来访问这个接口,然后在控制台看结果,我都迫不及待想要去试试了,你呢?

4、我打开了浏览器输入了地址,然后我看到控制台打印了下面这样的信息

调用失败发生异常 
调用成功 
是的,你没看错,先输出了一个异常日志,然后又输出了一个成功日志,说明了它在异常的情况下帮我重试了一次,然后才成功的,当然你也可以多尝试几次看看不一样的结果。

5、@Retryable 几个比较重要的参数

value : 抛出某些异常的时候才进行重试

include: 和value的含义类似

exclude: 排除某些异常不进行重试,这里要注意的是,如果value、include、exclude都为空的时候则任何异常都进行重试

maxAttempts: 最大重试次数

backoff: 重试策略,默认使用注解@Backoff 而@BackOff中value的默认为1000L,multiplier的默认值为0,表示默认情况下固定暂停1秒进行重试,如果我们把multiplier调整为2,那么表面第一次进行重试时间为1秒,第二次为2秒,第三次为4秒。

是不是很牛逼,有木有GET到新技能?

注意:注解了@Recover方法的参数可以没有,如果有一定是和注解@Retryable处理的异常是一样的或者是它的子集,否则recover方法将不能被执行,并不是网上一些人瞎逼逼说一定要和@Retryable处理的异常要保持一致

 

请大家多多关注,让我能有勇气坚持下去

© 著作权归作者所有

共有 人打赏支持
稻草鸟人

稻草鸟人

粉丝 50
博文 12
码字总数 10204
作品 0
上海
后端工程师
私信 提问
加载中

评论(20)

kubei
kubei
谢谢 博主的 分享
稻草鸟人
稻草鸟人

引用来自“终曲”的评论

生产环境重试有时候很危险,根据不同的异常可能要fail fast,那就把错误处理的逻辑全部隐式转嫁到抛什么异常上了,代码更难读

回复@终曲 : 重试只是其中最常见的方式,不错,有些可能要FAILFAST有些需要FAIL OVER当然还有其他降级等策略
Z
Zollty
没看出有多优雅。。。
终曲
终曲
生产环境重试有时候很危险,根据不同的异常可能要fail fast,那就把错误处理的逻辑全部隐式转嫁到抛什么异常上了,代码更难读
稻草鸟人
稻草鸟人

引用来自“楼雨”的评论

一点都不优雅,当项目越久越大,人员N次更替之后,你这简直是恶梦。
当然,也不赞同第一种写法。

回复@楼雨 : 如何写更好?请指教
楼雨
楼雨
一点都不优雅,当项目越久越大,人员N次更替之后,你这简直是恶梦。
当然,也不赞同第一种写法。
HeartArea
HeartArea
原理就是aop,但是low逼的是为什么引入retry时不能把aspectj-weaver依赖也搞进入啊,还得自己手加。
HideHai
HideHai
又涨姿势了
notreami
notreami
无非改成切面实现,自己实现,一样没有问题。
notreami
notreami
无非改成切面实现,自己实现,一样没有问题。
微服务架构的故障隔离及容错处理机制

本文首先介绍微服务架构存在的风险,然后针对如何避免微服务架构的故障,提出了多种有效的微服务架构中的方法和技术,其中例如服务降级、变更管理、健康检查和修复、断路器、限流器等。 目录...

伊竹凌
08/27
0
0
基于.NET CORE微服务框架 -谈谈surging的服务容错降级

一、前言 对于不久开源的surging受到不少.net同学的青睐,也受到.net core学习小组的关注,邀请加入.NET China Foundation 以方便国内.net core开源项目的推广,我果断接受邀请加入了队伍进行...

fanly11
2017/07/23
0
0
微服务神经元--Neural

微服务神经元(Neural) 为微服务架构的提供一个类似于中枢神经的功能,主要功能如下: NPI(SPI):解决JDK原生SPI的缺陷 支持实现的排序 支持实现的分组 支持单例、多例选择 个性化重试 支持...

李景枫
2016/05/14
3.5K
0
微服务学习(1)-微服务概念

一、什么是微服务(Microservices )? 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注...

花蝴蝶511
2017/12/14
0
0
@eechen来来,哥给你展示什么叫“优雅”

@eechen总是在与自己无关的问题乱插一脚,要么推销php,要么攻击别的语言,比如:https://www.oschina.net/question/3188325_2215860 本人对php没什么偏见,而且我们公司的oa就是用php开发的。...

wei2011
2016/12/30
1K
17

没有更多内容

加载失败,请刷新页面

加载更多

如何在Angular中使用better-scroll插件

由于需要在一个固定的的高度做无限滚动,本来css的overflow-y也可以完成的,奈何安卓不是很流畅,还很生硬,就是用了第三方库better-scroll,配合angular的ng-content。angular的ng-content和...

前端攻城老湿
15分钟前
2
0
Js中apply和Math.max()函数的问题及区别

这篇文章主要介绍了js中apply和Math.max()函数的问题,本文给大家带来两种答案,每一种答案给大家介绍的非常详细,在文章底部给大家提到了js中Math.max.apply和Math.max的区别,写的十分的全...

前端攻城小牛
15分钟前
2
0
解决 SpringBoot 不继承父starter-parent打包不包含依赖的问题

由于项目需要继承自己平台的父 parent , 有的模块是纯 api ,不能有任何依赖, 所以父 parent 不能直接引入 springboot, 单独给非 boot 项目排除依赖的话又特别的麻烦, 且不好把控。 记得刚接触...

stys35
17分钟前
1
0
vuex进阶知识点巩固

我们先回忆一下上一篇的代码 computed:{ getName(){ return this.$store.state.name }} 这里假设现在逻辑有变,我们最终期望得到的数据(getName),是基于 this.$store.state.na...

嫣然丫丫丫
32分钟前
1
0
Python出现安全策略问题的解决方法

Python运行期间出现如下错误 import: attempt to perform an operation not allowed by the security policy `PS' @ error/constitute.c/IsCoderAuthorized/408. 解决方法:在脚本的开头添加......

大糊涂
39分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部