这篇文章主要介绍“Retry重试机制是什么意思”,在日常操作中,相信很多人在Retry重试机制是什么意思问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Retry重试机制是什么意思”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
在项目开发中,有的时候,总是避免不了调用第三方服务接口,有的时候可能因为网络等情况的因素,我们需要重试几次才能调用成功,所以就需要一重试机制来保证接口的正常访问。
这是谷歌guava提供的工具包,我们可以在项目中引入相应的包,很轻松实现重试访问。guava-retrying中大量运用的策略模式,可以自定义各种执行重试策略。下面是简单实用步骤。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
我这里实现一个对接口的简单访问,以此来模拟访问第三方接口。
@GetMapping("/retrytest")
public Map<String, Object> retrytest(){
Map<String, Object> resultMap = Maps.newHashMap();
resultMap.put("id", 1001L);
resultMap.put("msg", "测试");
Map<String, Object> tokenMap = Maps.newHashMap();
tokenMap.put("token", UUID.randomUUID().toString());
resultMap.put("data", tokenMap);
return resultMap;
}
Retryer中定义重试的各种策略,在执行call方法的时候,会将这些重试策略一一使用。
RetryListener是重试监听器,可以监听每次重试的过程。
BlockStrategy是自定义阻塞策略。
@Bean
public Retryer<String> retry(){
RetryListener retryListener = new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
try {
if(attempt.hasException()){
log.error("---"+ Arrays.toString(attempt.getExceptionCause().getStackTrace()));
}else {
log.info("---"+ attempt.get().toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
BlockStrategy blockStrategy = new BlockStrategy() {
@Override
public void block(long sleepTime) throws InterruptedException {
LocalDateTime startTime = LocalDateTime.now();
long start = System.currentTimeMillis();
long end = start;
log.info("[SpinBlockStrategy]...begin wait.");
while (end - start <= sleepTime) {
end = System.currentTimeMillis();
}
//使用Java8新增的Duration计算时间间隔
Duration duration = Duration.between(startTime, LocalDateTime.now());
log.info("[SpinBlockStrategy]...end wait.duration={}", duration.toMillis());
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
//retryIf 重试条件
.retryIfException()
.retryIfRuntimeException()
.retryIfExceptionOfType(Exception.class)
.retryIfException(Predicates.equalTo(new Exception()))
//等待策略:每次请求间隔1s
// .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
//停止策略 : 尝试请求3次
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
//时间限制 : 某次请求不得超过2s , 类似: TimeLimiter timeLimiter = new SimpleTimeLimiter();
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(2, TimeUnit.SECONDS))
.withRetryListener(retryListener)
.withBlockStrategy(blockStrategy)
.build();
return retryer;
}
编写retryer调用call方法的具体实现逻辑。
@Slf4j
public class RetryCallable implements Callable<String> {
private RestTemplate restTemplate;
public RetryCallable(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
int times = 1;
@Override
public String call() {
log.info("call times={}", times++);
log.info("请求时间: {}", LocalDateTime.now());
//对远程地址的访问
return Objects.requireNonNull(
restTemplate.getForObject("http://localhost:8080/retrytest", Object.class)).toString();
}
}
@GetMapping("/hello")
public Object hello(@RequestParam(required = false) String token){
log.info("hello "+ token);
Map result = null;
String msg = "";
try {
//定义请求实现 利用重试器调用请求
String callResult = retryer.call(new RetryCallable(restTemplate));
result = new Gson().fromJson(callResult, Map.class);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
log.warn("请求失败:{}",e.getMessage());
}
HashMap<String, Object> resultData = Maps.newHashMap();
resultData.put("data",result);
resultData.put("token",token);
resultData.put("msg",msg);
return resultData;
}
调用接口测试
2019-10-12 13:46:23.863 INFO 68012 --- [nio-8080-exec-1] com.wj.retry.controller.HelloController : hello f5b78e95-87f7-435e-b9be-04bcb88ad056
2019-10-12 13:46:23.865 INFO 68012 --- [pool-1-thread-1] com.wj.retry.controller.RetryCallable : call times=1
2019-10-12 13:46:23.875 INFO 68012 --- [pool-1-thread-1] com.wj.retry.controller.RetryCallable : 请求时间: 2019-10-12T13:46:23.874
2019-10-12 13:46:24.068 INFO 68012 --- [nio-8080-exec-1] com.wj.retry.RetryApplication : ---{msg=测试, data={token=eacb4a99-9ef9-4581-b8e5-28fdabac1c52}, id=1001}
若失败会调用多次(按照重试器中定义的策略)并,抛出异常
上面的实现会写相对较多的代码,若使用spring-retry则相对简单多了,可以基于注解实现
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
@Retryable的参数说明:
value:抛出指定异常才会重试
include:和value一样,默认为空,当exclude也为空时,默认所以异常
exclude:指定不处理的异常
maxAttempts:最大重试次数,默认3次
backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000L,我们设置为2000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1.5))
public Object retry(@RequestParam(required = false) String token) {
String msg = "";
log.info("springretry");
log.info("请求时间: {}", LocalDateTime.now());
String resultStr = Objects.requireNonNull(
restTemplate.getForObject("http://localhost:8080/retrytest", Object.class)).toString();
Map result = new Gson().fromJson(resultStr, Map.class);
HashMap<String, Object> resultData = Maps.newHashMap();
resultData.put("data",result);
resultData.put("token",token);
resultData.put("msg",msg);
return resultData;
}
最后在启动类上加上@EnableRetry注解开启重试机制。ok,就这样两个步骤就完成了
除了上面调用第三方服务接口可能会用到重试机制,在微服务项目中,服务之间的通信,重试机制可以说是随处可见。
在springcloud中Ribbon,feign,Hystrix等组件都可以自己配置重试机制,来达到提高能正常通信的成功率。
此外,在各种消息中间件中也都有重试机制的体现,例如kafka,消息发送失败可以重新发送,消息消费失败了,也可以配置重试机制,可以最大程度达到消息的不丢失。
可以考虑这么一个事情,若目标逻辑执行时间过长,超出了重试的等待时间,客户端就要发起重试,那么服务端就会出现重复调用执行的问题,所以,有重试机制就要考虑幂等性的问题。
到此,关于“Retry重试机制是什么意思”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/3553496/blog/3116198