首頁 > 軟體

Spring Boot Reactor 整合 Resilience4j詳析

2022-09-24 14:02:01

1 引入 pom 包

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-all</artifactId>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
</dependency>

2 設定說明

2.1 限流 ratelimiter

兩個限流設定:backendA 1s 中最多允許 10 次請求;

backendB 每 500ms 最多允許 6 次請求。

resilience4j.ratelimiter:
  instances:
    backendA:
      limitForPeriod: 10
      limitRefreshPeriod: 1s
      timeoutDuration: 10ms
      registerHealthIndicator: true
      eventConsumerBufferSize: 100
    backendB:
      limitForPeriod: 6
      limitRefreshPeriod: 500ms
      timeoutDuration: 3s
設定屬性預設值描述
timeoutDuration5【s】一個執行緒等待許可的預設等待時間
limitRefreshPeriod500【ns】限制重新整理的週期。在每個週期之後,速率限制器將其許可權計數設定回 limitForPeriod 值
limitForPeriod50一個 limitRefreshPeriod (週期)允許存取的數量(許可數量)

2.2 重試 retry

注意指定需要重試的異常,不是所有的異常重試都有效。比如 DB 相關校驗異常,如唯一約束等,重試也不會成功的。

重試設定:

resilience4j.retry:
  instances:
    backendA:
      maxAttempts: 3
      waitDuration: 10s
      enableExponentialBackoff: true
      exponentialBackoffMultiplier: 2
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException

    backendB:
      maxAttempts: 3
      waitDuration: 10s
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
設定屬性預設值描述
maxAttempts3最大重試次數(包括第一次)
waitDuration500【ms】兩次重試之間的等待間隔
intervalFunctionnumOfAttempts -> waitDuration修改失敗後等待間隔的函數。預設情況下,等待時間是個常數。
retryOnResultPredicateresult->false設定一個判斷結果是否應該重試的 predicate 函數。如果結果應該重試,Predicate 必須返回 true,否則它必須返回 false。
retryExceptionPredicatethrowable -> true和 retryOnResultPredicate 類似,如果要重試,Predicate 必須返回true,否則返回 false。
retryExceptions需要重試的異常型別列表
ignoreExceptions不需要重試的異常型別列表
failAfterMaxAttemptsfalse當重試達到設定的 maxAttempts 並且結果仍未通過 retryOnResultPredicate 時啟用或禁用丟擲 MaxRetriesExceededException 的布林值
intervalBiFunction(numOfAttempts, Either<throwable, result>) -> waitDuration根據 maxAttempts 和結果或異常修改失敗後等待間隔時間的函數。與 intervalFunction 一起使用時會丟擲 IllegalStateException。

2.3 超時 TimeLimiter

超時設定:

resilience4j.timelimiter:
  instances:
    backendA:
      timeoutDuration: 2s
      cancelRunningFuture: true
    backendB:
      timeoutDuration: 1s
      cancelRunningFuture: false

超時設定比較簡單,主要是設定 timeoutDuration 也就是超時的時間。

cancelRunningFuture 的意思是:是否應該在執行的 Future 呼叫 cancel 去掉呼叫。

2.4 斷路器 circuitbreaker

斷路器有幾種狀態:關閉、開啟、半開。注意:開啟,意味著不能存取,會迅速失敗。

CircuitBreaker 使用滑動視窗來儲存和彙總呼叫結果。您可以在基於計數的滑動視窗和基於時間的滑動視窗之間進行選擇。基於計數的滑動視窗聚合最後 N 次呼叫的結果。基於時間的滑動視窗聚合了最後 N 秒的呼叫結果。

斷路器設定:

resilience4j.circuitbreaker:
  instances:
    backendA:
      // 健康指標引數,非斷路器屬性
      registerHealthIndicator: true
      slidingWindowSize: 100
設定屬性預設值描述
slidingWindowSize100記錄斷路器關閉狀態下(可以存取的情況下)的呼叫的滑動視窗大小
failureRateThreshold50(百分比)當失敗比例超過 failureRateThreshold 的時候,斷路器會開啟,並開始短路呼叫
slowCallDurationThreshold60000【ms】請求被定義為慢請求的閾值
slowCallRateThreshold100(百分比)慢請求百分比大於等於該值時,開啟斷路器開關
permittedNumberOfCalls10半開狀態下允許通過的請求數
maxWaitDurationInHalfOpenState0設定最大等待持續時間,該持續時間控制斷路器在切換到開啟之前可以保持在半開狀態的最長時間。

值 0 表示斷路器將在 HalfOpen 狀態下無限等待,直到所有允許的呼叫都已完成。

2.5 壁倉 bulkhead

resilience4j 提供了兩種實現壁倉的方法:

  • SemaphoreBulkhead 使用 Semaphore 實現
  • FixedThreadPoolBulkhead 使用有界佇列和固定執行緒池實現
resilience4j.bulkhead:
  instances:
    backendA:
      maxConcurrentCalls: 10
    backendB:
      maxWaitDuration: 10ms
      maxConcurrentCalls: 20

resilience4j.thread-pool-bulkhead:
  instances:
    backendC:
      maxThreadPoolSize: 1
      coreThreadPoolSize: 1
      queueCapacity: 1

2.5.1 SemaphoreBulkhead

設定屬性預設值描述
maxConcurrentCalls25允許的並行執行的數量
maxWaitDuration0嘗試進入飽和隔板時執行緒應被阻止的最長時間

2.5.2 FixedThreadPoolBulkhead

設定屬性預設值描述
maxThreadPoolSizeRuntime.getRuntime().availableProcessors()執行緒池最大執行緒個數
coreThreadPoolSizeRuntime.getRuntime().availableProcessors()-1執行緒池核心執行緒個數
queueCapacity100執行緒池佇列容量
keepAliveDuration20【ms】執行緒數超過核心執行緒數之後,空餘執行緒在終止之前等待的最長時間

3 使用

3.1 設定

在 application.yml 檔案中新增以下 resilience4j 設定:

resilience4j.circuitbreaker:
  instances:
    backendA:
      registerHealthIndicator: true
      slidingWindowSize: 100

resilience4j.retry:
  instances:
    backendA:
      maxAttempts: 3
      waitDuration: 10s
      enableExponentialBackoff: true
      exponentialBackoffMultiplier: 2
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException

    backendB:
      maxAttempts: 3
      waitDuration: 10s
      retryExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException


resilience4j.bulkhead:
  instances:
    backendA:
      maxConcurrentCalls: 10
    backendB:
      maxWaitDuration: 10ms
      maxConcurrentCalls: 20

resilience4j.thread-pool-bulkhead:
  instances:
    backendC:
      maxThreadPoolSize: 1
      coreThreadPoolSize: 1
      queueCapacity: 1

resilience4j.ratelimiter:
  instances:
    backendA:
      limitForPeriod: 10
      limitRefreshPeriod: 1s
      timeoutDuration: 10ms
      registerHealthIndicator: true
      eventConsumerBufferSize: 100
    backendB:
      limitForPeriod: 6
      limitRefreshPeriod: 500ms
      timeoutDuration: 3s

resilience4j.timelimiter:
  instances:
    backendA:
      timeoutDuration: 2s
      cancelRunningFuture: true
    backendB:
      timeoutDuration: 1s
      cancelRunningFuture: false

3.2 使用註解實現

直接在需要限流的方法上增加註解@RateLimiter 實現限流;增加註解@Retry 實現重試;增加註解 @CircuitBreaker 熔斷;增加註解 @Bulkhead 實現壁倉。name 屬性中分別填寫限流器、重試、熔斷、壁倉元件的名字。

@Bulkhead(name = "backendA")
@CircuitBreaker(name = "backendA")
@Retry(name = "backendA")
@RateLimiter(name = "backendA")
public Mono<List<User>> list() {
  long startTime = System.currentTimeMillis();
  return Mono.fromSupplier(() -> {
        return userRepository.findAll();
      }).doOnError(e -> {
        // 列印異常紀錄檔&增加監控(自行處理)
        logger.error("list.user.error, e", e);
      })
      .doFinally(e -> {
        // 耗時 & 整體健康
        logger.info("list.user.time={}, ", System.currentTimeMillis() - startTime);
      });
}
  
@Bulkhead(name = "backendA")
@CircuitBreaker(name = "backendA")//最多支援10個並行量
@Retry(name = "backendA")//使用 backendA 重試器,如果丟擲 IOException 會重試三次。
@RateLimiter(name = "backendA")// 限流 10 Qps
public Mono<Boolean> save(User user) {
  long startTime = System.currentTimeMillis();
  return Mono.fromSupplier(() -> {
        return userRepository.save(user) != null;
      })
      .doOnError(e -> {
        // 列印異常紀錄檔&增加監控(自行處理)
        logger.error("save.user.error, user={}, e", user, e);
      })
      .doFinally(e -> {
        // 耗時 & 整體健康
        logger.info("save.user.time={}, user={}", user, System.currentTimeMillis() - startTime);
      });
}

注意:以上所有元件,都支援自定義。

到此這篇關於Spring Boot Reactor 整合 Resilience4j詳析的文章就介紹到這了,更多相關Spring Boot Reactor 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com