最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

從零搭建腳手架之集成Spring?Retry實現(xiàn)失敗重試和熔斷器模式(實戰(zhàn)教程)

 更新時間:2022年07月20日 10:51:22   作者:lakernote  
在我們的大多數(shù)項目中,會有一些場景需要重試操作,而不是立即失敗,讓系統(tǒng)更加健壯且不易發(fā)生故障,這篇文章主要介紹了從零搭建開發(fā)腳手架之集成Spring?Retry實現(xiàn)失敗重試和熔斷器模式,需要的朋友可以參考下

背景

在我們的大多數(shù)項目中,會有一些場景需要重試操作,而不是立即失敗,讓系統(tǒng)更加健壯且不易發(fā)生故障。

場景如下

  • 瞬時網(wǎng)絡(luò)抖動故障
  • 服務(wù)器重啟
  • 偶發(fā)死鎖
  • 某些上游的異常或者響應(yīng)碼,需要進行重試
  • 遠程調(diào)用
  • 從數(shù)據(jù)庫中獲取或存儲數(shù)據(jù)

以上皆為瞬時故障。

也會有一些場景,例如不是瞬時故障,例如接口響應(yīng)一直很慢,需要的是斷路器,如果還是繼續(xù)重試,會對服務(wù)有很大的影響,例如請求一次需要30s,如果還去不斷的重試,會拖垮我們的系統(tǒng),我們需要一定次數(shù)的失敗后停止向服務(wù)發(fā)送進一步的請求,并在一段時間后恢復發(fā)送請求。

Spring Retry提供了以下能力:

  • 失敗重試
  • 斷路器模式

不支持艙壁bulkhead線程隔離
不支持超時timeout機制

項目地址

https://github.com/spring-projects/spring-retry

https://docs.spring.io/spring-batch/docs/current/reference/html/retry.html

實戰(zhàn)

添加依賴

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${version}</version>
</dependency>
或者
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <aifactId>spring-boot-starter-aop</artifactId>
</dependency>

啟用重試

@Configuration
@EnableRetry
public class RetryConfig {
}

@Retryable

在需要重試的方法上加上@Retryable注解

部分參數(shù)如下

  • label: 重試的名字,系統(tǒng)唯一,默認 “”
  • maxAttempts:異常時重試次數(shù),默認 3
  • maxAttemptsExpression: SpEL表達式 ,從配置文件獲取maxAttempts的值,可以在application.yml設(shè)置,與maxAttempts二選一
  • exceptionExpression: SpEL表達式,匹配異常。例如:exceptionExpression = "#{message.contains('test')}"
  • include:需要重試的異常
  • exclude:不需要重試的異常
  • backoff:重試中的退避策略 ,@Backoff注解,部分參數(shù)如下:
  • value: 重試間隔ms,默認 1000
  • delay: 在指數(shù)情況下用作初始值,在均勻情況下用作最小值, 它與value屬性不能共存,當delay不設(shè)置的時候會去讀value屬性設(shè)置的值,如果delay設(shè)置的話則會忽略value屬性, 默認 0
  • delayExpression: SpEL表達式 ,從配置文件獲取delay的值,可以在application.yml設(shè)置,與delay二選一
  • multiplier: 則用作產(chǎn)生下一個退避延遲的乘數(shù) , 默認 0
  • delay = 2000, multiplier = 2 表示第一次重試間隔為2s,第二次為4秒,第三次為8s
  • maxDelay: 最大的重試間隔,當超過這個最大的重試間隔的時候,重試的間隔就等于maxDelay的值 默認 0
@Service
@Slf4j
public class RetryService {
   
    @Retryable(value = RuntimeException.class)
    public void test(String param){
        log.info(param);
        throw new RuntimeException("laker Error");
    }
}

當拋出RuntimeException時會嘗試重試。

根據(jù)@Retryable的默認行為,重試最多可能發(fā)生 3 次,重試之間有 1 秒的延遲。

測試日志如下

2022-07-16 18:23:46.274  INFO 10204 --- [           main] com.example.demo.retry.RetryService      : laker
2022-07-16 18:23:47.278  INFO 10204 --- [           main] com.example.demo.retry.RetryService      : laker
2022-07-16 18:23:48.289  INFO 10204 --- [           main] com.example.demo.retry.RetryService      : laker

java.lang.RuntimeException: laker Error
    at com.example.demo.retry.RetryService.test(RetryService.java:18)
    at com.example.demo.retry.RetryService$$FastClassBySpringCGLIB$$41aa3d8d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)

@Recover

@Retryable方法重試失敗之后,最后就會調(diào)用@Recover方法。用于@Retryable失敗時的兜底處理方法。

@Recover的方法必須要與@Retryable注解的方法保持一致,第一入?yún)橐卦嚨漠惓?,其他參?shù)與@Retryable保持一致,返回值也要一樣,否則無法執(zhí)行!,方法可以是public、private.

@Service
@Slf4j
public class RetryService {
    @Retryable(value = RuntimeException.class)
    public void test(String param) {
        log.info(param);
        throw new RuntimeException("laker Error");
    }
    @Recover
    void recover(RuntimeException e, String param) {
        log.info("recover e:{},param:{}", e, param);
    }
}

在這里,當拋出RuntimeException時會嘗試重試。

test方法在 3 次嘗試后不斷拋出 RuntimeException,則會調(diào)用recover()方法。

測試日志如下:

2022-07-16 18:40:19.828  INFO 4308 --- [           main] com.example.demo.retry.RetryService      : laker
2022-07-16 18:40:20.834  INFO 4308 --- [           main] com.example.demo.retry.RetryService      : laker
2022-07-16 18:40:21.848  INFO 4308 --- [           main] com.example.demo.retry.RetryService      : laker
2022-07-16 18:40:21.849  INFO 4308 --- [           main] com.example.demo.retry.RetryService      : recover e:java.lang.RuntimeException: laker Error,param:laker

@CircuitBreaker

熔斷模式:指在具體的重試機制下失敗后打開斷路器,過了一段時間,斷路器進入半開狀態(tài),允許一個進入重試,若失敗再次進入斷路器,成功則關(guān)閉斷路器,注解為@CircuitBreaker,具體包括熔斷打開時間、重置過期時間。

同一個方法上與@Retryable注解只能二選一,否則注解失效

相關(guān)代碼參見CircuitBreakerRetryPolicy.java

主要參數(shù)如下:

  • maxAttempts: 最大嘗試次數(shù)(包括第一次失?。J為 3
  • maxAttemptsExpression: SpEL表達式 ,從配置文件獲取maxAttempts的值,可以在application.yml設(shè)置,與maxAttempts二選一
  • openTimeout:當在此超時時間內(nèi)達到maxAttempts失敗時,電路會自動打開,防止訪問下游組件。默認為 5000
  • openTimeoutExpression: SpEL表達式
  • resetTimeout: 如果電路打開的時間超過此超時時間,則它會在下一次調(diào)用時重置,以使下游組件有機會再次響應(yīng)。默認為 20000
  • resetTimeoutExpression: SpEL表達式
  • label:短路器的名字,系統(tǒng)唯一
  • include:需要短路的異常
  • exclude:不需要短路的異常
   @CircuitBreaker(maxAttempts = 2, openTimeout = 1000, resetTimeout = 2000, value = RuntimeException.class)
    public void testCircuitBreaker(String param) {
        log.info(param);
        throw new RuntimeException("laker Error");
    }

    @Recover
    void recover(RuntimeException e, String param) {
        log.info("recover e:{},param:{}", e, param);
    }

當拋出RuntimeException時會嘗試熔斷。

在openTimeout 1s時間內(nèi),觸發(fā)異常超過2次,斷路器打開,testCircuitBreaker業(yè)務(wù)方法不允許執(zhí)行,直接執(zhí)行恢復方法recover。

經(jīng)過resetTimeout 2s后,熔斷器關(guān)閉,繼續(xù)執(zhí)行testCircuitBreaker業(yè)務(wù)方法。

注意:這里沒有上面@Retryable的能力了哦,但是這個實際項目還是很需要的。

測試日志如下:

2022-07-16 19:22:26.195  laker0
2022-07-16 19:22:26.195  recover e:java.lang.RuntimeException: laker Error,param:laker0
2022-07-16 19:22:26.196  laker1
2022-07-16 19:22:26.196  recover e:java.lang.RuntimeException: laker Error,param:laker1
2022-07-16 19:22:26.196  recover e:java.lang.RuntimeException: laker Error,param:laker2
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker3
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker4
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker5
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker6
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker7
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker8
2022-07-16 19:22:26.197  recover e:java.lang.RuntimeException: laker Error,param:laker9
2022-07-16 19:22:32.206  laker3
2022-07-16 19:22:32.206  recover e:java.lang.RuntimeException: laker Error,param:laker0

高級實戰(zhàn)

上面說到了,斷路器@CircuitBreaker 并么有攜帶重試功能,所有我們實際項目要結(jié)合2者使用。

方式一 @CircuitBreaker + RetryTemplate

1.自定義RetryTemplate

@Configuration
@EnableRetry
public class RetryConfig {
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        // 退避策略 因為是瞬時異常 所以不宜過大,100ms即可
        fixedBackOffPolicy.setBackOffPeriod(100L);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        // 重試3次
        retryPolicy.setMaxAttempts(3);
        retryTemplate.setRetryPolicy(retryPolicy);
        return retryTemplate;
    }
}

2.在斷路器中用retryTemplate包裹一層

   @CircuitBreaker(maxAttempts = 2, openTimeout = 1000, resetTimeout = 2000, value = RuntimeException.class)
    public String testCircuitBreaker(String param) {
        return retryTemplate.execute(context -> {
            log.info(String.format("Retry count %d", context.getRetryCount()) + param);
            throw new RuntimeException("laker Error");
        });
    }
    @Recover
    String recover(RuntimeException e, String param) {
        log.info("recover e:{},param:{}", e, param);
        return "";
    }

測試日志如下:

2022-07-16 20:14:11.385 Retry count 0laker0
2022-07-16 20:14:11.496 Retry count 1laker0
2022-07-16 20:14:11.606 Retry count 2laker0
2022-07-16 20:14:11.607 recover e:java.lang.RuntimeException: laker Error,param:laker0
2022-07-16 20:14:11.608 Retry count 0laker1
2022-07-16 20:14:11.714 Retry count 1laker1
2022-07-16 20:14:11.826 Retry count 2laker1
2022-07-16 20:14:11.826 recover e:java.lang.RuntimeException: laker Error,param:laker1
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker2
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker3
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker4
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker5
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker6
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker7
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker8
2022-07-16 20:14:11.827 recover e:java.lang.RuntimeException: laker Error,param:laker9

方式二 @CircuitBreaker + @Retryable

定義2個springBean,一個用于重試,一個用于熔斷,且是熔斷包含著重試,否則會失效。

@Service
@Slf4j
public class RetryService {
    @Autowired
    RetryTemplate retryTemplate;

    @Retryable(value = RuntimeException.class,backoff = @Backoff(delay = 100))
    public void test(String param) {
        log.info(param);
        throw new RuntimeException("laker Error");
    }
}

@Service
@Slf4j
public class CircuitBreakerService {

    @Autowired
    RetryService retryService;

    @CircuitBreaker(maxAttempts = 2, openTimeout = 1000, resetTimeout = 2000, value = RuntimeException.class)
    public void testCircuitBreaker(String param) {
        // 這里是添加了重試注解的方法
        retryService.test(param);
    }

    @Recover
    void recover(RuntimeException e, String param) {
        log.info("recover e:{},param:{}", e, param);
    }
}

參考

https://blog.csdn.net/cckevincyh/article/details/112347200

https://medium.com/@just4give/build-resilient-microservices-using-spring-retry-and-circuit-breaker-pattern-a92abab567ab

到此這篇關(guān)于從零搭建開發(fā)腳手架之集成Spring Retry實現(xiàn)失敗重試和熔斷器模式的文章就介紹到這了,更多相關(guān)Spring Retry重試和熔斷器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java8函數(shù)式編程應(yīng)用小結(jié)

    Java8函數(shù)式編程應(yīng)用小結(jié)

    Java8非常重要的就是引入了函數(shù)式編程的思想,使得這門經(jīng)典的面向?qū)ο笳Z言有了函數(shù)式的編程方式,彌補了很大程度上的不足,函數(shù)式思想在處理復雜問題上有著更為令人稱贊的特性,本文給大家介紹Java8函數(shù)式編程應(yīng)用小結(jié),感興趣的朋友一起看看吧
    2023-12-12
  • java使用UDP實現(xiàn)多人聊天功能

    java使用UDP實現(xiàn)多人聊天功能

    這篇文章主要為大家詳細介紹了java使用UDP實現(xiàn)多人聊天功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 如何把springboot jar項目 改為war項目

    如何把springboot jar項目 改為war項目

    這篇文章主要介紹了如何把springboot jar項目 改為war項目,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • SpringBoot啟動security后如何關(guān)閉彈出的/login頁面

    SpringBoot啟動security后如何關(guān)閉彈出的/login頁面

    這篇文章主要介紹了SpringBoot啟動security后如何關(guān)閉彈出的login頁面問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringBoot項目中新增脫敏功能的實例代碼

    SpringBoot項目中新增脫敏功能的實例代碼

    項目中,由于使用端有兩個,對于兩個端的數(shù)據(jù)權(quán)限并不一樣。Web端可以查看所有數(shù)據(jù),小程序端只能查看脫敏后的數(shù)據(jù),這篇文章主要介紹了SpringBoot項目中新增脫敏功能,需要的朋友可以參考下
    2022-11-11
  • Java中讀取文件轉(zhuǎn)換為字符串的方法

    Java中讀取文件轉(zhuǎn)換為字符串的方法

    今天小編就為大家分享一篇Java中讀取文件轉(zhuǎn)換為字符串的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • SpringSecurity自定義登錄接口的實現(xiàn)

    SpringSecurity自定義登錄接口的實現(xiàn)

    本文介紹了使用Spring Security實現(xiàn)自定義登錄接口,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-01-01
  • 解決try-catch捕獲異常信息后Spring事務(wù)失效的問題

    解決try-catch捕獲異常信息后Spring事務(wù)失效的問題

    這篇文章主要介紹了解決try-catch捕獲異常信息后Spring事務(wù)失效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java數(shù)據(jù)結(jié)構(gòu)之散列表(動力節(jié)點Java學院整理)

    Java數(shù)據(jù)結(jié)構(gòu)之散列表(動力節(jié)點Java學院整理)

    散列表(Hash table,也叫哈希表),是根據(jù)關(guān)鍵字(key value)而直接進行訪問的數(shù)據(jù)結(jié)構(gòu)。這篇文章給大家介紹了java數(shù)據(jù)結(jié)構(gòu)之散列表,包括基本概念和散列函數(shù)相關(guān)知識,需要的的朋友參考下吧
    2017-04-04
  • 解決mybatis中的mapper命名問題

    解決mybatis中的mapper命名問題

    這篇文章主要介紹了解決mybatis中的mapper命名問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06

最新評論

疏附县| 通化市| 清河县| 西平县| 民乐县| 南投市| 台北市| 柯坪县| 屏山县| 连云港市| 鹤山市| 潼南县| 鱼台县| 当阳市| 温州市| 清流县| 石门县| 阳原县| 玉树县| 丰县| 青河县| 广水市| 卢龙县| 莲花县| 江华| 上高县| 舒兰市| 仪陇县| 河东区| 常州市| 赤壁市| 英德市| 革吉县| 本溪市| 沛县| 禹州市| 揭东县| 大关县| 桑日县| 南投市| 富平县|