溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù)

發(fā)布時(shí)間:2021-01-21 15:05:15 來(lái)源:億速云 閱讀:431 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

今天就跟大家聊聊有關(guān)如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

Sentinel

  • 阿里出品,Spring Cloud Alibaba限流組件,目前持續(xù)更新中

  • 自帶Dashboard,可以查看接口Qps等,并且可以動(dòng)態(tài)修改各種規(guī)則

  • 流量控制,直接限流、冷啟動(dòng)、排隊(duì)

  • 熔斷降級(jí),限制并發(fā)限制數(shù)和相應(yīng)時(shí)間

  • 系統(tǒng)負(fù)載保護(hù),提供系統(tǒng)級(jí)別防護(hù),限制總體CPU等

  • 主要核心:資源,規(guī)則(流量控制規(guī)則、熔斷降級(jí)規(guī)則、系統(tǒng)保護(hù)規(guī)則、來(lái)源訪(fǎng)問(wèn)控制規(guī)則 和 熱點(diǎn)參數(shù)規(guī)則。),和指標(biāo)

  • 文檔非常清晰和詳細(xì),中文

  • 支持動(dòng)態(tài)規(guī)則(推模式和拉模式)

Hystrix

  • Netflix出品,Spring Cloud Netflix限流組件,已經(jīng)停止新特性開(kāi)發(fā),只進(jìn)行bug修復(fù),最近更新為2018年,功能穩(wěn)定

  • 有簡(jiǎn)單的dashboard頁(yè)面

  • 以隔離和熔斷為主的容錯(cuò)機(jī)制,超時(shí)或被熔斷的調(diào)用將會(huì)快速失敗,并可以提供 fallback 機(jī)制的初代熔斷框架,異常統(tǒng)計(jì)基于滑動(dòng)窗口

resilience4j

  • 是一款輕量、簡(jiǎn)單,并且文檔非常清晰、豐富的熔斷工具。是Hystrix替代品,實(shí)現(xiàn)思路和Hystrix一致,目前持續(xù)更新中

  • 需要自己對(duì)micrometer、prometheus以及Dropwizard metrics進(jìn)行整合

  • CircuitBreaker 熔斷

  • Bulkhead 隔離

  • RateLimiter QPS限制

  • Retry 重試

  • TimeLimiter 超時(shí)限制

  • Cache 緩存

自己實(shí)現(xiàn)(基于Guava)

  • 基于Guava的令牌桶,可以輕松實(shí)現(xiàn)對(duì)QPS進(jìn)行限流

貳、技術(shù)對(duì)比

如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù)

叁、應(yīng)用改造

3.1、sentinel

3.1.1、引入依賴(lài)

<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 {
  //資源名稱(chēng)
  String value() default "";
 
  //流量方向
  EntryType entryType() default EntryType.OUT;
 
  //資源類(lèi)型
  int resourceType() default 0;
 
  //異常處理方法
  String blockHandler() default "";
 
  //異常處理類(lèi)
  Class<?>[] blockHandlerClass() default {};
 
  //熔斷方法
  String fallback() default "";
 
  //默認(rèn)熔斷方法
  String defaultFallback() default "";
 
  //熔斷類(lèi)
  Class<?>[] fallbackClass() default {};
 
  //統(tǒng)計(jì)異常
  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、針對(duì)接口配置熔斷方法或者限流方法

默認(rèn)過(guò)濾攔截所有Controller接口

/**
   * 限流,參數(shù)需要和方法保持一致
   * @param request
   * @param response
   * @param num
   * @return
   * @throws BlockException
   */
  public JsonResult errorReturn(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer num) throws BlockException {
    return JsonResult.error("error 限流" + num );
  }
 
  /**
   * 熔斷,參數(shù)需要和方法保持一直,并且需要添加BlockException異常
   * @param request
   * @param response
   * @param num
   * @param b
   * @return
   * @throws BlockException
   */
  public JsonResult errorReturn(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer num,BlockException b) throws BlockException {
    return JsonResult.error("error 熔斷" + num );
  }

注意也可以不配置限流或者熔斷方法。通過(guò)全局異常去捕獲UndeclaredThrowableException或者BlockException避免大量的開(kāi)發(fā)量

3.1.4、接入dashboard

spring:
 cloud:
  sentinel:
   transport:
    port: 8719
    dashboard: localhost:8080

如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù)

3.1.5、規(guī)則持久化和動(dòng)態(tài)更新

接入配置中心如:zookeeper等等,并對(duì)規(guī)則采用推模式

3.2、hystrix

3.2.1、引入依賴(lài)

<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, HttpServletResponse response, @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、針對(duì)接口配置熔斷方法

/**
 * 該方法是熔斷回調(diào)方法,參數(shù)需要和接口保持一致
 * @param request
 * @param response
 * @param num
 * @return
 */
public JsonResult fallbackMethod(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer num) {
  response.setStatus(500);
  log.info("發(fā)生了熔斷?。?quot;);
  return JsonResult.error("熔斷");
}

3.2.4、配置默認(rèn)策略

hystrix:
 command:
  default:
   execution:
    isolation:
     strategy: THREAD
     thread:
      # 線(xiàn)程超時(shí)15秒,調(diào)用Fallback方法
      timeoutInMilliseconds: 15000
   metrics:
    rollingStats:
     timeInMilliseconds: 15000
   circuitBreaker:
    # 10秒內(nèi)出現(xiàn)3個(gè)以上請(qǐng)求(已臨近閥值),并且出錯(cuò)率在50%以上,開(kāi)啟斷路器.斷開(kāi)服務(wù),調(diào)用Fallback方法
    requestVolumeThreshold: 3
    sleepWindowInMilliseconds: 10000

3.2.5、接入監(jiān)控

如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù)

如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù)

曲線(xiàn):用來(lái)記錄2分鐘內(nèi)流量的相對(duì)變化,我們可以通過(guò)它來(lái)觀察到流量的上升和下降趨勢(shì)。

集群監(jiān)控需要用到注冊(cè)中心

3.3、resilience4j

3.3.1、引入依賴(lài)

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, HttpServletResponse response, @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、針對(duì)接口配置熔斷方法

/**
 * 需要參數(shù)一致,并且加上相應(yīng)異常
 * @param request
 * @param response
 * @param num
 * @param exception
 * @return
 */
public JsonResult fallbackMethod(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer num, BulkheadFullException exception) {
  return JsonResult.error("error 熔斷" + num );
}

3.3.4、配置規(guī)則

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

配置的規(guī)則可以被代碼覆蓋

3.3.5、配置監(jiān)控

如grafana等

肆、關(guān)注點(diǎn)

  • 是否需要過(guò)濾部分異常

  • 是否需要全局默認(rèn)規(guī)則

  • 可能需要引入其他中間件

  • k8s流量控制

  • 規(guī)則存儲(chǔ)和動(dòng)態(tài)修改

  • 接入改造代價(jià)

看完上述內(nèi)容,你們對(duì)如何正確的使用Spring Boot單體應(yīng)用熔斷技術(shù)有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI