SpringCloud升级之路2020.0.x版-31. FeignClient 实现断路器以及线程隔离限流的思路 (3)

ThreadPoolBulkheadConfig.java

//以下五个参数对应 Java 线程池的配置,我们这里就不再赘述了 private int maxThreadPoolSize = Runtime.getRuntime().availableProcessors(); private int coreThreadPoolSize = Runtime.getRuntime().availableProcessors(); private int queueCapacity = 100; private Duration keepAliveDuration = Duration.ofMillis(20); private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); //对应 RuntimeException 的 writableStackTrace 属性,即生成异常的时候,是否缓存异常堆栈 //限流器相关的异常都是继承 RuntimeException,这里统一指定这些异常的 writableStackTrace //设置为 false,异常会没有异常堆栈,但是会提升性能 private boolean writableStackTraceEnabled = true; //Java 很多 Context 传递都基于 ThreadLocal,但是这里相当于切换线程了,某些任务需要维持上下文,可以通过实现 ContextPropagator 加入这里即可 private List<ContextPropagator> contextPropagators = new ArrayList<>();

在添加了上一节所说的 resilience4j-spring-cloud2 依赖之后,我们可以这样配置断路器和线程隔离:

resilience4j.circuitbreaker: configs: default: registerHealthIndicator: true slidingWindowSize: 10 minimumNumberOfCalls: 5 slidingWindowType: TIME_BASED permittedNumberOfCallsInHalfOpenState: 3 automaticTransitionFromOpenToHalfOpenEnabled: true waitDurationInOpenState: 2s failureRateThreshold: 30 eventConsumerBufferSize: 10 recordExceptions: - java.lang.Exception resilience4j.thread-pool-bulkhead: configs: default: maxThreadPoolSize: 50 coreThreadPoolSize: 10 queueCapacity: 1000 如何实现微服务实例方法粒度的断路器

我们要实现的是每个微服务的每个实例的每个方法都是不同的断路器,我们需要拿到:

微服务名

实例 ID,或者能唯一标识一个实例的字符串

方法名:可以是 URL 路径,或者是方法全限定名。

我们这里方法名采用的是方法全限定名称,而不是 URL 路径,因为有些 FeignClient 将参数放在了路径上面,例如使用 @PathVriable,如果参数是类似于用户 ID 这样的,那么一个用户就会有一个独立的断路器,这不是我们期望的。所以采用方法全限定名规避这个问题。

那么在哪里才能获取到这些呢?回顾下 FeignClient 的核心流程,我们发现需要在实际调用的时候,负载均衡器调用完成之后,才能获取到实例 ID。也就是在 org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient 调用完成之后。所以,我们在这里植入我们的断路器代码实现断路器。

另外就是配置粒度,可以每个 FeignClient 单独配置即可,不用到方法这一级别。举个例子如下:

resilience4j.circuitbreaker: configs: default: slidingWindowSize: 10 feign-client-1: slidingWindowSize: 100

下面这段代码,contextId 即 feign-client-1 这种,不同的微服务实例方法 serviceInstanceMethodId 不同。如果 contextId 对应的配置没找到,就会抛出 ConfigurationNotFoundException,这时候我们就读取并使用 default 配置。

try { circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceInstanceMethodId, contextId); } catch (ConfigurationNotFoundException e) { circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceInstanceMethodId); } 如何实现微服务实例线程限流器

对于线程隔离限流器,我们只需要微服务名和实例 ID,同时这些线程池只做调用,所以其实和断路器一样,可以放在 org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient 调用完成之后,植入线程限流器相关代码实现。

微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer

SpringCloud升级之路2020.0.x版-31. FeignClient 实现断路器以及线程隔离限流的思路

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzgxjg.html