并发调用隔离之BulkHead模式学习

本文介绍了BulkHead模式的概念及其在Java中的实现方式。该模式通过隔离不稳定因素,限制其影响范围,从而提高系统的整体稳定性。文章详细阐述了使用信号量和线程池两种实现方法,并对比了它们的特点。

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

1 BulkHead模式是什么

bulkhead指船的防水壁,如下图:当一个防水壁漏水时不会导致整个船沉掉,起到保护作用,提高稳定性。即通过隔离的形式,让不稳定因素限制在某一个小范围内,不会导致整个系统崩溃。

在这里插入图片描述
在我们日常开发系统,对外提供服务均以HTTP或RPC的形式对外提供。如下图,每种形式在接收到请求后根据业务的不同会在内部调用多个外部依赖来完成业务。

在这里插入图片描述

一个接口会依赖多个外部远程服务。外部服务由于各种原因,可能不可靠。会出现超时,无响应的情况。这样就会导致调用线程阻塞。如果有大量的这种请求产生,则会使大量调用线程阻塞,导致对外提供的HTTP或RPC服务不可用。

因此通过隔离的形式,限制不同并发调用对资源的使用范围,提高系统的可用性。

如下图[1],hystrix中对每个远程请求分配一个线程池,并限制线程池中线程数量,最终减少故障带来的影响范围。

在这里插入图片描述

2 Java中实现BulkHead的两种方式

通过第一节的介绍显而易见,可以通过线程隔离的形式来控制,即限制调用并发数

在Java中可以两种主要控制方式如下:

  • Semaphore(信号量)
  • 每个远程调用分配一个线程池的形式来实现。

日常服务我们对外提供的服务以Http或RPC为主。这两种主要是通过每请求每线程的形式对外提供服务。最终我们在请求线程中再次调用外部依赖完成调用。

我们隔离的目的就是线程特定请求并发调用数量,这样保护HTTP或RPC处理请求的线程池不被打满,保证服务可用

最终将所有依赖进行包装。并将系统中对外部的调用路由到一个个包装模块上,通过信号量大小或线程池大小实现限制。

图2

2.1 信号量并发数限制

通过第二节的介绍,当请求进入系统,服务依赖外部调用。我们将外部调用封装,并创建全局实例。对全系统中这个请求的调用通过信号量进行限制。这样的方式,RPC或HTTP服务线程池不会因某个依赖被打满。

这种方式的确定显而易见,通过信号量限制的方式,调用线程会阻塞在外部调用上,没法并发处理多个无顺序依赖关系的外部调用。此外没法像线程池获取异步调用结果一样处理超时,及时释放线程。因此需要RPC超时设置且可靠,使用时,外部依赖需要保证能够快速失败或具备一定可靠性。

这种模式下设置信号量大小时,根据调用服务线程数量及依赖的业务的情况进行划分。

2.2 线程池限制并发数

依然对外部依赖进行包装,每个依赖创建一个线程池,并固定线程数量。那么这种模式下的并发限制就是通过线程池大小来限制。当对外部依赖调用打满所关联的线程池,那么就被限制住。

通过这种方式,调用线程不会阻塞在某个外部调用上。如果一个请求依赖多个无依赖关系的外部调用,这时也可以并发调用。最终等待这些线程返回的结果,同时可以通过设置超时时间来避免让一个调用程阻塞过久,提前返回。

关于线程池隔离的其它优缺点可以参考netflix[2]的介绍。

3 隔离的开源工具

常见的如hystrix及resilience4j-bulkhead提供隔离的能力,限制并发调用数。

4 参考资料

[1]Isolation,https://github.com/Netflix/Hystrix/wiki/How-it-Works#Isolation
[2]threads,https://github.com/Netflix/Hystrix/wiki/How-it-Works#Threads

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值