- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解重试框架Spring retry实践由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断。对于重试是有场景限制的,不是什么场景都适合重试,比如参数校验不合法、写操作等(要考虑写是否幂等)都不适合重试。远程调用超时、网络突然中断可以重试。在微服务治理框架中,通常都有自己的重试与超时配置,比如dubbo可以设置retries=1,timeout=500调用失败只重试1次,超过500ms调用仍未返回则调用失败。在spring retry中可以指定需要重试的异常类型,并设置每次重试的间隔以及如果重试失败是继续重试还是熔断(停止重试).
设计与实现 。
retryoperations定义重试的api,retrytemplate是api的模板模式实现,实现了重试和熔断。提供的api如下:
1
2
3
4
|
public
interface
retryoperations {
<t, e
extends
throwable>t execute(retrycallback<t, e>retrycallback)
throws
e;
}
// 其他api已省略
|
retrycallback定义了需要执行重试的操作,定义好操作后,就是如何重试的问题了。retrytemplate通过制定不同的重试策略来执行如何重试的逻辑。默认的重试策略是simpleretryplicy,也就是会重试3次。重试第1次如果成功后面就不会继续重试了。那么如果3尺都重试失败了呢?流程结束或者返回兜底结果。要返回兜底结果需要配置recoveycallback,从名字可以看出这是一个兜底回调接口,也就是重试失败后执行的逻辑。除了simpleretrypolicy还有其他重试策略,先来看下retrypolicy接口:
1
2
3
4
5
6
|
public
interface
retrypolicy
extends
serializable {
boolean
canretry(retrycontext context);
retrycontext open(retrycontext parent);
void
close(retrycontext context);
void
registerthrowable(retrycontext context, throwable throwable);
}
|
canretry在每次重试的时候调用,是否可以继续重试的判断条件 open重试开始前调用,会创建一个重试上下文到retrycontext,保存重试的堆栈等信息 registerthrowable每次重试异常时调用(有异常会继续重试) 。
以simpleretrypolicy为例,当重试次数达到3(默认3次)停止重试,重试次数保存在重试上下文中.
提供如下重试策略实现:
重试回退策略,指的是每次重试是立即重试还是等待一段时间后重试。默认情况下是立即重试,如果需要配置等待一段时间后重试则需要指定回退策略backoffretrypolicy。backoffretrypolicy有如下实现:
有状态重试 or 无状态重试 。
所谓无状态重试是指重试在一个线程上下文中完成的重试,反之不在一个线程上下文完成重试的就是有状态重试。之前的simpleretrypolicy就属于无状态重试,因为重试是在一个循环中完成的。那么什么会后会出现或者说需要有状态重试呢?通常有两种情况:事务回滚和熔断.
数据库操作异常dataaccessexception,不能执行重试,而如果抛出其他异常可以重试.
熔断的意思不在当前循环中处理重试,而是全局重试模式(不是线程上下文)。熔断会跳出循环,那么必然会丢失线程上下文的堆栈信息。那么肯定需要一种“全局模式”保存这种信息,目前的实现放在一个cache(map实现的)中,下次从缓存中获取就能继续重试了.
quick start 。
在需要执行重试的类上使用@enableretry,如果设置了proxytargetclass=true这使用cglib动态代理:
1
2
3
4
5
6
|
@configuration
@enableretry
(proxytargetclass =
true
)
@component
public
class
retryexamples {
}
|
基于最大重试次数策略的重试,如果重试了3次仍然抛出异常则停止重试,执行兜底回调,所以最后的输出结果是integer.max_value:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
private
void
retryexample3()
throws
exception {
retrytemplate retrytemplate =
new
retrytemplate();
simpleretrypolicy simpleretrypolicy =
new
simpleretrypolicy();
simpleretrypolicy.setmaxattempts(
3
);
retrytemplate.setretrypolicy(simpleretrypolicy);
integer result = retrytemplate.execute(
new
retrycallback<integer, exception>() {
int
i =
0
;
// 重试操作
@override
public
integer dowithretry(retrycontext retrycontext)
throws
exception {
log.info(
"retry count: {}"
, retrycontext.getretrycount());
return
len(i++);
}
},
new
recoverycallback<integer>() {
//兜底回调
@override
public
integer recover(retrycontext retrycontext)
throws
exception {
log.info(
"after retry: {}, recovery method called!"
, retrycontext.getretrycount());
return
integer.max_value;
}
});
log.info(
"final result: {}"
, result);
}
private
int
len(
int
i)
throws
exception {
if
(i <
10
)
throw
new
exception(i +
" le 10"
);
return
i;
}
|
下面介绍如何使用熔断重试策略模式(circuitbreakerretrypolicy),需要设置如下三个参数:
断路器开闭实现判断:
测试代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
retrytemplate template =
new
retrytemplate();
circuitbreakerretrypolicy retrypolicy =
new
circuitbreakerretrypolicy(
new
simpleretrypolicy(
3
));
retrypolicy.setopentimeout(
5000
);
retrypolicy.setresettimeout(
20000
);
template.setretrypolicy(retrypolicy);
for
(
int
i =
0
; i <
10
; i++) {
//thread.sleep(100);
try
{
object key =
"circuit"
;
boolean
isforcerefresh =
false
;
retrystate state =
new
defaultretrystate(key, isforcerefresh);
string result = template.execute(
new
retrycallback<string, runtimeexception>() {
@override
public
string dowithretry(retrycontext context)
throws
runtimeexception {
log.info(
"retry count: {}"
, context.getretrycount());
throw
new
runtimeexception(
"timeout"
);
}
},
new
recoverycallback<string>() {
@override
public
string recover(retrycontext context)
throws
exception {
return
"default"
;
}
}, state);
log.info(
"result: {}"
, result);
}
catch
(exception e) {
system.out.println(e);
}
}
|
这里由于设置了isforcerefresh = false,则key = "circuit"的值(也就是retrycontext)会从缓存中获取,所以当重试失败且满足this.time < this.openwindow发生熔断的时候,后面仍然可以继续已全局模式实现重试(拿到的retrycontext是同一个).
注解开发 。
如果每次有重试需求的时候都写一个retrytemplate太臃肿了,使用注解可以大大简化开发,减少重复代码。下面是一个使用注解实现的最大重试策略的重试:
1
2
3
4
5
6
7
8
9
10
|
@retryable
(value = sqldataexception.
class
, backoff =
@backoff
(value = 0l))
public
string service3()
throws
sqldataexception {
log.info(
"service3 open"
);
throw
new
sqldataexception();
}
@recover
public
string recover(sqldataexception ne) {
return
"sqldataexception recover"
;
}
|
注解包括:
@enableretry 。
@retryable 。
@recover 。
@backoff 。
@circuitbreaker 。
@enableretry:能否重试,proxytargetclass属性为true时(默认false),使用cglib代理 。
@retryable:注解需要被重试的方法 。
@backoff:重试回退策略(立即重试还是等待一会再重试) 。
@recover: 用于方法。用于@retryable失败时的“兜底”处理方法。 @recover注释的方法必须要与@retryable注解的方法“签名”保持一致,第一入参为要重试的异常,其他参数与@retryable保持一致,返回值也要一样,否则无法执行! 。
@circuitbreaker:用于方法,实现熔断模式.
更多的例子欢迎到我的github(https://github.com/happyxiaofan/springboot-learning-example) star。谢谢 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://blog.csdn.net/u011116672/article/details/77823867 。
最后此篇关于详解重试框架Spring retry实践的文章就讲到这里了,如果你想了解更多关于详解重试框架Spring retry实践的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
是否可以重试网络客户端请求?在奇怪的情况下,我的应用程序在尝试连接到 xml Web 服务时会抛出错误,但如果我重试,它就可以正常工作。我希望它在抛出错误之前重试 2 次,除非有人有更好的解决方案:)
我在一本书中找到了这段代码片段: int ival; // read cin and test only for EOF; loop is executed even if there are oth
是否可以使用 for lop 来设置对象的条件。如果该条件未通过测试(if 语句),则更改条件直到它通过测试?这是我的伪代码尝试,但我怀疑它是否有效: for (int i = 0; i < myAr
我有以下问题。我的主要 Activity 由一个 ListView 组成,其中填充了从 Web 服务获得的数据。首次加载主要 Activity 时,以防无法从网络检索数据,我想显示一个带有 2 个按钮
我有微服务应用程序。为了协作,每个服务都使用异步消息传递。我知道,spring data jpa 默认使用乐观锁。但是如果这种锁定不是由用户调用,而是由另一个服务调用的方法(在我的示例中有验证服务,可
我希望能够在 F# 中编写一个计算表达式,如果它抛出异常,它将能够重试操作。现在我的代码看起来像: let x = retry (fun() -> GetResourceX()) let y = re
是否可以在 NServiceBus 版本 3.2.2 中禁用重试? 使用以下配置,可以禁用重试: 但当线程数设置为 20 时则不会。在这种情况下,消息会重试两次: 这看起来很像
我在 failed_jobs 上有多个失败的作业。我尝试重新排队 MaxAttemptsExceededException 但总是失败。如何重试那里的工作类型? 注意:每次我通过 php artisa
下面的 sproc 尝试向表中插入一行并生成一个随机 ID,用于在相应表上进行 PK。与随机生成的 ID 的冲突在 catch 块中处理,在那里再次重试/调用该过程。现在,这需要很长时间并导致死锁,因
我试图实现代码以使用“mocha-retry”重试失败的测试以下是示例。 describe(retries,' retries-',function () { var self = this;
我正在尝试通过 Azure 数据工厂将数据从 Azure 数据湖存储插入到 Azure 表。 Azure Data Lake 文件中的数据与最终 Azure 表接收器的架构相同。 ADF 管道包含从
是http.RoundTripper在 Go 中基于 HTTP 状态代码(例如 429)实现 http GET 请求重试机制的正确位置? 它在某种程度上“感觉正确”( Go Playground )并
使用 spring reactive WebClient,我使用了一个 API,如果响应状态为 500,我需要使用指数退避重试。但是在 Mono 类中,我没有看到任何以 Predicate 作为输入参
我一直在尝试编写 react native 的快速入门指南,但一直收到此错误 There appears to be trouble with your network connection. Ret
我正在尝试使用从我们心爱的堆栈溢出中获取的 Retry Monad: type RetryBuilder(max, sleep : TimeSpan) = member x.Return(
使用 spring reactive WebClient,我使用了一个 API,如果响应状态为 500,我需要使用指数退避重试。但是在 Mono 类中,我没有看到任何以 Predicate 作为输入参
我有一个由 C#.NET 4.0 开发的两层 Windows 窗体应用程序。在这个应用程序中,我读取文件内容并在数据访问层中创建实体列表,并将其返回到 GUI 层以在 GridView 中显示。在我当
如果有人问过这个问题,我深表歉意,但我已经做了很多搜索,但还没有找到与我的问题类似的问题。 在我的应用程序中,我有一个密码更改页面,如果某人是新用户或重置了他/她的密码,该页面就会触发。 问题是,一旦
想知道为什么我的 promise 正在解决但试图重试。 var getResultsStream = url => Rx.Observable.onErrorResumeNext( Rx.O
假设我有以下 Promise 链: var result = Promise.resolve(filename) .then(unpackDataFromFile) .then(tra
我是一名优秀的程序员,十分优秀!