这篇文章主要介绍“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重试机制是什么意思”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。