您好,登錄后才能下訂單哦!
這篇文章主要介紹“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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。