Resilience4J

Spring Cloud Circuit Breaker

  1. 官网:https://spring.io/projects/spring-cloud-circuitbreaker#overview
  2. CircuitBreaker的目的是保护分布式系统免受故障和异常,提高系统的可用性和健壮性。
  3. 当一个组件或服务出现故障时,CircuitBreaker会迅速切换到开放OPEN状态(保险丝跳闸断电),阻止请求发送到该组件或服务,从而避免更多的请求发送到该组件或服务。这可以减少对该组件或服务的负载,防止该组件或服务进一步崩溃,并使整个系统能够继续正常运行。同时,CircuitBreaker还可以提高系统的可用性和健壮性,因为它可以在分布式系统的各个组件之间自动切换,从而避免单点故障的问题。
  4. Circuit Breaker只是一套规范和接口,落地实现者是Resilience4J。

Resilience4J概述

  1. 官网:https://resilience4j.readme.io/docs/circuitbreaker
  2. Github:https://github.com/resilience4j/resilience4j#1-introduction
  3. 中文手册:https://github.com/lmhmhl/Resilience4j-Guides-Chinese/blob/main/index.md
  4. Resilience4j是一个轻量级容错框架,设计灵感来源于 Netflix 的 Hystrix 框架,为函数式编程所设计。
  5. Resilience4j 提供了一组高阶函数(装饰器),包括:断路器,限流器,重试,隔离,可以对任何的函数式接口,lambda表达式,或方法的引用进行增强,并且这些装饰器可以进行叠加。这样做的好处是,你可以根据需要选择特定的装饰器进行组合。

服务熔断和降级

断路器3大状态

断路器通过有限状态机实现,有三个普通状态:关闭、开启、半开,还有两个特殊状态:禁用、强制开启。

img

断路器3大状态之间的转换

img

断路器开启或者关闭的条件

  1. 当满足一定的峰值和失败率达到一定条件后,断路器将会进入OPEN状态(保险丝跳闸),服务熔断。当OPEN的时候,所有请求都不会调用主业务逻辑方法,而是直接走fallbackmetnod兜底方法,进行服务降级。
  2. 一段时间之后,断路器会从OPEN进入到HALF_OPEN半开状态,会放几个请求过去探探链路是否通?如成功,断路器会关闭CLOSE(类似保险丝闭合,恢复可用);如失败,继续开启。重复上述。

断路器配置参数

  1. 官方文档:https://resilience4j.readme.io/docs/circuitbreaker#create-and-configure-a-circuitbreaker
  2. 中文手册:https://github.com/lmhmhl/Resilience4j-Guides-Chinese/blob/main/core-modules/CircuitBreaker.md
  3. 默认CircuitBreaker.java配置类:https://github.com/resilience4j/resilience4j/blob/master/resilience4j-circuitbreaker/src/main/java/io/github/resilience4j/circuitbreaker/CircuitBreakerConfig.java
failure-rate-threshold以百分比配置失败率峰值
sliding-window-type断路器的滑动窗口类型 可以基于“次数”(COUNT_BASED)或者“时间”(TIME_BASED)进行熔断,默认是COUNT_BASED。
sliding-window-size若COUNT_BASED,则10次调用中有50%失败(即5次)打开熔断断路器;若为TIME_BASED,则此时还有额外的两个设置属性,含义为:在N秒内(sliding-window-size)100%(slow-call-rate-threshold)的请求超过N秒(slow-call-duration-threshold)打开断路器。
slowCallRateThreshold以百分比的方式配置,断路器把调用时间大于slowCallDurationThreshold的调用视为慢调用,当慢调用比例大于等于峰值时,断路器开启,并进入服务降级。
slowCallDurationThreshold配置调用时间的峰值,高于该峰值的视为慢调用。
permitted-number-of-calls-in-half-open-state允许断路器在HALF_OPEN状态下时进行N次调用,如果故障或慢速调用仍然高于阈值,断路器再次进入打开状态。
minimum-number-of-calls在每个滑动窗口期样本数,配置断路器计算错误率或者慢调用率的最小调用数。比如设置为5意味着,在计算故障率之前,必须至少调用5次。如果只记录了4次,即使4次都失败了,断路器也不会进入到打开状态。
wait-duration-in-open-state从OPEN到HALF_OPEN状态需要等待的时间

案例演示

基于数量的滑动窗口案例演示

  1. 6次访问中当执行方法的失败率达到50%时,CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
  2. 等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
  3. 如还是异常,CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。
增加PayCircuitController

修改8001支付模块,增加API接口

package com.sun.cloud.controller;
 
import cn.hutool.core.util.IdUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.concurrent.TimeUnit;
 
@RestController
public class PayCircuitController {
    // Resilience4j CircuitBreaker 的例子
    @GetMapping(value = "/pay/circuit/{id}")
    public String myCircuit(@PathVariable("id") Integer id) {
        if (id < 0) throw new RuntimeException("----circuit id 不能负数");
        if (id == 9999) {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return "Hello, circuit! inputId:  " + id + " \t " + IdUtil.simpleUUID();
    }
}
修改PayFeignApi接口

⚠️ 注意:修改后,cloud-api-commons模块重新install

package com.sun.cloud.apis;
 
import com.sun.cloud.entities.PayDTO;
import com.sun.cloud.resp.ResultData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
 
@FeignClient(value = "cloud-payment-service")
public interface PayFeignApi {
    /**
     * 新增一条支付相关流水记录
     * @param payDTO 流水记录的数据传输对象
     * @return ResultData
     */
    @PostMapping("/pay/add")
    ResultData addPay(@RequestBody PayDTO payDTO);
 
    /**
     * 按照主键记录查询支付流水信息
     * @param id 支付流水ID
     * @return ResultData
     */
    @GetMapping("/pay/get/{id}")
    ResultData getPayInfo(@PathVariable("id") Integer id);
 
    /**
     * openfeign天然支持负载均衡演示
     * @return String
     */
    @GetMapping(value = "/consul/info")
    String getInfoByConsul();
 
    /**
     * Resilience4j CircuitBreaker 的例子
     * @param id 支付流水ID
     * @return String
     */
    @GetMapping(value = "/pay/circuit/{id}")
    String myCircuit(@PathVariable("id") Integer id);
}
配置断路器

cloud-consumer-feign-order80进行以下操作

  1. 添加依赖
<!--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>
  1. yaml文件配置断路器
spring:
  cloud:
    openfeign:
      # 开启circuitbreaker和分组激活
      circuitbreaker:
        enabled: true
        # 没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
        group:
          enabled: true
 
#  Resilience4j CircuitBreaker 按照次数:COUNT_BASED 的例子
#  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
    instances:
      cloud-payment-service:
        baseConfig: default
增加OrderCircuitController进行测试

修改cloud-consumer-feign-order80模块,添加测试的接口

package com.sun.cloud.controller;
 
import com.sun.cloud.apis.PayFeignApi;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class OrderCircuitController {
    @Resource
    private PayFeignApi payFeignApi;
 
    @GetMapping(value = "/feign/pay/circuit/{id}")
    @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ㄒ)/~~";
    }
}
测试

50%错误后触发熔断并给出服务降级,告知调用者服务不可用。此时就算是输入正确的访问地址也无法调用服务。它还在断路中(OPEN状态),一会儿过渡到半开并继续正确地址访问,慢慢切换回CLOSE状态,可以正常访问了,链路恢复。

基于时间的滑动窗口案例演示

  1. 基于时间的滑动窗口是通过有N个桶的环形数组实现。
  2. 如果滑动窗口的大小为10秒,这个环形数组总是有10个桶,每个桶统计了在这一秒发生的所有调用的结果(部分统计结果),数组中的第一个桶存储了当前这一秒内的所有调用的结果,其他的桶存储了之前每秒调用的结果。
  3. 滑动窗口不会单独存储所有的调用结果,而是对每个桶内的统计结果和总的统计值进行增量的更新,当新的调用结果被记录时,总的统计值会进行增量更新。
  4. 检索快照(总的统计值)的时间复杂度为O(1),因为快照已经预先统计好了,并且和滑动窗口大小无关。
  5. 关于此方法实现的空间需求(内存消耗)约等于0(n)。由于每次调用结果(元组)不会被单独存储,只是对N个桶进行单独统计和一次总分的统计。
  6. 每个桶在进行部分统计时存在三个整型,为了计算:失败调用数,慢调用数,总调用数。还有一个long类型变量,存储所有调用的响应时间。
配置断路器
spring:
  cloud:
    openfeign:
      # 开启circuitbreaker和分组激活
      circuitbreaker:
        enabled: true
        # 没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
        group:
          enabled: true
 
# 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
测试

接口的调用时间超过2s视为慢调用,50%错误后触发熔断并给出服务降级,告知调用者服务不可用。此时就算是输入正确的访问地址也无法调用服务。它还在断路中(OPEN状态),一会儿过渡到半开并继续正确地址访问,慢慢切换回CLOSE状态,可以正常访问了,链路恢复。

隔离(BulkHead)

  1. 官网说明:https://resilience4j.readme.io/docs/bulkhead
  2. 中文手册:https://github.com/lmhmhl/Resilience4j-Guides-Chinese/blob/main/core-modules/bulkhead.md
  3. 作用:依赖隔离、负载保护,用来限制对于下游服务的最大并发数量的限制。
  4. Resilience4j提供了如下两种隔离的实现方式,可以限制并发执行的数量。
    • SemaphoreBulkhead(信号量舱壁)
    • FixedThreadPoolBulkhead(固定线程池舱壁)

SemaphoreBulkhead

信号量舱壁(SemaphoreBulkhead)原理:

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

在支付模块8001,新增请求方法,用于测试

@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接口

修改cloud-api-commons模块,增加API方法

/**
 * Resilience4j Bulkhead 的例子
 * @param id 支付流水ID
 * @return String
 */
@GetMapping(value = "/pay/bulkhead/{id}")
String myBulkhead(@PathVariable("id") Integer id);
修改订单模块

修改cloud-consumer-feign-order80

  1. 添加依赖
<!--resilience4j-bulkhead-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-bulkhead</artifactId>
</dependency>
  1. 修改yaml文件
resilience4j:
  bulkhead:
    configs:
      default:
        maxConcurrentCalls: 2 # 隔离允许并发线程执行的最大数量
        maxWaitDuration: 1s # 当达到并发调用数量时,新的线程的阻塞时间,我只愿意等待1秒,过时不候进舱壁兜底fallback
    instances:
      cloud-payment-service:
        baseConfig: default
 
  timelimiter:
    configs:
      default:
        timeout-duration: 20s
  1. 编写业务类

创建OrderCircuitController,并设置舱壁 / 隔离

/**
 * (船的)舱壁,隔离
 * @param id 支付流水ID
 * @return 响应结果
 */
@GetMapping(value = "/feign/pay/bulkhead/{id}")
@Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadFallback", type = Bulkhead.Type.SEMAPHORE)
public String myBulkhead(@PathVariable("id") Integer id) {
    return payFeignApi.myBulkhead(id);
}
 
public String myBulkheadFallback(Throwable t) {
    return "myBulkheadFallback,隔板超出最大数量限制,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~";
}

FixedThreadPoolBulkhead

  1. 固定线程池舱壁(FixedThreadPoolBulkhead)的功能与SemaphoreBulkhead一样也是用于限制并发执行的次数的,但是二者的实现原理存在差别而且表现效果也存在细微的差别。
  2. FixedThreadPoolBulkhead使用一个固定线程池和一个等待队列来实现舱壁。
  3. 当线程池中存在空闲时,则此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求。
  4. 当线程池中无空闲时时,接下来的请求将进入等待队列,若等待队列仍然无剩余空间时接下来的请求将直接被拒绝。在队列中的请求等待线程池出现空闲时,将进入线程池进行业务处理。
  5. 另外:ThreadPoolBulkhead只对CompletableFuture方法有效,所以我们必创建返回CompletableFuture类型的方法。
修改订单模块
  1. 添加依赖
<!--resilience4j-bulkhead-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-bulkhead</artifactId>
</dependency>
  1. 配置yaml文件
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
  1. 修改controller
/**
 * (船的)舱壁,隔离,THREADPOOL
 *
 * @param id 支付流水ID
 * @return 响应结果
 */
@GetMapping(value = "/feign/pay/bulkhead/{id}")
@Bulkhead(name = "cloud-payment-service", fallbackMethod = "myBulkheadPoolFallback", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> myBulkheadTHREADPOOL(@PathVariable("id") Integer id) {
    System.out.println(Thread.currentThread().getName() + "\t" + "enter the method!!!");
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "\t" + "exist the method!!!");
 
    return CompletableFuture.supplyAsync(() -> payFeignApi.myBulkhead(id) + "\t" + " Bulkhead.Type.THREADPOOL");
}
 
public CompletableFuture<String> myBulkheadPoolFallback(Integer id, Throwable t) {
    return CompletableFuture.supplyAsync(() -> "Bulkhead.Type.THREADPOOL,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~");
}

限流(RateLimiter)

  1. 官网:https://resilience4j.readme.io/docs/ratelimiter
  2. 中文手册:https://github.com/lmhmhl/Resilience4j-Guides-Chinese/blob/main/core-modules/ratelimiter.md
  3. 限流就是限制最大访问流量。系统能提供的最大并发是有限的,同时来的请求又太多,就需要限流。 比如商城秒杀业务,瞬时大量请求涌入,服务器忙不过就只好排队限流了,和去景点排队买票和去医院办理业务排队等号道理相同。
  4. 所谓限流,就是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速,以保护应用系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。

常见限流算法

漏斗算法(Leaky Bucket)

  • 一个固定容量的漏桶,按照设定常量固定速率流出水滴,类似医院打吊针,不管你源头流量多大,我设定匀速流出。
  • 如果流入水滴超出了桶的容量,则流入的水滴将会溢出了(被丢弃),而漏桶容量是不变的。
image.png
  • 缺点

这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。

image.png

令牌桶算法(Token Bucket)

SpringCloud默认使用该算法

image.png

滚动时间窗(tumbling time window)

允许固定数量的请求进入(比如1秒取4个数据相加,超过25值就over)超过数量就拒绝或者排队,等下一个时间段进入。

由于是在一个时间间隔内进行限制,如果用户在上个时间间隔结束前请求(但没有超过限制),同时在当前时间间隔刚开始请求(同样没超过限制),在各自的时间间隔内,这些请求都是正常的。下图统计了3次,but…

image.png

缺点:间隔临界的一段时间内的请求就会超过系统限制,可能导致系统被压垮。由于计数器算法存在时间临界点缺陷,因此在时间临界点左右的极短时间段内容易遭到攻击。

假如设定1分钟最多可以请求100次某个接口,如12:00:00-12:00:59时间段内没有数据请求但12:00:59-12:01:00时间段内突然并发100次请求,紧接着瞬间跨入下一个计数周期计数器清零;在12:01:00-12:01:01内又有100次请求。那么也就是说在时间临界点左右可能同时有2倍的峰值进行请求,从而造成后台处理请求加倍过载的bug,导致系统运营能力不足,甚至导致系统崩溃,/(ㄒoㄒ)/~~

image.png

滑动时间窗口(sliding time window)

顾名思义,该时间窗口是滑动的。所以,从概念上讲,这里有两个方面的概念需要理解:

  • 窗口:需要定义窗口的大小
  • 滑动:需要定义在窗口中滑动的大小,但理论上讲滑动的大小不能超过窗口大小

滑动窗口算法是把固定时间片进行划分并且随着时间移动,移动方式为开始时间点变为时间列表中的第2个时间点,结束时间点增加一个时间点,

不断重复,通过这种方式可以巧妙的避开计数器的临界点的问题。下图统计了5次

image.png

演示

修改支付模块

修改服务提供者8001,PayCircuitController新增myRatelimit方法

@GetMapping(value = "/pay/ratelimit/{id}")
public String myRatelimit(@PathVariable("id") Integer id) {
    return "Hello, myRatelimit欢迎到来 inputId:  " + id + " \t " + IdUtil.simpleUUID();
}
PayFeignApi接口新增限流api方法
/**
 * Resilience4j Ratelimit 的例子
 *
 * @param id 支付流水ID
 * @return 响应数据
 */
@GetMapping(value = "/pay/ratelimit/{id}")
String myRatelimit(@PathVariable("id") Integer id);
修改订单80模块
  1. 添加依赖
<!--resilience4j-ratelimiter-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
</dependency>
  1. 修改yaml文件
####resilience4j ratelimiter 限流的例子
resilience4j:
  ratelimiter:
    configs:
      default:
        limitForPeriod: 2 #在一次刷新周期内,允许执行的最大请求数
        limitRefreshPeriod: 1s # 限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
        timeout-duration: 1 # 线程等待权限的默认等待时间
    instances:
      cloud-payment-service:
        baseConfig: default
  1. 修改controller
@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ㄒ)/~~";
}

相关文章

评论区