生產過程
只是泛指調用 Disruptor 發佈事件的開發代碼, 與事件(Event)一樣,不是被定義的特定類型。
RingBuffer.next() -> MultiProducerSequencer.next()
得到下一個可用事件槽。如果 預分配的序列號 >(消費最慢的消費者已處理的序列號 + 容量bufferSize), 則表示當前沒有空閒的事件槽,此時將阻塞。
public long next(int n) {
if (n < 1) {
throw new IllegalArgumentException("n must be > 0");
}
long current;
long next;
do {
// 當前生產的序列號
current = cursor.get();
// 預計下一個序列號
next = current + n;
long wrapPoint = next - bufferSize; // 能夠進行生產時消費者最少要處理到的序列號
long cachedGatingSequence = gatingSequenceCache.get(); //所有消費者組裏最小消費序列號
// 能夠生產時最少要處理到的序列號 > 消費者內最小的消費序列號
// 或 消費者最小消費序列號 > 當前生產序列號 (這個條件正常情況應該不太可能,更多是考慮糾錯重新設置gatingSequenceCache)
if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current) {
//這裏取的是: 所有消費者集合裏消費最慢的那個序號列 與 當前生產序列號 最小的值,能保證每種模式下的消費者組中的消費者都不會漏處理。
long gatingSequence = Util.getMinimumSequence(gatingSequences, current);
if (wrapPoint > gatingSequence) {
// 預分配的序列號 >(消費的序列號 + 容量size), 有消費者還沒消費到wrapPoint ,當前沒有空閒事件槽需要等待固定時長
LockSupport.parkNanos(1); // TODO, should we spin based on the wait strategy?
continue;
}
// 更新爲:消費最少的那個消費者的已處理序列號
gatingSequenceCache.set(gatingSequence);
}
// CAS方式設置next序列
else if (cursor.compareAndSet(current, next)) {
break;
}
}
while (true);
return next;
}
public void publish(final long sequence)
{
setAvailable(sequence);
waitStrategy.signalAllWhenBlocking();//喚醒等待的消費者
}
根據源碼來分析,這個過程裏有幾個重要因素:
- 體現容量的概念: “wrapPoint = next - bufferSize”。 表示: 若能夠在nenxt序列號上生產時消費者最少要處理到的序列。
- 因爲有 串|並 的組合消費。所以這裏用來比對的是gatingSequenceCache :消費最慢的那個消費者已處理序列號;保證每種方式下的消費者都不會漏處理。
基本邏輯是:
如果: 能夠生產時最少要處理到的序列號wrapPoint > 消費者內最小(少)的消費序列號gatingSequenceCache 則自旋等待1 nanoseconds 後進入下一次計算,並更新gatingSequenceCache 爲消費最少的消費者序列號。每次分配好的next序列號會更新到生產序列器cursor中。隨後按指定生產序列號publish
事件,並喚醒每一個等待中的消費線程。
消費
要素
com.lmax.disruptor.EventFactory<T>
生產者和消費者之間進行交換的數據被稱爲事件(Event),在Disruptor
啓動初始化階段會默認創建並存儲於緩衝區數組每個下標地址中。它不是一個被 Disruptor
定義的特定類型,而是由開發者指定工廠類EventFactory
來創建實例;
所以 在發佈事件前,需要對RingBuffer.get(RingBuffer.next())
獲取到的數據對象實例重新賦值。
com.lmax.disruptor.EventHandler<T> | com.lmax.disruptor.WorkHandler<T>
消費者處理類需要實現的接口,可組合使用。
獨立消費者應當實現EventHandler接口,同一事件每個消費者都會處理;Disruptor.handleEventsWith(EventHandler<? super DataEvent>... handlers)
。
不重複消費則實現WorkHandler接口,此時同一事件被隨機一個消費者處理;Disruptor.handleEventsWithWorkerPool(WorkHandler<? super DataEvent>... handlers)
。
com.lmax.disruptor.EventProcessor extends Runnable
消費者信息的線程Runnable
對象。
在實例實現裏,一般都持有事件消費者WorkHandler | EventHandler
、異常處理者ExceptionHandler
、 消費者的 Sequence
、序列消費控制屏障SequenceBarrier
;
com.lmax.disruptor.dsl.ConsumerRepository<T>
消費者信息倉庫,存儲了消費者線程上下文信息的封裝對象com.lmax.disruptor.dsl.ConsumerInfo
。按消費模式也有兩種具體實現:
消費者線程 EventProcessor
Disruptor.start()
遍歷消費者信息倉庫ConsumerRepository
裏的每一個消費者ConsumerInfo
執行方法ConsumerInfo.start(Executor executor)
; 實際上是Executor.execute
執行每一個事件消費者 線程Runnable
對象EventProcessor
。
事件處理有兩種模式:
EventHandler -> BatchEventProcessor -> EventProcessorInfo
WorkHandler -> WorkProcessor -> WorkerPool -> WorkerPoolInfo
分組內都共用同一個 SequenceBarrier
, 每一個EventHandler
都有各自獨立的 Sequence;而WorkHandler
在WorkerPool
層面共用一個workSequence。
EventHandler
每一個消費者都被封裝爲接口EventProcessor
的實例類BatchEventProcessor
,每個BatchEventProcessor
有單獨的Sequence。和EventHandler
、SequenceBarrier
組合在一起得到接口ConsumerInfo
的實例類EventProcessorInfo
。
關係: 1 EventHandler
: 1 Sequence
: 1 BatchEventProcessor
: 1 EventProcessorInfo
// Disruptor
EventHandlerGroup<T> createEventProcessors(final Sequence[] barrierSequences, final EventHandler<? super T>[] eventHandlers){
checkNotStarted();
// 每一個消費者都有自己的序列Sequence
final Sequence[] processorSequences = new Sequence[eventHandlers.length];
// 從ringBuffer中創建了序列控制閥
final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);
for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++) {
final EventHandler<? super T> eventHandler = eventHandlers[i];
// 每一個消費者創建線程runnable對象BatchEventProcessor
final BatchEventProcessor<T> batchEventProcessor =
new BatchEventProcessor<>(ringBuffer, barrier, eventHandler);
if (exceptionHandler != null) {
batchEventProcessor.setExceptionHandler(exceptionHandler);
}
// 消費者信息對象的倉庫
consumerRepository.add(batchEventProcessor, eventHandler, barrier);
processorSequences[i] = batchEventProcessor.getSequence();
}
// 給緩衝區RingBuffer增加每個消費者的序列監聽。也就是設置初始的gatingSequences
updateGatingSequencesForNextInChain(barrierSequences, processorSequences);
return new EventHandlerGroup<>(this, consumerRepository, processorSequences);
}
很關鍵的一點:
創建ProcessingSequenceBarrier
時傳入了參數“barrierSequences” 作爲其持有屬性dependentSequences,類型爲FixedSequenceGroup
;表示需要依賴的上游消費者序列器組合。WaitStrategy.waitFor
方法以此來判定傳入的消費序列號是否可以被當前消費者消費。(詳見BlockingWaitStrategy
,對於同享同一個ProcessingSequenceBarrier
的情況用ReentrantLock
來控制併發)
final class ProcessingSequenceBarrier implements SequenceBarrier{
private final WaitStrategy waitStrategy; // 等待策略
private final Sequence dependentSequence; // 依賴的上游消費者序列器組
private volatile boolean alerted = false;
private final Sequence cursorSequence; // 生產序列器
private final Sequencer sequencer;
ProcessingSequenceBarrier(
final Sequencer sequencer, final WaitStrategy waitStrategy, final Sequence cursorSequence, final Sequence[] dependentSequences){
this.sequencer = sequencer;
this.waitStrategy = waitStrategy;
this.cursorSequence = cursorSequence;
if (0 == dependentSequences.length) {
dependentSequence = cursorSequence; // 如果沒有需要依賴的上游消費者序列,則直接依賴生產序列
} else {
dependentSequence = new FixedSequenceGroup(dependentSequences); // 將依賴的上游消費者序列器組合, 判定時一般是取所有消費者中最少消費的那個序列號
}
}
// FixedSequenceGroup
public long get() {
return Util.getMinimumSequence(sequences); // 取序列器組中值最小的
}
代碼"disruptor.handleEventsWith(new DataEventHandler("dataEventHandler1")).thenHandleEventsWithWorkerPool(new DataWorkHandler("dataWorkHandler3"));"中:
創建EventHandler
消費者的ProcessingSequenceBarrier
傳入“barrierSequences” 爲空數組, 所以它就直接受限於生產序列器。
WorkHandler
每一個消費者都被封裝爲接口EventProcessor
的實例類WorkProcessor
,多個消費者存儲在WorkerPool
內的數組裏並共用一個workSequence
。由WorkerPool
構建消費者信息對象ConsumerInfo
的實例是WorkerPoolInfo
。
n WorkHandler
: n WorkProcessor
: 1 WorkerPool
: 1 WorkerPoolInfo
// Disruptor
EventHandlerGroup<T> createWorkerPool(final Sequence[] barrierSequences, final WorkHandler<? super T>[] workHandlers)
{
final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(barrierSequences);
// 多個WorkHandler消費者組合在同一個WorkerPool
final WorkerPool<T> workerPool = new WorkerPool<>(ringBuffer, sequenceBarrier, exceptionHandler, workHandlers);
consumerRepository.add(workerPool, sequenceBarrier);
final Sequence[] workerSequences = workerPool.getWorkerSequences();
updateGatingSequencesForNextInChain(barrierSequences, workerSequences);
return new EventHandlerGroup<>(this, consumerRepository, workerSequences);
}
代碼"disruptor.handleEventsWith(new DataEventHandler("dataEventHandler1")).thenHandleEventsWithWorkerPool(new DataWorkHandler("dataWorkHandler3"));"中:
創建WorkHandler
消費者的ProcessingSequenceBarrier
傳入“barrierSequences” 爲前一EventHandler
類型消費者的序列器, 所以它就受限於上一組消費者的消費情況, 以此來達到串行先後的順序控制。
GatingSequences
上述兩種模式的消費者創建時, 都會執行方法updateGatingSequencesForNextInChain
來更新RingBuffer
裏成員變量AbstractSequencer
實例的"gatingSequences"屬性:添入新的“processorSequences”的同時也清除掉上原有的“barrierSequences”
// Disruptor
private void updateGatingSequencesForNextInChain(final Sequence[] barrierSequences, final Sequence[] processorSequences) {
if (processorSequences.length > 0) {
ringBuffer.addGatingSequences(processorSequences);
for (final Sequence barrierSequence : barrierSequences) {
ringBuffer.removeGatingSequence(barrierSequence);
}
consumerRepository.unMarkEventProcessorsAsEndOfChain(barrierSequences);
}
}
因爲在ProcessingSequenceBarrier
的設計邏輯裏體現了消費者的依賴先後順序,所以生產階段的gatingSequences只需要關心最後一組消費者的消費情況就能判定是否可以繼續next生產。
消費者線程的執行
在本文示例代碼中, 多個EventHandler
可以獨立消費同一個事件;所以它們都獨立依賴於生產序列器的生產情況的, 在線程邏輯實現裏直接用生產序列號比對。
接着對於WorkHandler
是競爭消費,所以它們統一封裝成了上層結構WorkerPool
,維護了統一的一個WorkSequence;當多個線程競爭執行時,CAS
方式來給WorkSequence 設值,並更新自己Sequence。此時判定的因素是:依賴上游的消費序列器。
以BatchEventProcessor.processEvents()
爲例。
private void processEvents(){
T event = null;
long nextSequence = sequence.get() + 1L; // 預計消費序列 累加1
while (true) {
try { //通過給控制閥定義的等待策略來判定是否阻塞下一個待分配序列; 返回的是可消費的最大有效序列。
final long availableSequence = sequenceBarrier.waitFor(nextSequence);
if (batchStartAware != null) {
batchStartAware.onBatchStart(availableSequence - nextSequence + 1);
}
// 預計消費序列 小於等於 可消費的最大序列, 則循環消費各個中間序列的事件。
while (nextSequence <= availableSequence) {
event = dataProvider.get(nextSequence);
// 執行從RingBuffer指定序列獲取到的事件
eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
nextSequence++;
}
// 更新已消費序列
sequence.set(availableSequence);
} catch (final TimeoutException e) {
notifyTimeout(sequence.get());
} catch (final AlertException ex){
if (running.get() != RUNNING){ // Disruptor.shutdown()會拋出AlertException 異常
break;
}
} catch (final Throwable ex)
{
// 異常處理
exceptionHandler.handleEventException(ex, nextSequence, event);
sequence.set(nextSequence);
nextSequence++;
}
}
}
- 執行
ProcessingSequenceBarrier.waitFor -> WaitStrategy.waitFor
返回有效的最大可消費序列。這個過程中, 如果分配的下一個可消費序列號next比生產線程還要大則釋放鎖資源等待Condition.await();如果被依賴的上游消費者組最小消費序列號比next要小,則調用靜態方法static void Thread.onSpinWait()
自旋等待(這需要JDK1.9的支持,否則就退化成一個while過程了)。 - 循環消費[next , max可消費序列號] 之間的事件,最後更新當前消費序列器的值爲: max可消費序列號。
- 異常通常交給
ExceptionHandler.handleEventException
處理。