BulkheadPolicy 是 Polly 中实现舱壁隔离的策略,通过 maxParallelization(最大并发数)和 maxQueuedActions(最大排队数)限制资源使用,超限即抛 BulkheadRejectedException,本质是物理隔离而非限流。
BulkheadPolicy?BulkheadPolicy 是 Polly 中实现舱壁隔离(Bulkhead Isolation)的策略,它通过限制并发执行的请求数量和排队等待的请求数量,防止某个依赖故障或延迟拖垮整个调用方线程池或资源。它的核心不是重试或熔断,而是“物理隔离”——像轮船的舱壁一样,把失败控制在
局部。
BulkheadPolicy 的两个关键参数:maxParallelization 和 maxQueuedActions
创建 BulkheadPolicy 时必须指定这两个整数参数,它们共同定义了资源使用边界:
maxParallelization:最多允许多少个操作**同时执行**(即占用线程/任务)maxQueuedActions:当所有并行槽位被占满时,最多允许多少个操作在队列中**等待执行**超出这两个限制的调用会立即抛出 BulkheadRejectedException,而不是阻塞或排队无限等待。
var bulkhead = Policy.BulkheadAsync(
maxParallelization: 5,
maxQueuedActions: 10
);
注意:maxParallelization 不等于线程数(尤其在 async/await 场景下),它表示“同时处于 ExecuteAsync 执行上下文中的操作数量”。对 I/O 密集型操作,实际线程消耗远小于此值;但对 CPU 密集型或同步阻塞调用,它可能直接对应线程池租用数。
Task.Run 或 SemaphoreSlim?手动用 SemaphoreSlim 或线程池限流,容易漏掉几个关键点:
WaitAsync 超时、手动抛出业务一致的拒绝异常RetryPolicy、CircuitBreakerPolicy)自然组合而 BulkheadPolicy 把这些封装进统一的 ExecuteAsync 接口,且支持 PolicyWrap 组合:
var policyWrap = Policy.WrapAsync(bulkhead, retry, breaker);
舱壁策略最容易被当成“限流器”滥用,但它本质是**资源隔离机制**,不是速率控制器:
RateLimitPolicy
Thread.Sleep),maxParallelization 会快速耗尽线程池,导致后续请求即使没超限也因无可用线程而卡死maxQueuedActions 设为 0 并不意味着“不排队”,而是“拒绝所有排队请求”——此时一旦 5 个并发满,第 6 个调用立刻抛 BulkheadRejectedException
ExecuteAsync 内部再用 .Wait() 或 .Result,这会破坏异步流并可能导致死锁或线程饥饿真正需要舱壁的场景,是调用外部不稳定服务(如第三方 HTTP API、数据库查询),且你明确知道该服务的吞吐瓶颈或连接池上限。盲目加舱壁反而增加延迟和拒绝率。