SpringCloud搭建微服务之Circuit Breaker断路器

这篇具有很好参考价值的文章主要介绍了SpringCloud搭建微服务之Circuit Breaker断路器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 概述

Circuit breaker是一套规范和接口,落地实现是Resilience4j,Resilience4j是一个专为函数式编程设计的轻量级容错库,Resilience4j提供高阶函数(装饰器),以通过断路器、速率限制器、重试或隔板增强任何功能接口、lambda表达式或方法引用。可以在任何函数式接口、lambda表达式或方法引用上堆叠多个装饰器,优点是可以选择需要的装饰器。
Resilience4j提供以下几个核心模块:

  • resilience4j-circuitbreaker:熔断
  • resilience4j-ratelimiter:速率限制
  • resilience4j-bulkhead:舱壁/隔离
  • resilience4j-retry:自动重试(同步和异步)
  • resilience4j-timelimiter:超时处理
  • resilience4j-cache:结果缓存

CircuitBreaker的目的是保护分布式系统免受故障和异常,提高系统的可用性和健壮性。当一个组件或服务出现故障时,CircuitBreaker会迅速切换到开放OPEN状态(保险丝跳闸断电),阻止请求发送到该组件或服务从而避免更多的请求发送到该组件或服务。这可以减少对该组件或服务的负载,防止该组件或服务进一步崩溃,并使整个系统能够继续正常运行。同时,其还可以提高系统的可用性和健壮性,因为其可以在分布式系统的各个组件之间自动切换,从而避免单点故障的问题。更多详情可以参阅官网和github中文手册
示意图如下:
spring cloud circuit breaker,SpringCloud,spring cloud,微服务,spring,限流

本文主要介绍resilience4j提供的熔断、隔离和限速

2. 服务熔断

2.1. 三种状态

断路器有三个普通状态:关闭(CLOSED)开启(OPEN)半开(HALF_OPEN),还有两个特殊状态:禁用(DISABLED)强制开启(FORCED_OPEN)

当熔断器关闭时,所有的请求都会通过熔断器

  • 如果失败率超过设定的阈值,熔断器就会从关闭状态转换为打开状态,这时所有的请求都会被拒绝
  • 当经过一段时间后,熔断器会从打开状态转换为半开状态,这时仅有一定数量的请求会被放入,并重新计算失败率
  • 如果失败率超过阈值,则变为打开状态,如果失败率低于阈值,则变为关闭状态

断路器使用滑动窗口来存储和统计调用的结果,可以选择基于调用数量的滑动窗口或基于时间的滑动窗口

  • 基于访问次数的滑动窗口统计了最近N次调用的返回结果,基于时间的滑动窗口统计了最近N秒调用的返回结果

熔断器另外两种特殊状态DISABLED(始终允许访问)和FORCED_OPEN(始终拒绝访问)

  • 这两个状态不会生成熔断器事件(除状态转换外),并且不会记录事件的成功或失败
  • 退出这两个状态的唯一方法是触发状态转换或者重置熔断器

2.2. 微服务集成circuitbreaker

2.2.1. 引入核心依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.2.2. 编写application.yml

熔断器分为基于次数和基于时间两种方式
基于次数配置如下:

resilience4j:
  circuitbreaker:
    configs:
      default:
        failure-rate-threshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分比CircuitBreaker变为OPEN状态
        sliding-window-type: COUNT_BASED #滑动窗口的类型
        sliding-window-size: 6 #滑动窗口的大小配置COUNT_BASED表示6个请求,配置TIME_BASED表示6秒
        minimum-number-of-calls: 6 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期),如果minimum-number-of-calls为10,则必须最少记录10个样本,然后才能计算失败率,如果只记录了9次调用,即使所有9次调用都失败,断路器也不会开启
        automatic-transition-from-open-to-half-open-enabled: true #是否启用自动从开启状态过渡到半开状态,默认值为true,如果启用,circuitbreaker将自动从开启状态过渡到半开状态,并允许一些请求通过以测试服务是否恢复正常
        wait-duration-in-open-state: 5s #从OPEN到HALF_OPEN状态需要等待的时间
        permitted-number-of-calls-in-half-open-state: 2 #半开状态允许的最大请求数,默认值为10,在半开状态下,circuitbreaker将允许最多permitted-number-of-calls-in-half-open-state个请求通过,如果其中有任何一个请求失败,circuitbreaker将重新进入开启状态
        record-exceptions:
          - java.lang.Exception
    instances:
      spring-cloud-provider:
        base-config: default

基于时间配置如下:

resilience4j:
  timelimiter:
    configs:
      default:
        timeout-duration: 10s #默认限制远程1s,超于1s就超时异常,配置了降级,就走降级逻辑
  circuitbreaker:
    configs:
      default:
        failure-rate-threshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分比CircuitBreaker变为OPEN状态
        slow-call-duration-threshold: 2s #慢调用时间阈值,高于这个阈值的视为慢调用并增加慢调用比例
        slow-call-rate-threshold: 30 #慢调用百分比峰值,断路器把调用时间大于slow-call-duration-threshold,视为慢调用,当慢调用比例高于阈值,断路器打开,并开启服务降级
        sliding-window-type: TIME_BASED #滑动窗口的类型
        sliding-window-size: 2 #滑动窗口的大小配置,配置TIME_BASED表示2秒
        minimum-number-of-calls: 2 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)
        wait-duration-in-open-state: 5s #从OPEN到HALF_OPEN状态需要等待的时间
        permitted-number-of-calls-in-half-open-state: 2 #半开状态允许的最大请求数,默认值为10
        record-exceptions:
          - java.lang.Exception
    instances:
      spring-cloud-provider:
        base-config: default

同时需要开启feign的circuit breaker

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true #开启circuitbreaker和分组
        group:
          enabled: true #没开分组永远不用分组的配置,精确优先、分组次之(开了分组)、默认最后

2.2.3. 编写Controller接口类

@GetMapping(value = "/getCircuit/{id}")
@CircuitBreaker(name = "spring-cloud-circuit", fallbackMethod = "circuitFallBack")
public ResponseEntity<String> getCircuit(@PathVariable(value = "id") Integer id) {
    return providerFeignClient.getCircuitInfo(id);
}

public ResponseEntity<String> circuitFallBack(Integer id, Throwable t) {
    return ResponseEntity.ok("This is circuitFallBack, 系统错误,请稍后再试");
}

3. 服务隔离

3.1. 两种实现方式

主要用于依赖隔离&负载保护,即用来限制对于下游服务的最大并发数量的限制。Resilience4j提供了两种隔离的实现方式,可以限制并发执行的数量

  • SemaphoreBulkhead使用了信号量
  • FixedThreadPoolBulkhead使用了有界队列和固定大小线程池

更多详情可以参阅github中文手册

3.1.1. 信号量舱壁原理

当信号量有空闲时,进入系统的请求会直接获取信号量并开始业务处理。当信号量全被占用时,接下来的请求将会进入阻塞状态,SemaphoreBulkhead提供了一个阻塞计时器,如果阻塞状态的请求在阻塞计时内无法获取到信号量则会拒绝这些请求。若请求在阻塞计时内获取到了信号量,那将直接获取信号量并执行相应的业务处理

3.1.2. 固定线程池舱壁原理

FixedThreadPoolBulkhead使用一个固定线程池和一个等待队列来实现舱壁。当线程池中存在空闲时,则此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求。当线程池中无空闲时,接下来的请求将进入等待队列,若等待队列仍然无剩余空间时,接下来的请求将直接被拒绝。在队列中的请求等待线程池出现空闲时,将进入线程池进行业务处理。
另外,ThreadPoolBulkhead只对CompletableFuture方法有效,所以需要创建返回CompletableFuture类型的方法

3.2. 微服务集成bulkhead

3.2.1. 引入核心依赖

<!--配置resilience4j依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--bulkhead依赖-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-bulkhead</artifactId>
</dependency>

3.2.2. 编写application.yml

信号量方式配置

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true #开启circuitbreaker和分组
        group:
          enabled: true #没开分组永远不用分组的配置,精确优先、分组次之(开了分组)、默认最后
resilience4j:
  bulkhead:
    configs:
      default:
        max-concurrent-calls: 2 #隔离允许并发线程执行的最大数量
        max-wait-duration: 1s #当达到并发调用数量时,新的线程的阻塞时间,只愿意等待1秒,过时不候进舱壁兜底fallback
    instances:
      spring-cloud-provider:
        base-config: default
  timelimiter:
    configs:
      default:
        timeout-duration: 20s

线程池方式配置

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true #开启circuitbreaker和分组
        group:
          enabled: false #没开分组永远不用分组的配置,精确优先、分组次之(开了分组)、默认最后;新启线程和原来主线程脱离
resilience4j:
  timelimiter:
    configs:
      default:
        timeout-duration: 10s #默认限制远程1秒
  thread-pool-bulkhead:
    configs:
      default:
        core-thread-pool-size: 4
        max-thread-pool-size: 8
        queue-capacity: 10
    instances:
      spring-cloud-provider:
        base-config: default

3.2.3. 编写Controller接口类

@GetMapping(value = "/getBulkheadInfo/{id}")
@Bulkhead(name = "spring-cloud-provider", fallbackMethod = "bulkheadFallback", type = Bulkhead.Type.SEMAPHORE)
public ResponseEntity<String> getBulkheadInfo(@PathVariable(value = "id") Integer id) {
    return providerFeignClient.getBulkheadInfo(id);
}
public ResponseEntity<String> bulkheadFallback(Integer id, Throwable t) {
    return ResponseEntity.ok("bulkheadFallback, 隔板超出最大数量限制,系统繁忙,请稍后再试");
}

@GetMapping(value = "/getBulkheadPoolInfo/{id}")
@Bulkhead(name = "spring-cloud-provider", fallbackMethod = "bulkheadPoolFallback", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> getBulkheadPoolInfo(@PathVariable(value = "id") Integer id) {
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return CompletableFuture.supplyAsync(() -> providerFeignClient.getBulkheadInfo(id).getBody());
}
public CompletableFuture<String> bulkheadPoolFallback(Integer id, Throwable t) {
    return CompletableFuture.supplyAsync(() -> "bulkheadPoolFallback, 线程池隔板超出最大数量限制,系统繁忙,请稍后再试");
}

4. 服务限流

就是限制最大访问流量,系统能提供的最大并发是有限的,同时进入的请求数又太多,就需要限流

4.1. 四种限流算法

漏斗算法:一个固定容量的漏桶,按照设定常量固定速率流出,不管源头流量多大,设定了均速流出,如果流入量超出了桶的容量,则流入的量将会溢出(被丢弃),而漏桶容量是不变的。其存在的缺点是,有两个变量,一个是桶的大小,支持流量突发增多时可以存多少请求,另一个是桶漏洞的大小。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在的资源冲突(没有发生拥塞),漏桶算法也不能使流量突发到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。
令牌桶算法:以固定的速率向一个令牌桶中添加令牌,而当需要发送数据时,需要从桶中取出一个令牌,只有当桶中又令牌时才能发送数据,且取出的令牌数量与发送的数据量成正比。如果桶中没有令牌,那么数据将被限制等待,直到有足够的令牌可用。此种算法是Spring Cloud默认算法
滚动时间窗口算法:允许固定数量的请求进入,超过数量就拒绝或排队,等下一个时间段进入,由于是在一个时间间隔内进行限制,如果用户在上个时间间隔结束前请求(但没有超过限制),同时在当前时间间隔刚开始请求(同样没超过限制),在各自的时间间隔内,这些请求都是正常的。其缺点是间隔临界的一段时间内的请求就会超过系统限制,可能导致系统被压垮。由于计数器算法存在时间临界点缺陷,因此在时间临界点左右的极短时间段内容易遭到攻击
滑动时间窗口算法:时间窗口是滑动的,其一需要定义窗口的大小,其二需要定义在窗口中滑动的大小。滑动大小不能超过窗口大小。滑动窗口算法是把固定时间片进行划分并且随着时间移动,移动方式为开始时间点变为时间列表中的第二哥时间点,结束时间点增加一个时间点,不断重复,通过这种方式可以巧妙的避开计数器的临界点的问题。文章来源地址https://www.toymoban.com/news/detail-860219.html

4.2. 微服务集成ratelimiter

4.2.1. 引入核心依赖

<!--配置resilience4j依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--ratelimiter依赖-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
</dependency>

4.2.2. 编写application.yml

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true #开启circuitbreaker和分组
        group:
          enabled: true #没开分组永远不用分组的配置,精确优先、分组次之(开了分组)、默认最后
resilience4j:
  ratelimiter:
    configs:
      default:
        limit-for-period: 2 #在一次刷新周期内,允许执行的最大请求数
        limit-refresh-period: 1s #限流器每隔limit-for-period刷新一次,将允许处理的最大请求数量重置为limit-for-period
        timeout-duration: 1 #线程等待权限的默认等待时间
    instances:
      spring-cloud-provider:
        base-config: default

4.2.3. 编写Controller接口类

@GetMapping(value = "/getRateLimiterInfo/{id}")
@RateLimiter(name = "spring-cloud-provider", fallbackMethod = "rateLimiterFallback")
public ResponseEntity<String> getRateLimiterInfo(@PathVariable(value = "id") Integer id) {
    return ResponseEntity.ok(providerFeignClient.getRatelimitInfo(id).getBody());
}

public ResponseEntity<String> rateLimiterFallback(Integer id, Throwable t) {
    return ResponseEntity.ok("rateLimiterFallback, 被限流了,禁止访问");
}

到了这里,关于SpringCloud搭建微服务之Circuit Breaker断路器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud的断路器模式是什么?如何使用断路器?Spring Cloud的配置管理是怎样实现的?

    Spring Cloud的断路器模式是一种应对微服务架构中潜在故障的解决方案。在微服务架构中,不同的服务相互依赖,当某个服务出现故障或响应缓慢时,可能会导致级联故障,影响整个系统的可用性。 断路器模式通过在服务调用链路上插入断路器,在服务出现故障时,可以快速失

    2024年02月15日
    浏览(41)
  • es 报错 Data too large 触发断路器

    报错原因是 es 在 full GC 之前触发了默认的断路器,导致报错 [parent] Data too large ,相似的报错内容如下: 查看当前 es 节点的 jvm 内存使用情况(ip和端口要换成自己的 es 节点) heap.current 当前使用的内存 heap.percent 内存使用量百分比 heap.max 内存最大值 如果本机内存足够,并且

    2024年01月18日
    浏览(60)
  • Spring Cloud Feign实战来袭:工程中配置断路器Hystrix报错NoClassDefFoundError:HystrixCommandAspect解决方案

    在Spring Cloud Feign工程中配置断路器Hystrix的时候,pom.xml文件已经加入Hystrix相关的jar: Application.java: 可以看出来是找不到HystrixCommandAspec.java这个类,于是在github上找到这个源文件: https://github.com/dmgcodevil/Hystrix/blob/958ec5d7b4bb967be077a4c2bbcdc71e7a7f5248/hystrix-contrib/hystrix-javanica/src/mai

    2024年02月16日
    浏览(46)
  • Spring Boot - 利用Resilience4j-Circuitbreaker实现断路器模式_防止级联故障

    Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级 Resilience4J 是一个针对 Java 8 应用程序的轻量级容错和弹性库。它设计用于在分布式系统中的服务之间提供弹性和容错性。Resilience4J 的名字来源于它提供的核心功能,即让系统(服务)能够“弹性”(resilient)地应对各

    2024年01月19日
    浏览(97)
  • SpringCloud微服务项目快速搭建(SpringCloud Alibaba)

            Spring Cloud Alibaba 是 Spring Cloud 和 Alibaba 面向微服务架构的一站式解决方案,为 Spring Cloud 生态中的各个组件提供了与 Alibaba 中间件的衔接、更方便、更易用的快速开发微服务的能力和支持 Nacos:服务注册和发现、配置中心,提供服务注册和发现、分布式配置等能力

    2024年02月10日
    浏览(41)
  • SpringCloud_微服务基础day1(走进微服务,认识springcloud,微服务(图书管理)项目搭建(一))

    官方网站:柏码 - 让每一行代码都闪耀智慧的光芒! (itbaima.net) 注意: 此阶段学习推荐的电脑配置,至少配备4核心CPU(主频3.0Ghz以上)+16GB内存,否则卡到你怀疑人生。 前面我们讲解了SpringBoot框架,通过使用SpringBoot框架,我们的项目开发速度可以说是得到了质的提升。同时

    2024年02月07日
    浏览(50)
  • 【SpringCloud Alibaba】(二)微服务环境搭建

    整个项目主要分为 用户微服务、商品微服务和订单微服务 ,整个过程模拟的是用户下单扣减库存的操作。这里,为了简化整个流程,将商品的库存信息保存到了商品数据表,同时,使用商品微服务来扣减库存。小伙伴们在实现时,也可以将商品库存信息单独开发一个微服务

    2024年02月15日
    浏览(40)
  • SpringCloud搭建Eureka服务注册中心(六)

    前面说过eureka是c/s模式的  server服务端就是服务注册中心,其他的都是client客户端,服务端用来管理所有服务,客户端通过注册中心,来调用具体的服务; 我们先来搭建下服务端,也就是服务注册中心; project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSche

    2024年02月10日
    浏览(60)
  • 【SpringCloud】Eureka原理分析、搭建Eureka服务、服务注册、服务发现

    🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 Redis 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 当有两个服务,第一个服务需要远程调用第二个服务,采用的方式是发起一次HTTP请求,在之前的代码中是将服务提供者的ip和端口号硬编码到

    2024年02月07日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包