淺析Spring Boot單體應用熔斷技術的使用
阿新 • • 發佈:2021-01-21
壹、入圍方案
Sentinel
- github地址:https://sentinelguard.io/zh-cn/docs/introduction.html
- 阿里出品,Spring Cloud Alibaba限流元件,目前持續更新中
- 自帶Dashboard,可以檢視介面Qps等,並且可以動態修改各種規則
- 流量控制,直接限流、冷啟動、排隊
- 熔斷降級,限制併發限制數和相應時間
- 系統負載保護,提供系統級別防護,限制總體CPU等
- 主要核心:資源,規則(流量控制規則、熔斷降級規則、系統保護規則、來源訪問控制規則 和 熱點引數規則。),和指標
- 文件非常清晰和詳細,中文
- 支援動態規則(推模式和拉模式)
Hystrix
- github地址:https://github.com/Netflix/Hystrix/wiki
- Netflix出品,Spring Cloud Netflix限流元件,已經停止新特性開發,只進行bug修復,最近更新為2018年,功能穩定
- 有簡單的dashboard頁面
- 以隔離和熔斷為主的容錯機制,超時或被熔斷的呼叫將會快速失敗,並可以提供 fallback 機制的初代熔斷框架,異常統計基於滑動視窗
resilience4j
- github地址:https://resilience4j.readme.io/docs
- 是一款輕量、簡單,並且文件非常清晰、豐富的熔斷工具。是Hystrix替代品,實現思路和Hystrix一致,目前持續更新中
- 需要自己對micrometer、prometheus以及Dropwizard metrics進行整合
- CircuitBreaker 熔斷
- Bulkhead 隔離
- RateLimiter QPS限制
- Retry 重試
- TimeLimiter 超時限制
- Cache 快取
自己實現(基於Guava)
- 基於Guava的令牌桶,可以輕鬆實現對QPS進行限流
貳、技術對比
叄、應用改造
3.1、sentinel
3.1.1、引入依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.0.3.RELEASE</version> </dependency>
3.1.2、改造介面或者service層
@SentinelResource(value = "allInfos",fallback = "errorReturn")
@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface SentinelResource { //資源名稱 String value() default ""; //流量方向 EntryType entryType() default EntryType.OUT; //資源型別 int resourceType() default 0; //異常處理方法 String blockHandler() default ""; //異常處理類 Class<?>[] blockHandlerClass() default {}; //熔斷方法 String fallback() default ""; //預設熔斷方法 String defaultFallback() default ""; //熔斷類 Class<?>[] fallbackClass() default {}; //統計異常 Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class}; //忽略異常 Class<? extends Throwable>[] exceptionsToIgnore() default {}; }
@RequestMapping("/get") @ResponseBody @SentinelResource(value = "allInfos",fallback = "errorReturn") public JsonResult allInfos(HttpServletRequest request,HttpServletResponse response,@RequestParam Integer num){ try { if (num % 2 == 0) { log.info("num % 2 == 0"); throw new BaseException("something bad with 2",400); } return JsonResult.ok(); } catch (ProgramException e) { log.info("error"); return JsonResult.error("error"); } }
3.1.3、針對介面配置熔斷方法或者限流方法
預設過濾攔截所有Controller介面
/** * 限流,引數需要和方法保持一致 * @param request * @param response * @param num * @return * @throws BlockException */ public JsonResult errorReturn(HttpServletRequest request,@RequestParam Integer num) throws BlockException { return JsonResult.error("error 限流" + num ); } /** * 熔斷,引數需要和方法保持一直,並且需要新增BlockException異常 * @param request * @param response * @param num * @param b * @return * @throws BlockException */ public JsonResult errorReturn(HttpServletRequest request,@RequestParam Integer num,BlockException b) throws BlockException { return JsonResult.error("error 熔斷" + num ); }
注意也可以不配置限流或者熔斷方法。通過全域性異常去捕獲UndeclaredThrowableException或者BlockException避免大量的開發量
3.1.4、接入dashboard
spring: cloud: sentinel: transport: port: 8719 dashboard: localhost:8080
3.1.5、規則持久化和動態更新
接入配置中心如:zookeeper等等,並對規則採用推模式
3.2、hystrix
3.2.1、引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> <version>2.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.0.4.RELEASE</version> </dependency>
3.2.2、改造介面
@HystrixCommand(fallbackMethod = "timeOutError")
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface HystrixCommand { String groupKey() default ""; String commandKey() default ""; String threadPoolKey() default ""; String fallbackMethod() default ""; HystrixProperty[] commandProperties() default {}; HystrixProperty[] threadPoolProperties() default {}; Class<? extends Throwable>[] ignoreExceptions() default {}; ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER; HystrixException[] raiseHystrixExceptions() default {}; String defaultFallback() default ""; }
@RequestMapping("/get") @ResponseBody @HystrixCommand(fallbackMethod = "fallbackMethod") public JsonResult allInfos(HttpServletRequest request,@RequestParam Integer num){ try { if (num % 3 == 0) { log.info("num % 3 == 0"); throw new BaseException("something bad whitch 3",400); } return JsonResult.ok(); } catch (ProgramException | InterruptedException exception) { log.info("error"); return JsonResult.error("error"); } }
3.2.3、針對介面配置熔斷方法
/** * 該方法是熔斷回撥方法,引數需要和介面保持一致 * @param request * @param response * @param num * @return */ public JsonResult fallbackMethod(HttpServletRequest request,@RequestParam Integer num) { response.setStatus(500); log.info("發生了熔斷!!"); return JsonResult.error("熔斷"); }
3.2.4、配置預設策略
hystrix: command: default: execution: isolation: strategy: THREAD thread: # 執行緒超時15秒,呼叫Fallback方法 timeoutInMilliseconds: 15000 metrics: rollingStats: timeInMilliseconds: 15000 circuitBreaker: # 10秒內出現3個以上請求(已臨近閥值),並且出錯率在50%以上,開啟斷路器.斷開服務,呼叫Fallback方法 requestVolumeThreshold: 3 sleepWindowInMilliseconds: 10000
3.2.5、接入監控
曲線:用來記錄2分鐘內流量的相對變化,我們可以通過它來觀察到流量的上升和下降趨勢。
叢集監控需要用到註冊中心
3.3、resilience4j
3.3.1、引入依賴
dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-bulkhead</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-ratelimiter</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-timelimiter</artifactId> <version>1.6.1</version> </dependency>
可以按需要引入:bulkhead,ratelimiter,timelimiter等
3.3.2、改造介面
@RequestMapping("/get") @ResponseBody //@TimeLimiter(name = "BulkheadA",fallbackMethod = "fallbackMethod") @CircuitBreaker(name = "BulkheadA",fallbackMethod = "fallbackMethod") @Bulkhead(name = "BulkheadA",fallbackMethod = "fallbackMethod") public JsonResult allInfos(HttpServletRequest request,@RequestParam Integer num){ log.info("param----->" + num); try { //Thread.sleep(num); if (num % 2 == 0) { log.info("num % 2 == 0"); throw new BaseException("something bad with 2",400); } if (num % 3 == 0) { log.info("num % 3 == 0"); throw new BaseException("something bad whitch 3",400); } if (num % 5 == 0) { log.info("num % 5 == 0"); throw new ProgramException("something bad whitch 5",400); } if (num % 7 == 0) { log.info("num % 7 == 0"); int res = 1 / 0; } return JsonResult.ok(); } catch (BufferUnderflowException e) { log.info("error"); return JsonResult.error("error"); } }
3.3.3、針對介面配置熔斷方法
/** * 需要引數一致,並且加上相應異常 * @param request * @param response * @param num * @param exception * @return */ public JsonResult fallbackMethod(HttpServletRequest request,BulkheadFullException exception) { return JsonResult.error("error 熔斷" + num ); }
3.3.4、配置規則
resilience4j.circuitbreaker: instances: backendA: registerHealthIndicator: true slidingWindowSize: 100 backendB: registerHealthIndicator: true slidingWindowSize: 10 permittedNumberOfCallsInHalfOpenState: 3 slidingWindowType: TIME_BASED minimumNumberOfCalls: 20 waitDurationInOpenState: 50s failureRateThreshold: 50 eventConsumerBufferSize: 10 recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate resilience4j.retry: instances: backendA: maxRetryAttempts: 3 waitDuration: 10s enableExponentialBackoff: true exponentialBackoffMultiplier: 2 retryExceptions: - org.springframework.web.client.HttpServerErrorException - java.io.IOException ignoreExceptions: - io.github.robwin.exception.BusinessException backendB: maxRetryAttempts: 3 waitDuration: 10s retryExceptions: - org.springframework.web.client.HttpServerErrorException - java.io.IOException ignoreExceptions: - io.github.robwin.exception.BusinessException 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: 0 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.3.5、配置監控
如grafana等
肆、關注點
- 是否需要過濾部分異常
- 是否需要全域性預設規則
- 可能需要引入其他中介軟體
- k8s流量控制
- 規則儲存和動態修改
- 接入改造代價
【後面的話】
個人建議的話,比較推薦sentinel,它提供了很多介面便於開發者自己拓展,同時我覺得他的規則動態更新也比較方便。最後是相關示例程式碼:單體應用示例程式碼
以上就是淺析Spring Boot單體應用熔斷技術的使用的詳細內容,更多關於Spring Boot單體應用熔斷技術的資料請關注我們其它相關文章!