使用Spring Boot + Resilience 4j實現斷路器
Resilience 4j提供以下功能。
- 斷路器
- RateLimiter
- 艙壁
- 重試
- 快取記憶體
- TimeLimiter
如果您打算在Spring Boot中使用它,可以使用Starter。請注意,Spring Boot 1.x和2.x系列之間的artifactId似乎有所不同。另外,上面只包含CircuitBreaker和RateLimiter,在使用其他功能時需要單獨新增依賴項。(由於未準備好AutoConfigure,您還需要自己定義bean。)
這次我將總結如何在Spring Boot 2.x系列中使用CircuitBreaker和RateLimiter。
環境
- JDK 8
- Spring Boot 2.1.2.RELEASE
- Resilience 4j 0.13.2
斷路器
當某些具有微服務的服務發生故障時,可以臨時阻止對故障服務的訪問並防止故障傳播。
CircuitBreaker有三種狀態:Closed,Open,HalfOpen。如果是正常的,則它是關閉的,如果處理失敗超過一定數量,它將變為開啟並且訪問被阻止。當在開啟狀態下經過一段時間後,進入HalfOpen狀態。如果處理在HalfOpen狀態下失敗超過一定量,則返回到關閉狀態。
在Resilience 4j中,處理的成功和失敗由環形緩衝器Ring Bit Buffer管理,並且當緩衝器中的故障數超過設定的速率時,狀態轉變。
斷路器使用狀態中的Ring Bit Buffer CLOSED來儲存呼叫的成功或失敗狀態。成功的呼叫儲存為0位,失敗的呼叫儲存為1位。Ring Bit Buffer具有(可配置的)固定大小。環位緩衝區在內部使用類似資料結構的BitSet來儲存與布林陣列相比節省記憶體的位。BitSet使用long []陣列來儲存這些位。這意味著BitSet只需要一個包含16個長(64位)值的陣列來儲存1024個呼叫的狀態。
例如,如果環形緩衝區的大小為10,則必須至少評估10個呼叫,然後才能計算故障率。如果僅評估了9個呼叫,即使所有9個呼叫都失敗,斷路器也不會開啟。
用於Closed - > Open和HalfOpen - > Closed判斷的環形緩衝區是不同的,可以定義大小,但使用相同的判斷條件(錯誤率)。
在持續關閉時間結束後,斷路器狀態從OPEN更改為HALF_OPEN並允許呼叫以檢視後端是否仍然不可用或已再次可用。
斷路器使用另一個(可配置的)環位緩衝區來評估HALF_OPEN狀態中的故障率。如果故障率高於配置的閾值,則狀態將更改回OPEN。如果故障率低於或等於閾值,則狀態變回CLOSED。
此外,處理的成功和失敗由異常判斷。預設情況下,如果任何異常丟擲異常,則會將其視為處理失敗,但您也可以指定要將其視為失敗的條件。
設定
application.yml你可以設定定義多個斷路器。
resilience4j: circuitbreaker: backends: circuitA: # #斷路器名 truering-buffer-size-in-closed-state: 5 #環形緩衝區是在封閉狀態下使用的大小 ring-buffer-size-in-half-open-state: 3 # HalfOpen 狀態下的大小 wait-duration-in-open-state : 5000 # Open持續時間 failure-rate-threshold: 50 # 到開啟狀態的閾值 record-failure-predicate: com.example.resilience.RecordFailurePredicate ignore-exceptions: 沒有失敗#異常類和計數 - com.example.resilience.exception.BusinessException record-exceptions: #異常類失敗和計數 - com.example.resilience.exception.SystemException circuitB: ・・・ |
如果你想只考慮一個特定的異常和故障使用RecordExceptions,當你不想忽視特定的異常時使用ignoreExceptions。
有兩種方法可以使用Spring AOP並在函式中實現它。無論哪種實現,如果Circuit處於Open狀態,它將生成CircuitBreakerOpenException。
在以下實現示例中,為簡單起見,它不是微服務。最初RestTemplate,我認為這將是Service Class 呼叫其他服務API等使用等的過程。
Spring AOP實現
透過@CircuitBreaker(name = "hogehoge")註釋到類或方法上則可以啟用斷路器。如果在類指定這個註釋,則為所有公共方法啟用斷路器。
@Service @CircuitBreaker(name = "circuitB") public class CircuitBreakerService { public String aop(String str) { if (str == null) { throw new RuntimeException(); } return "success!!"; } } |
呼叫者不用考慮任何事情,只需執行該方法即可。
@RestController @RequestMapping("/circuit") public class CircuitBreakerController { private final CircuitBreakerService service; public CircuitBreakerController(CircuitBreakerService service) { this.service = service; } @GetMapping("/aop") public String aop(@RequestParam(required = false) String str) { return service.aop(str); } } |
如何寫業務函式?
@Service public class CircuitBreakerService { public String func(String str) { if (str == null) { throw new RuntimeException(); } return "success!!"; } } |
呼叫端使用斷路器的decorate~方法修飾要呼叫的方法。
@RestController @RequestMapping("/circuit") public class CircuitBreakerController { private final CircuitBreaker circuitBreaker; private final CircuitBreakerService service; public CircuitBreakerController(CircuitBreakerRegistry registry, CircuitBreakerService service) { this.circuitBreaker = registry.circuitBreaker("circuitA"); this.service = service; } @GetMapping("/func") public String func(@RequestParam(required = false) String str) { return CircuitBreaker.decorateSupplier(circuitBreaker, () -> service.func(str)).get(); } } |
後備處理
接下來,如果發生故障,執行回退過程怎麼辦?在Hystrix 的情況下,透過指定@HystrixCommand("hogeMethod"),由於Resilience4j沒有設定的這樣的功能,必須自己實現。
@RestController @RequestMapping("/circuit") public class CircuitBreakerController { private final CircuitBreaker circuitBreaker; private final CircuitBreakerService service; public CircuitBreakerController(CircuitBreakerRegistry registry, CircuitBreakerService service) { this.circuitBreaker = registry.circuitBreaker("circuitA"); this.service = service; } @GetMapping("/func") public String func(@RequestParam(required = false) String str) { return Try.ofSupplier(CircuitBreaker.decorateSupplier(circuitBreaker, () -> service.func(str))) .recover(CircuitBreakerOpenException.class, "Circuit is Open!!") .recover(RuntimeException.class, "fallback!!").get(); } } |
完整的原始碼位於下方。https://github.com/d-yosh/spring-boot-resilience4j-example
RateLimiter
您可以限制每單位時間的執行次數。
單位時間是一個週期,並且可以在一個週期中執行的數量是有限的。如果它超過了可以在一個迴圈中執行的上限,則讓它等待,如果等待時間超過超時時間,則發生RequestNotPermitted。
在application.yml可以定義多個RateLimiter。
resilience4j:
ratelimiter:
limiters:
limiterA: # #RateLimiter名稱
limit-for-period: 1 # 每時間單位#可執行處理數
limit-refresh-period-in-millis: 10000 # #單位時間(毫秒)
timeout-in-millis: 10000 #timeout time(milliseconds)
limiterB:
・・・
它與斷路器實現方式相同,有兩種方法可以使用Spring AOP並在業務函式中編寫它。實現方法也類似於斷路器。
@Service @RateLimiter(name = "limiterB") public class RateLimiterService { public String func() { return LocalDateTime.now().toString(); } } |
呼叫者不用考慮任何事情,只需執行該方法即可。
@RestController @RequestMapping("/ratelimiter") public class RateLimiterController { private final RateLimiterService service; public RateLimiterController(RateLimiterService service) { this.service = service; } @GetMapping("aop") public String aop() { return service.aop(); } } |
函式方法:
@Service public class RateLimiterService { public String func() { return LocalDateTime.now().toString(); } } @RestController @RequestMapping("/ratelimiter") public class RateLimiterController { private final RateLimiter rateLimiter; private final RateLimiterService service; public RateLimiterController(RateLimiterRegistry registry, RateLimiterService service) { this.rateLimiter = registry.rateLimiter("limiterA"); this.service = service; } @GetMapping("func") public String func() { return Try.ofSupplier(RateLimiter.decorateSupplier(rateLimiter, service::func)) .recover(RequestNotPermitted.class, "Request Not Permitted!!").get(); } } |
後備處理,與斷路器一樣,沒有自動執行回退處理的機制,因此您需要自己實現它。
完整的原始碼位於下方。https://github.com/d-yosh/spring-boot-resilience4j-example
單位時間為5秒,超時時間為1秒,每單位時間的執行次數為1。如果同時傳送多個請求,則會發出失敗請求。(如果您同時請求三個,則至少一個將始終失敗。)
$ curl http://localhost:8080/ratelimiter/func 2019-01-22T23:09:35.612 $ curl http://localhost:8080/ratelimiter/func Request Not Permitted!! |
相關文章
- 使用Resilience4J實現斷路器模式模式
- Spring Boot中使用斷路器模式實現彈性微服務Spring Boot模式微服務
- Java 專案中使用 Resilience4j 框架實現隔斷機制/斷路器Java框架
- 使用Resilience4j實施反應式斷路器 - WenqiENQ
- Spring Boot2+Resilience4j實現容錯之BulkheadSpring Boot
- 帶有Resilience4j斷路器的Spring雲閘道器 - romeSpring
- Spring Cloud:使用Hystrix實現斷路器原理詳解(下)SpringCloud
- 使用Spring Boot實現事務管理Spring Boot
- 使用Spring Boot實現的GraphQL示例Spring Boot
- 使用Spring Boot實現模組化Spring Boot
- 使用Spring Boot實現訊息佇列Spring Boot佇列
- 使用Spring Boot實現分散式事務Spring Boot分散式
- 使用Spring Boot實現Redis事務 | VinsguruSpring BootRedis
- 使用Spring Boot和Kafka Streams實現CQRSSpring BootKafka
- 利用Spring Boot實現微服務的API閘道器統一限流與熔斷Spring Boot微服務API
- 使用Spring Boot實現檔案上傳功能Spring Boot
- 使用Vue+Spring Boot實現Excel上傳VueSpring BootExcel
- Spring Cloud入門教程-Hystrix斷路器實現容錯和降級SpringCloud
- Spring Boot實現資料訪問計數器Spring Boot
- 介紹Spring Cloud斷路器SpringCloud
- Spring Boot實現Web SocketSpring BootWeb
- 利用Spring Boot實現微服務的鏈路追蹤Spring Boot微服務
- 使用 Spring Boot 3.2 和 CRaC 實現更快啟動Spring Boot
- 使用Spring Boot實現資料庫整合配置案例Spring Boot資料庫
- spring boot使用Jedis整合Redis實現快取(AOP)Spring BootRedis快取
- 使用Spring Boot實現動態健康檢查HealthChecksSpring Boot
- Spring Boot Admin 整合診斷利器 Arthas 實踐Spring Boot
- resilience4j不夠用?自制分散式斷路器來幫忙 -Nicolas分散式
- 在Spring Boot中實現API閘道器與路由Spring BootAPI路由
- Spring Boot中實現Thymeleaf通知Spring Boot
- Spring boot webflux 中實現 RequestContextHolderSpring BootWebUXContext
- 使用 Resilience4j 框架實現重試機制框架
- 【流式傳輸】使用Spring Boot實現ChatGpt流式傳輸Spring BootChatGPT
- 使用Spring Boot, Istio和Cert Manager實現Kubernetes的HTTPSSpring BootHTTP
- Spring Boot系列之使用@Scheduled實現定時任務Spring Boot
- Spring Boot 使用 JSR303 實現引數驗證Spring BootJS
- (譯)使用Spring Boot和Axon實現CQRS&Event SourcingSpring Boot
- 如何使用Spring Boot,Spring Data和H2 DB實現REST APISpring BootRESTAPI