resilience4j(十二):核心模块Bulkhead源码之Bulkhead、SemaphoreBulkhead

本文深入探讨了resilience4j中的Bulkhead模块,尤其是SemaphoreBulkhead的实现。通过Bulkhead,可以实现应用中不同方法的并发控制,防止异常影响整个系统。主要介绍了Bulkhead的核心配置、模块间关系,以及SemaphoreBulkhead的isCallPermitted方法。文章还提到了BulkheadEvent和动态配置的可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Bulkhead

resilience4j-SpringBoot2-demo

Bulkhead中文意思:船舶中的隔舱板,将船体分割成多个船舱。把应用系统当成一艘船,那么应用中不同方法,就对应船里面不同船舱,船舱可能是单人间,也可能是四人间、八人间、或者大通铺。船舱容量对应应用中不同方法允许承受的最大并发量。Bulkhead作用是让一个应用中不同方法互不影响,避免某些方法调用异常危及整个应用。

主要分为以下几个模块:隔离器配置,隔离器注册,隔离器事件消费者注册,隔离器状态及指标,隔离器事件,隔离器事件处理器,隔离器事件消费者。

各模块间关系

在这里插入图片描述

  • BulkheadRegistry通过其实现类InMemoryBulkheadRegistry根据BulkheadConfig创建Bulkhead实例。
  • EventConsumerRegistry通过其实现类DefaultEventConsumerRegistry创建EventConsumer事件消费者。
  • Bulkhead通过其实现类SemaphoreBulkhead控制并发,并发布BulkheadEvent从而被注册到EventProcessor事件处理器的EventConsumer事件消费者消费。

Bulkhead接口介绍

通过下图可看出主要依次分为一下几个部分:

### Bulkhead 模式概述 Bulkhead 模式是一种容错设计,其核心思想是通过限制并发请求的数量来防止系统资源被耗尽,从而避免级联故障。Resilience4j 提供了基于信号量(Semaphore)和线程池(ThreadPool)两种实现方式的 Bulkhead 模式,分别适用于同步和异步场景。 在 Resilience4j 中,Bulkhead 的主要作用是限制对某个服务或资源的并发调用次数。当并发调用数达到设定的阈值时,新的请求将被拒绝,而不是继续执行。这种机制可以有效防止某个服务因过载而导致整个系统崩溃。 ### 配置与使用 Resilience4jBulkhead 支持通过配置文件进行定义,也可以通过编程方式进行设置。以下是一个基于配置文件的示例: ```yaml resilience4j.bulkhead.configs.default.maxConcurrentCalls=10 resilience4j.bulkhead.configs.default.maxWaitDuration=0 ``` 上述配置表示: - `maxConcurrentCalls`:最大并发调用数为 10,即最多允许 10 个并发请求同时执行。 - `maxWaitDuration`:请求等待时间设为 0,表示如果当前并发数已满,新的请求将立即被拒绝;若设置为正数,则请求会在指定时间内等待可用资源。 ### 编程方式实现 Bulkhead 除了配置文件,还可以通过编程方式创建和使用 Bulkhead 实例。以下是一个使用 `BulkheadRegistry` 和 `Bulkhead` 的 Java 示例: ```java import io.github.resilience4j.bulkhead.Bulkhead; import io.github.resilience4j.bulkhead.BulkheadConfig; import io.github.resilience4j.bulkhead.BulkheadRegistry; import java.time.Duration; public class BulkheadExample { public static void main(String[] args) { // 定义 Bulkhead 配置 BulkheadConfig config = BulkheadConfig.custom() .maxConcurrentCalls(4) .maxWaitDuration(Duration.ofMillis(100)) .build(); // 创建 BulkheadRegistry BulkheadRegistry registry = BulkheadRegistry.of(config); // 获取或创建 Bulkhead 实例 Bulkhead bulkhead = registry.bulkhead("backendService"); // 使用 Bulkhead 执行任务 for (int i = 0; i < 10; i++) { new Thread(() -> { try { bulkhead.acquirePermission(); // 获取许可 System.out.println("Executing task in thread: " + Thread.currentThread().getName()); Thread.sleep(500); // 模拟任务执行时间 } catch (InterruptedException e) { e.printStackTrace(); } finally { bulkhead.releasePermission(); // 释放许可 } }).start(); } } } ``` 在该示例中,最多允许 4 个线程并发执行任务,超出的请求将等待最多 100 毫秒。如果在等待时间内无法获取许可,则请求将被拒绝。 ### 获取 Bulkhead 状态信息 Resilience4j 提供了 `Bulkhead.Metrics` 类来获取当前 Bulkhead 的运行状态,包括可用的并发调用数、等待队列中的请求数等。以下是一个获取状态信息的示例: ```java Bulkhead.Metrics metrics = bulkhead.getMetrics(); int availableConcurrentCalls = metrics.getAvailableConcurrentCalls(); int queuedTasks = metrics.getEstimatedCurrentQueueSize(); System.out.println("Available concurrent calls: " + availableConcurrentCalls); System.out.println("Queued tasks: " + queuedTasks); ``` 该代码通过 `getMetrics()` 方法获取当前 Bulkhead 的指标信息,并输出可用的并发调用数和等待队列大小[^1]。 ### 原理分析 Bulkhead核心原理是通过信号量(Semaphore)控制并发访问。当一个请求进入时,它会尝试获取一个信号量许可;如果成功获取,则继续执行任务;如果未成功获取(即已达到最大并发数),则根据配置决定是等待还是直接拒绝请求。 Resilience4jBulkhead 实现基于非阻塞式设计,避免了传统线程池调度带来的性能瓶颈。它适用于需要控制并发访问的场景,例如数据库连接池、外部服务调用等。 ### 与其他组件的集成 Resilience4jBulkhead 可以与其他组件(如 Circuit Breaker 和 Retry)结合使用,构建更加健壮的服务调用链路。例如,在调用某个外部服务时,可以先通过 Bulkhead 限制并发请求,再通过 Circuit Breaker 监控失败率,最后通过 Retry 实现失败重试策略。 以下是一个结合 Circuit Breaker 和 Bulkhead 的示例: ```java import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; import io.github.resilience4j.bulkhead.Bulkhead; import io.github.resilience4j.bulkhead.BulkheadConfig; import io.github.resilience4j.bulkhead.BulkheadRegistry; import java.time.Duration; public class CombinedExample { public static void main(String[] args) { // 创建 CircuitBreaker 配置 CircuitBreakerConfig cbConfig = CircuitBreakerConfig.custom() .failureRateThreshold(50.0f) .waitDurationInOpenState(Duration.ofSeconds(5)) .ringBufferSizeInClosedState(10) .build(); CircuitBreakerRegistry cbRegistry = CircuitBreakerRegistry.of(cbConfig); CircuitBreaker circuitBreaker = cbRegistry.circuitBreaker("backendService"); // 创建 Bulkhead 配置 BulkheadConfig bhConfig = BulkheadConfig.custom() .maxConcurrentCalls(5) .maxWaitDuration(Duration.ofMillis(100)) .build(); BulkheadRegistry bhRegistry = BulkheadRegistry.of(bhConfig); Bulkhead bulkhead = bhRegistry.bulkhead("backendService"); // 使用组合策略调用服务 for (int i = 0; i < 10; i++) { new Thread(() -> { if (circuitBreaker.getState() == CircuitBreaker.State.OPEN) { System.out.println("CircuitBreaker is OPEN, rejecting request."); return; } try { bulkhead.acquirePermission(); if (Math.random() < 0.3) { throw new RuntimeException("Simulated failure"); } System.out.println("Request processed successfully by " + Thread.currentThread().getName()); } catch (Exception e) { circuitBreaker.onError(0, e); System.out.println("Request failed: " + e.getMessage()); } finally { bulkhead.releasePermission(); } }).start(); } } } ``` 在该示例中,首先通过 Circuit Breaker 判断服务是否处于可用状态,再通过 Bulkhead 控制并发访问,从而构建了一个多层次的容错机制。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值