CircuitBreaker断路器
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
CircuitBreaker的目的是保护分布式系统免受故障和异常,提高系统的可用性和健壮性。
当一个组件或服务出现故障时,CircuitBreaker会迅速切换到开放OPEN状态(保险丝跳闸断电),阻止请求发送到该组件或服务从而避免更多的请求发送到该组件或服务。这可以减少对该组件或服务的负载,防止该组件或服务进一步崩溃,并使整个系统能够继续正常运行。同时,CircuitBreaker还可以提高系统的可用性和健壮性,因为它可以在分布式系统的各个组件之间自动切换,从而避免单点故障的问题。
CircuitBreaker只是一套规范接口,落地实现者是Resilience4j。
Resilience4j
resilience4j是一个专为函数式编程设计的轻量级容错库,Resilience4j提供高阶函数(装饰器),以通过断路器、速率限制器、重试或隔板增强任何功能接口、lambda表达式或方法引用。可以在任何函数式接口、lambda表达式或方法引用上堆叠多个装饰器。
Resilience4j服务熔断和服务降级
断路器
- 断路器有三个普通状态:关闭(closed)、开启(open)、半开(half_open),还有两个特殊状态:禁用(disabled)、强制开启的(Forced_open)
- 当熔断器关闭时,所有的请求都会通过熔断器。
- 当失败率超过一定的阈值,熔断器就会从关闭状态转换到打开状态,这时所有的请求都会被拒绝。
- 当经过一段时间后,熔断器会从打开状态转换到半开状态,这时仅有一定数量的请求会被放入,并重新计算失败率
- 如果失败率超过阈值,则变为打开状态,如果失败率低于阈值,则变为关闭状态。
- 断路器使用滑动窗口来存储和统计调用的结果。可以选择基于调动数量的滑动窗口或者基于时间的滑动窗口。
- 基于访问数量的滑动窗口统计了最近n秒的调用返回结果。
- 除此之外,熔断器还会有两种特殊状态:disabled(始终允许访问)和forced_open(始终拒绝访问)。
- 这两个状态不会生成熔断器事件(除状态转换外),并且不会记录事件的成功与失败。
- 退出这两个状态的唯一方法是触发状态转换或者重置熔断器。
断路器配置
常用的几个配置:
配置属性 | 默认值 | 描述 |
---|---|---|
failureRateThreshold | 50 | 以百分比配置失败率阈值。当失败率等于或者大于阈值时,断路器状态变关闭为开启,并进行服务降级 |
slowCallRateThreshold | 100 | 以百分比的方式配置,断路器把调用时间大于slowCallRateThreshold的调用视为慢调用,当慢调用比例大于或者等于阈值时,断路器开启,并进行服务降级。 |
slowCallDurationThreshold | 60000(ms,毫秒) | 配置调用时间的阈值,高于该阈值的呼叫被视为慢调用,并增加慢调用比例。 |
permittedNumberOfCallsInHalfOpenState | 10 | 断路器在半开的状态下,允许通过的调用次数 |
minimunNumberOfCalls | 100 | 在每个滑动窗口期样本数,配置断路器计算错误率或者慢调用率的最小调用数。比如设置为5意味着,在计算故障率之前,必须至少调用5次。如果只记录了4次,即使4次都失败了,断路器也不会进入到打开状态。 |
waitDurationInOpenState | 60000(ms,毫秒) | 从OPEN到HALF_OPEN状态需要等待的时间 |
slidingWindowType | COUNT_BASED | 断路器的滑动窗口期类型。 |
可以基于“次数”(COUNT_BASED)或者“时间”(TIME_BASED)进行熔断,默认是COUNT_BASED。 若为COUNT_BASED,则10次调用中有50%失败(即5次)打开熔断断路器; | ||
若为TIME_BASED则,此时还有额外的两个设置属性,含义为:在N秒内(sliding-window-size)100%(slow-call-rate-threshold)的请求超过N秒(slow-call-duration-threshold)打开断路器。 | ||
slidingWindowSize | 100 | 配置滑动窗口的大小 |
案例:按照COUNT_BASED(计数的滑动窗口)
- 服务客户端的模块pom文件引入依赖:
<!--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>
- 在yaml文件中要操作两步,一是spring的配置中 开启circuitbreaker和分组激活spring.cloud.openfeign.circuitbreaker.enabled,二是配置Resilience4j的配置信息
整体配置文件如下:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
connect-timeout: 3000
read-timeout: 3000
cloud-provider-payment:
#连接超时时间
connectTimeout: 5000
#读取超时时间
readTimeout: 5000
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048 #最小触发压缩的大小
mime-types: text/xml,application/xml,application/json #触发压缩数据类型
response:
enabled: true
# 开启circuitbreaker和分组激活 spring.cloud.openfeign.circuitbreaker.enabled
circuitbreaker:
enabled: true
group:
enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
logging:
level:
com:
ergou:
cloud:
apis:
PayFeignApi: debug
# 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
服务客户端的模块的controller:
@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ㄒ)/~~";
}
}
案例:按照TIME_BASED(时间的滑动窗口)
yaml文件的配置改为:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
connect-timeout: 3000
read-timeout: 3000
cloud-provider-payment:
#连接超时时间
connectTimeout: 5000
#读取超时时间
readTimeout: 5000
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048 #最小触发压缩的大小
mime-types: text/xml,application/xml,application/json #触发压缩数据类型
response:
enabled: true
# 开启circuitbreaker和分组激活 spring.cloud.openfeign.circuitbreaker.enabled
circuitbreaker:
enabled: true
group:
enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
logging:
level:
com:
ergou:
cloud:
apis:
PayFeignApi: debug
# 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
建议使用COUNT_BASED的方式
Resilience4j舱壁隔离BulkHead
舱壁隔离(依赖隔离&负载保护):用来限制对于下游服务的最大并发数量的限制。
Resilience提供了两种隔离的实现方式,可以限制并发执行的数量:
- SemaphoreBulkhead:使用了信号量
- FixedThreadPoolBulkhead:使用了有界队列和固定大小线程池
SemaphoreBulkhead(信号量舱壁)
原理:
当信号量有空闲时,进入系统的请求会直接获取信号量并开始业务处理。
当信号量全被占用时,接下来的请求将会进入阻塞状态,SemaphoreBulkhead提供了一个阻塞计时器,
如果阻塞状态的请求在阻塞计时内无法获取到信号量则系统会拒绝这些请求。
若请求在阻塞计时内获取到了信号量,那将直接获取信号量并执行相应的业务处理。
使用步骤
- 在服务客户端的pom中引入依赖:
<!--resilience4j-bulkhead-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-bulkhead</artifactId>
</dependency>
- yaml文件:
属性配置:
maxConcurrentCalls:舱壁允许的最大并行执行量,默认值是25
maxWaitDuration:尝试进入饱和舱壁时,应阻塞线程的最长时间,默认值是0
在配置文件下方配置:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
connect-timeout: 3000
read-timeout: 3000
cloud-provider-payment:
#连接超时时间
connectTimeout: 5000
#读取超时时间
readTimeout: 5000
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048 #最小触发压缩的大小
mime-types: text/xml,application/xml,application/json #触发压缩数据类型
response:
enabled: true
# 开启circuitbreaker和分组激活 spring.cloud.openfeign.circuitbreaker.enabled
circuitbreaker:
enabled: true
group:
enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
logging:
level:
com:
ergou:
cloud:
apis:
PayFeignApi: debug
# 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
#舱壁隔离的配置信息
bulkhead:
configs:
default:
maxConcurrentCalls: 2 # 隔离允许并发线程执行的最大数量
maxWaitDuration: 1s # 当达到并发调用数量时,新的线程的阻塞时间,我只愿意等待1秒,过时不候进舱壁兜底fallback
instances:
cloud-payment-service:
baseConfig: default
controller类:
/**
*(船的)舱壁,隔离 信息量舱壁demo
* @param 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(固定线程池)
FixedThreadPoolBulkhead的功能与SemaphoreBulkhead一样也是用于限制并发执行的次数的,但是二者的实现原理存在差别而且表现效果也存在细微的差别。FixedThreadPoolBulkhead使用一个固定线程池和一个等待队列来实现舱壁。
当线程池中存在空闲时,则此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求。
当线程池中无空闲时时,接下来的请求将进入等待队列,
若等待队列仍然无剩余空间时接下来的请求将直接被拒绝,
在队列中的请求等待线程池出现空闲时,将进入线程池进行业务处理。
另外:ThreadPoolBulkhead只对CompletableFuture方法有效,所以我们必创建返回CompletableFuture类型的方法
配置项:
- maxThreadPoolSize:配置最大线程池的大小,默认值是Runtime.getRuntime().availableProcessors
- coreThreadPoolSize:配置核心线程池的大小,默认值是Runtime.getRuntime().availableProcessors - 1
- queueCapacity:配置队列的容量,默认值是100
- keepAliveDuration:当线程数大于核心数时,这是多余空闲线程在终止前等待新任务的最长时间,默认值是20ms
使用步骤
- pom引入依赖,依赖也是同上方的信号舱舱壁隔离的一样的,见上
- yaml文件:(服务客户端的模块)
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
connect-timeout: 3000
read-timeout: 3000
cloud-provider-payment:
#连接超时时间
connectTimeout: 5000
#读取超时时间
readTimeout: 5000
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048 #最小触发压缩的大小
mime-types: text/xml,application/xml,application/json #触发压缩数据类型
response:
enabled: true
# 开启circuitbreaker和分组激活 spring.cloud.openfeign.circuitbreaker.enabled
circuitbreaker:
enabled: true
# group: #当要使用固定线程池舱壁的时候,要设置为false或者直接注释掉
# enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
logging:
level:
com:
ergou:
cloud:
apis:
PayFeignApi: debug
# 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
#舱壁隔离的配置信息
# bulkhead:
# configs:
# default:
# maxConcurrentCalls: 2 # 隔离允许并发线程执行的最大数量
# maxWaitDuration: 1s # 当达到并发调用数量时,新的线程的阻塞时间,我只愿意等待1秒,过时不候进舱壁兜底fallback
# instances:
# cloud-payment-service:
# baseConfig: default
#固定线程池舱壁隔离
thread-pool-bulkhead:
configs:
default:
core-thread-pool-size: 1
max-thread-pool-size: 1
queue-capacity: 1
instances:
cloud-payment-service:
baseConfig: default
# timelimiter:
# configs:
# default:
# timeout-duration: 10s
controller:
@GetMapping(value = "/feign/pay/bulkhead/{id}")
@Bulkhead(name = "cloud-payment-service",fallbackMethod = "myBulkThreadPoolHeadFallback",type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> myBulkheadThreadPool(@PathVariable("id") Integer id)
{
return CompletableFuture.supplyAsync(() -> payFeignApi.myBulkhead(id) + "\\tThreadPool");
}
public CompletableFuture<String> myBulkThreadPoolHeadFallback(Throwable t)
{
return CompletableFuture.supplyAsync(() -> "(固定线程池舱壁隔离)隔板超出最大数量限制,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~");
}
Resilience4j限流RateLimiter
限流就是限制最大访问量。系统能提供的最大并发是有限制的,同时来的请求太多了,就需要限流。
也就是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速,以保护应用系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。
常见限流算法
- 漏斗算法:让请求像水流过漏斗一样,请求的处理效率是固定的,来不及处理的请求在“漏斗”中等待。漏斗算法对于存在突发特性的流量来说缺乏效率。
- 令牌桶算法:准备一定的令牌数,请求通过时,如果令牌有剩余,该请求就领取一个令牌,并进入处理,处理完后释放令牌。没有令牌剩余的时候就是到等待队列中等待令牌。这种方法是SpringCloud默认使用的算法。
- 滚动时间窗:取一段时间内,允许固定数量的请求进入,如果这段时间内超过该固定数量,就拒绝或者排队,等下一个时间段进入。但是间隔临界的一段时间内的请求超过系统限制,可能导致系统被压垮。
- 滑动时间窗:滑动事件窗口是把固定时间片段进行划分,并且随着时间移动,移动方式为开始时间点变为时间列表中的第二个时间点,结束时间点增加一个时间点,不断重复。达到一种滑片滑动的效果。
配置项
- timeoutDuration:线程等待权限的默认等待时间,默认是五秒钟
- limitRefreshPeriod:限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod,默认是500纳秒
- limitForPeriod:在一次刷新周期内,允许执行的最大请求数,默认是50
使用步骤
pom文件中引入依赖:
<!--resilience4j-ratelimiter-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
</dependency>
yaml文件:
####resilience4j ratelimiter 限流的例子
resilience4j:
ratelimiter:
configs:
default:
limitForPeriod: 2 #在一次刷新周期内,允许执行的最大请求数
limitRefreshPeriod: 1s # 限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
timeout-duration: 1 # 线程等待权限的默认等待时间
instances:
cloud-payment-service:
baseConfig: default
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ㄒ)/~~";
}