Spring Cloud入门笔记3(CircuitBreaker)

场景:

各种微服务之间进行调用时,有可能会调用到一写故障的微服务,此时可以用CircuitBreaker进行断路等操作,保证系统正常运行

基础知识:

熔断(CircuitBreaker)(服务熔断和服务降级)

步骤一:导入依赖

<!--resilience4j-circuitbreaker-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- 由于断路保护等需要AOP实现,所以必须导入AOP包 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

步骤二:编写配置文件

按次数
# Resilience4j CircuitBreaker 按照次数:_BASEDCOUNT 的例子
#  6次访问中当执行方法的失败率达到50%时CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
#  等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
#  如还是异常CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。
#resilience4j:
#  circuitbreaker:
#    configs:
# 编译默认配置文件
#      default:
#        failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
#        slidingWindowType: COUNT_BASED # 滑动窗口的类型
#        slidingWindowSize: 6 #滑动窗⼝的⼤⼩配置COUNT_BASED表示6个请求,配置TIME_BASED表示6秒
#        minimumNumberOfCalls: 6 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。如果minimumNumberOfCalls为10,则必须最少记录10个样本,然后才能计算失败率。如果只记录了9次调用,即使所有9次调用都失败,断路器也不会开启。
#        automaticTransitionFromOpenToHalfOpenEnabled: true # 是否启用自动从开启状态过渡到半开状态,默认值为true。如果启用,CircuitBreaker将自动从开启状态过渡到半开状态,并允许一些请求通过以测试服务是否恢复正常
#        waitDurationInOpenState: 5s #从OPEN到HALF_OPEN状态需要等待的时间
#        permittedNumberOfCallsInHalfOpenState: 2 #半开状态允许的最大请求数,默认值为10。在半开状态下,CircuitBreaker将允许最多permittedNumberOfCallsInHalfOpenState个请求通过,如果其中有任何一个请求失败,CircuitBreaker将重新进入开启状态。
#        recordExceptions:
#          - java.lang.Exception
# 作用于consul上的服务
#    instances:
#      cloud-payment-service:
#        baseConfig: default

按时间

# Resilience4j CircuitBreaker 按照时间:TIME_BASED 的例子
#resilience4j:
#  timelimiter:
#    configs:
#      default:
#        timeout-duration: 10s #神坑的位置,timelimiter 默认限制远程1s,超于1s就超时异常,配置了降级,就走降级逻辑
#  circuitbreaker:
#    configs:
#      default:
#        failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
#        slowCallDurationThreshold: 2s #慢调用时间阈值,高于这个阈值的视为慢调用并增加慢调用比例。
#        slowCallRateThreshold: 30 #慢调用百分比峰值,断路器把调用时间⼤于slowCallDurationThreshold,视为慢调用,当慢调用比例高于阈值,断路器打开,并开启服务降级
#        slidingWindowType: TIME_BASED # 滑动窗口的类型
#        slidingWindowSize: 2 #滑动窗口的大小配置,配置TIME_BASED表示2秒
#        minimumNumberOfCalls: 2 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。
#        permittedNumberOfCallsInHalfOpenState: 2 #半开状态允许的最大请求数,默认值为10。
#        waitDurationInOpenState: 5s #从OPEN到HALF_OPEN状态需要等待的时间
#        recordExceptions:
#          - java.lang.Exception
#    instances:
#      cloud-payment-service:
#        baseConfig: default

步骤三:编写controller

被调用者
//=========Resilience4j bulkhead 的例子
@GetMapping(value = "/pay/bulkhead/{id}")
public String myBulkhead(@PathVariable("id") Integer id)
{
    if(id == -4) throw new RuntimeException("----bulkhead id 不能-4");

    if(id == 9999)
    {
        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
    }

    return "Hello, bulkhead! inputId:  "+id+" \t " + IdUtil.simpleUUID();
}
中间PayFeignApi
@GetMapping(value = "/pay/circuit/{id}")
public String myCircuit(@PathVariable("id") Integer id);


调用者
@RestController
public class OrderCircuitController {
    @Resource
    private PayFeignApi payFeignApi;

    @GetMapping(value = "/feign/pay/circuit/{id}")
     //添加该注解,name指定该类要掉用的微服务(与配置文件内的设置的服务名相同)
     //fallbackMethod指定,服务降级后的兜底处理方法
    @CircuitBreaker(name = "cloud-payment-service", fallbackMethod = "myCircuitFallback")
    public String myCircuitBreaker(@PathVariable("id") Integer id)
    {
        return payFeignApi.myCircuit(id);
    }
    //myCircuitFallback就是服务降级后的兜底处理方法
    public String myCircuitFallback(Integer id,Throwable t) {
        // 这里是容错处理逻辑,返回备用结果
        return "myCircuitFallback,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~";
    }

按次数总结:

滑动窗口长度为6,样本数为6,运行6次操作,3对3错,

达到最小样本数,触发断路器检查机制,发现错误率达到30%

触发开路熔断,进行服务降级,触发保底方法

5秒后,变为半开路状态,开始小心试探,

隔段时间,放2个过去,只要有一个失败,就变回开路

往复循环

按时间总结:

滑动窗口长度为2秒,样本数为2,请求超过两2秒为慢查询,

进行2次操作,一个5秒(慢查询),一个1秒(正常)

达到最小样本数,触发断路器检查机制,两个请求都成功,

但其中慢查询百分比超过30%

触发开路熔断,进行服务降级,触发保底方法

5秒后,变为半开路状态,开始小心试探,

隔段时间,放2个过去,只要有一个失败,就变回开路

往复循环

隔离(BulkHead)

步骤一:导入依赖

<!--resilience4j-bulkhead-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-bulkhead</artifactId>
</dependen
cy>

步骤二:编写配置文件

信号量

####resilience4j bulkhead 的例子
resilience4j:
  bulkhead:
    configs:

#编写默认配置文件
      default:
        maxConcurrentCalls: 2 
隔离允许并发线程执行的最大数量
                
maxWaitDuration: 1s 当达到并发调用数量时,新的线程的阻塞时间,我只愿意等待1秒,过时不候进舱壁兜底fallback
    
instances:

        #作用于服务
      cloud-payment-service:
        baseConfig: default
  timelimiter:
    configs:
      default:
        timeout-duration: 20s
#这个配置项定义了操作的超时时间。在这个例子中,超时时间被设置为 20s,意味着任何超过 20 秒的操作都会被 TimeLimiter 拦截,并抛出一个 TimeoutException

线程池

####resilience4j bulkhead -THREADPOOL的例子
#resilience4j:
#  timelimiter:
#    configs:
#      default:
#        timeout-duration: 10s #timelimiter默认限制远程1s,超过报错不好演示效果所以加上10秒
#  thread-pool-bulkhead:
#    configs:
#      default:
#        core-thread-pool-size: 1 #允许最大并发量
#        max-thread-pool-size: 1 #线程池就一个位
#        queue-capacity: 1 #只允许一个人排队

#    instances:
#      cloud-payment-service:
#        baseConfig: default
# spring.cloud.openfeign.circuitbreaker.group.enabled 请设置为false 新启线程和原来主线程脱离

步骤三:编写Controller

被调用者

//=========Resilience4j bulkhead 的例子
@GetMapping(value = "/pay/bulkhead/{id}")
public String myBulkhead(@PathVariable("id") Integer id)
{
    if(id == -4throw new RuntimeException("----bulkhead id 不能-4");

    if(id == 9999)
    {
        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
    }

    return "Hello, bulkhead! inputId:  "+id+\t " + IdUtil.simpleUUID();
}

中间PayFeignApi

/**
 * Resilience4j Bulkhead 
的例子
 
@param id
 
@return
 
*/

@GetMapping(value = "/pay/bulkhead/{id}")
public String myBulkhead(@PathVariable("id") Integer id);

调用者

/**
 * (船的)舱壁,隔离
 *
 * @param id
 * @return
 */
@GetMapping(value = "/feign/pay/bulkhead/{id}")
信号量
//@Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadFallback", //type = Bulkhead.Type.SEMAPHORE)
线程池
@Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadFallback", type = Bulkhead.Type.THREADPOOL)
public String myBulkhead(@PathVariable("id") Integer id) {
    return payFeignApi.myBulkhead(id);
}

public String myBulkheadFallback(Throwable t) {
    return "myBulkheadFallback,隔板超出最大数量限制,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~";
}

信号量总结:

就是抢车位,有位就进去,没位就等1秒,

1秒后,如果还是没位,直接触发降级

timeout-duration: 20s 防止僵尸车一直占着

线程池总结:

固定线程池舱壁(FixedThreadPoolBulkhead)

FixedThreadPoolBulkhead的功能与SemaphoreBulkhead一样也是用于限制并发执行的次数的,但是二者的实现原理存在差别而且表现效果也存在细微的差别。FixedThreadPoolBulkhead使用一个固定线程池和一个等待队列来实现舱壁。

当线程池中存在空闲时,则此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求。

当线程池中无空闲时时,接下来的请求将进入等待队列,

   若等待队列仍然无剩余空间时接下来的请求将直接被拒绝,

   在队列中的请求等待线程池出现空闲时,将进入线程池进行业务处理。

另外:ThreadPoolBulkhead只对CompletableFuture方法有效,所以我们必创建返回CompletableFuture类型的方法

限流(RateLimiter)

步骤一:导入依赖

<!--resilience4j-ratelimiter-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
</dependency>

步骤二:编写配置文件

####resilience4j ratelimiter 限流的例子
resilience4j:
  ratelimiter:
    configs:
      default:
        limitForPeriod#在一次刷新周期内,允许执行的最大请求数
        
limitRefreshPeriod: 1s 限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
        
timeout-duration: 1 线程等待权限的默认等待时间
    
instances:
        cloud-payment-service:
          baseConfig: default

步骤三:编写Controller

被调用者

//=========Resilience4j ratelimit 的例子
@GetMapping(value = "/pay/ratelimit/{id}")
public String myRatelimit(@PathVariable("id") Integer id)
{
    return "Hello, myRatelimit欢迎到来 inputId:  "+id+\t " + IdUtil.simpleUUID();
}

中间PayFeignApi

/**
 * Resilience4j Ratelimit 
的例子
 
@param id
 
@return
 
*/

@GetMapping(value = "/pay/ratelimit/{id}")
public String myRatelimit(@PathVariable("id") Integer id);

 调用者

@GetMapping(value = "/feign/pay/ratelimit/{id}")
@RateLimiter(name = "cloud-payment-service",fallbackMethod = "myRatelimitFallback")
public String myBulkhead(@PathVariable("id") Integer id)
{
    return payFeignApi.myRatelimit(id);
}
public String myRatelimitFallback(Integer id,Throwable t)
{
    return "你被限流了,禁止访问/(o)/~~";
}

 

### Spring Cloud 尚硅谷学习笔记概述 Spring Cloud 是一系列框架的有序集合,用于帮助开发者快速构建分布式系统中的常见模式。这些组件包括但不限于服务发现、配置管理、断路器、路由网关等。 #### 服务注册与发现:Eureka vs Nacos 在微服务体系中,服务之间的调用依赖于有效的服务注册与发现机制。Eureka 和 Nacos 都提供了这样的功能[^2]。然而,在实际项目选型上可能会因为两者特性不同而有所偏好: - **Eureka** 主要由 Netflix 开发并维护,作为早期的服务治理解决方案之一,具有较高的社区活跃度和成熟度。 - **Nacos**, 则是由阿里巴巴开源的一款集成了服务发现与配置管理的产品,其设计目标是为了简化云原生应用的开发过程[^3]。 对于希望采用国产化技术栈的企业来说,Nacos 可能会成为首选;而对于已经熟悉 Netflix 生态圈的技术团队而言,则可能继续沿用 Eureka。 #### API Gateway: Zuul vs Spring Cloud Gateway 当涉及到API网关的选择时,Zuul 和 Spring Cloud Gateway 成为了两个备选项。尽管它们都能满足基本需求,但在性能和技术演进方向上有显著差异[^1]: - **Zuul 1.x**: 使用的是传统的阻塞I/O模型以及Servlet容器来处理HTTP请求,这导致了较低的吞吐量和较差的整体表现。 - **Spring Cloud Gateway (SCG)** : 构建于现代响应式编程基础之上(Reactor),采用了异步非阻塞的方式来进行网络通信,从而实现了更高的并发能力和更低延迟。 因此,除非有特殊的历史遗留原因需要保留旧版本的 Zuul ,否则推荐使用 SCG 来替代前者。 #### 断路器 Hystrix 的核心概念 Hystrix 是用来实现熔断模式的一种工具库,旨在保护应用程序免受级联故障的影响。其中一个重要的参数就是 `circuitBreaker.requestVolumeThreshold` , 它定义了一个时间窗口内至少要有多少次失败才能触发断路行为[^4]。如果在这个时间段内的错误次数低于设定值,则即使存在异常也不会激活熔断逻辑。 ```yaml hystrix: command: default: circuitBreaker: requestVolumeThreshold: 20 # 默认情况下, 至少需要20个请求才会考虑开启熔断 ``` 通过合理调整此属性可以有效控制系统的稳定性和可用性水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值