Bulkhead
Bulkhead中文意思:船舶中的隔艙板,將船體分割成多個船艙。把應用系統當成一艘船,那麼應用中不同方法,就對應船裏面不同船艙,船艙可能是單人間,也可能是四人間、八人間、或者大通鋪。船艙容量對應應用中不同方法允許承受的最大併發量。Bulkhead作用是讓一個應用中不同方法互不影響,避免某些方法調用異常危及整個應用。
主要分爲以下幾個模塊:隔離器配置,隔離器註冊,隔離器事件消費者註冊,隔離器狀態及指標,隔離器事件,隔離器事件處理器,隔離器事件消費者。
各模塊間關係
- BulkheadRegistry通過其實現類InMemoryBulkheadRegistry根據BulkheadConfig創建Bulkhead實例。
- EventConsumerRegistry通過其實現類DefaultEventConsumerRegistry創建EventConsumer事件消費者。
- Bulkhead通過其實現類SemaphoreBulkhead控制併發,併發布BulkheadEvent從而被註冊到EventProcessor事件處理器的EventConsumer事件消費者消費。
Bulkhead接口介紹
通過下圖可看出主要依次分爲一下幾個部分:
- 動態改變隔離配置
- 隔離請求判斷&完成時操作 (隔離器最核心流程)
- 獲取對應隔離信息
- 裝飾器模式提供多個接口、支持lambda表達式。
- 度量指標
- 事件發佈&註冊
核心配置
- maxConcurrentCalls : Bulkhead允許的最大並行執行量。默認:25
- maxWaitDuration:嘗試進入飽和艙壁時線程阻塞等待的最長時間。默認:0
核心流程圖
Bulkhead核心處理流程如下所示,當請求被拒絕時,拋出BulkheadFullException。並在請求通過、拒絕、完成時,publish 對應 BulkheadEvent。
本文主要講述SemaphoreBulkhead信號量隔離機制,最新版本新增支持了ThreadPoolBulkhead。
BulkheadEvent
隔離器事件,有三種類型。
/** 請求被允許通過時,發佈.*/
CALL_PERMITTED
/** 請求被允許拒絕時,發佈*/
CALL_REJECTED,
/** 處理請求後發佈,無論請求是通過還是被拒絕*/
CALL_FINISHED;
SemaphoreBulkhead
Bulkhead接口實現類,利用JDK的Semaphore實現併發控制。
從圖中其構造方法可看出,使用的是Semaphore公平模式,即先到先得。
isCallPermitted
public boolean isCallPermitted() {
//嘗試獲取信號量,並返回結果
boolean callPermitted = tryEnterBulkhead();
//根據獲取結果發佈對應event
publishBulkheadEvent(
() -> callPermitted ? new BulkheadOnCallPermittedEvent(name)
: new BulkheadOnCallRejectedEvent(name)
);
return callPermitted;
}
boolean tryEnterBulkhead() {
boolean callPermitted = false;
//獲取配置的最大等待時長
long timeout = config.getMaxWaitTime();
if (timeout == 0) {
//直接嘗試獲取許可
callPermitted = semaphore.tryAcquire();
} else {
try {
//在對應規定時間內嘗試獲取許可
callPermitted = semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
callPermitted = false;
}
}
return callPermitted;
}
semaphore.tryAcquire在Semaphore介紹中有介紹,這裏不在敘述。
訂閱消費事件和前面章節CircuitBreaker事件消費類似,不在敘述。
總結:
- Bulkhead通過JDK中Semaphore(公平模式)實現併發控制。
- 可在運行時修改Bulkhead配置,同時也可訂閱對應事件。
- Bulkhead是通過拋出BulkheadFullException方式終止請求調用的。