目录
系列索引
- Disruptor源码解析一 Disruptor高性能之道
- Disruptor源码解析二 Sequence相关类解析
- Disruptor源码解析三 RingBuffer解析
- Disruptor源码解析四 消费者的组织串联
- Disruptor源码解析五 消费者的具体实现
- Disruptor源码解析六 示例与性能压测
前言
- 之前介绍了RingBuffer和内部Sequencer的具体实现,disruptor的生产者操作直接用ringBuffer的相关接口调用即可。
- 本节主要解释一下,消费者的主要串联方式。
消费者架构
消费者的组织
一个生产者P1与三个消费者C1、C2、C3,C3的事件处理需要C1与C2先完成。则该模型结构如下:
每个消费者都是异步的,便于并行处理业务(如http或者rpc请求)。
消费者接口
Disruptor类中,添加消费者有4个接口,实际是3种实现方式,分别是EventHandler, EventProcessor,WorkHandler。
public class Disruptor<T>{
// 添加并行消费者,每一个EventHandler都是独立的消费者。 这些消费者是并行关系,彼此无依赖的。
public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers){}
// 添加并行消费者,每一个EventProcessorFactory创建一个EventProcessor映射为一个消费者。 这些消费者之间是并行关系
public final EventHandlerGroup<T> handleEventsWith(final EventProcessorFactory<T>... eventProcessorFactories){}
// 添加并行消费者,每一个EventProcessor映射为一个消费者。 这些消费者之间是并行关系
public EventHandlerGroup<T> handleEventsWith(final EventProcessor... processors){}
// 添加一个多线程的消费者。该消费者会将事件分发到各个WorkHandler。每一个事件只会被其中一个WorkHandler处理。
public final EventHandlerGroup<T> handleEventsWithWorkerPool(final WorkHandler<T>... workHandlers){}
}
public interface EventHandler<T>{
/**
* {@link BatchEventProcessor}会批量的从RingBuffer中取出数据,然后逐个调用该方法进行处理
*
* 警告:如果在处理事件时抛出异常,而没有指定{@link ExceptionHandler}时,会导致BatchEventProcessor停止工作,可能导致死锁!
* -> 系统默认的异常处理{@link FatalExceptionHandler}会将异常包装为RuntimeException重新抛出,直接退出循环吗,会导致死锁。
*
* 这样的好处是,你可以降低一些操作的消耗,可以攒到批量数据的结尾时进行一次操作。
* 如IO操作,对写复制容器的操作(写入时尽量将多次写入合并为一次写入)。
* @param event published to the {@link RingBuffer} 序号对应的事件数据
* @param sequence of the event being processed 序号
* @param endOfBatch flag to indicate if this is the last event in a batch from the {@link RingBuffer}
* 是否是本次批处理的最后一个
* @throws Exception if the EventHandler would like the exception handled further up the chain.
*/
void onEvent(T event, long sequence, boolean endOfBatch) throws Exception;
}
/**
* 事件处理器(EventHandler的代理对象)
* 一个事件处理器实现Runnable接口,在轮询时使用适当的等待策略(WaitStrategy)从RingBuffer中轮询获取可用事件(拉取数据)。
* 你最好不实现该接口而是优先使用EventHandler接口和BatchEventProcessor。
*
* 划重点:
* 1.事件处理器是最小的事件处理单元,继承Runnable接口,是一个无限执行的任务(轮询监听),在运行时不会让出线程,因此每一个事件处理器需要独立的线程。
* 2.一个消费者中可能只有一个事件处理器(BatchEventProcessor),也可能有多个事件处理器(WorkPool)。
* 3.BatchEventProcessor既是事件处理器,也是消费者。
* WorkProcessor是事件处理器,但不是消费者,WorkPool才是消费者。
* 4.管理消费者,其实也是管理消费们的所有事件处理器。
* 5.每一个事件处理器都有自己独立的Sequence(进度),如果是多个事件处理器协作的话,这些处理器之间会进行同步。
*/
public interface EventProcessor extends Runnable
{
/**
* 获取事情处理器的Sequence(进度),每一个事件处理器有自己独立的Sequence,
* @return reference to the {@link Sequence} for this {@link EventProcessor}
*/
Sequence getSequence();
/**
* 通知事件处理器在完成本次消费之后,暂停下来。协作指令(类似中断)
*/
void halt();
/**
* 查询事件处理器是否运行中
*/
boolean isRunning();
}
/**
* 事件处理器工厂
*/
public interface EventProcessorFactory<T>
{
EventProcessor createEventProcessor(RingBuffer<T> ringBuffer, Sequence[] barrierSequences);
}
/**
* 它是{@link WorkProcessor}处理事件的实现,两者之间是组合关系,{@link WorkProcessor}负责跟踪和拉取事件,{@link WorkHandler}负责处理事件。
* 手动加粗:{@link WorkHandler}不是消费者。
*/
public interface WorkHandler<T>{
void onEvent(T event) throws Exception;
}
可以看到,有3中消费者接口
- EventHandler 就是一个最简单的接口,被EventProcessor代理。
- EventProcessor是一个具体的消费者,可中断,实现类有
- BatchEventProcessor: 单线程批处理消费者,一次添加多个时每个event会被所有的消费者消费。
- WorkProcessor: WorkPool消费者里面的事件处理单元,不是消费者,只是一个消费者里面的一个工作单元, 多个WorkProcessor协作构成WorkPool消费者。一次添加多个时,每个event只会被一个process消费。
- WorkHandler: WorkPool 里的处理接口,WorkProcessor负责跟踪和拉取事件,WorkHandler负责处理事件。
具体下来其实有两种消费者工作模式: 单线程批处理模式(类比多个consumerGroup) 以及 workPool模式(类比一个consumerGroup)。消费者的具体实现放在下一章节分享,本节主要分享如何链式组织消费者,这一块的实现主要依赖EventHandlerGroup。
消费者的串行与并行
并行
消费者的并行实现比较简单,通过handleEventsWith 参数为EventHandler,EventProcessor 或者EventProcessorFactory的方法都是添加的多个单线程批处理消费者,这些消费者是并行的,即每一个event走到这一层(其实是指EventHandlerGroup)都会被所有的消费者消费一遍。
也可以通过EventHandlerGroup的add方法实现并行。
串行
Disrutor的handleEventsWith返回的对象都是EventHandlerGroup,其实就是把当前传入的所有消费者,当成了串行流程的一个节点,这个节点的名称叫做EventHandlerGroup。
之前的章节还有分享过SequenceBarrier的概念,每个串行节点前必须有一个SequenceBarrier,来控制能不能消费,第一个EventHandlerGroup节点的SequenceBarrier是生产者的游标,之后每一个串行的EventHandlerGroup依赖的SequenceBarrier都是前一个节点的最小消费Sequence。
Disruptor代码分享如下(以添加eventHandler为例):
public class Disruptor<T>{
public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)
{
return createEventProcessors(new Sequence[0], handlers);
}
/**
* 创建事件处理器(创建BatchEventProcessor消费者)
* @param barrierSequences 屏障sequences,消费者的消费进度需要慢于它的前驱消费者
* @param eventHandlers 事件处理方法 每一个EventHandler都会被包装为{@link BatchEventProcessor}(一个独立的消费者).
* @return
*/
EventHandlerGroup<T> createEventProcessors(
final Sequence[] barrierSequences,
final EventHandler<? super T>[] eventHandlers)
{
// 组织消费者之间的关系只能在启动之前
checkNotStarted();
// 收集添加的消费者的序号
final Sequence[] processorSequences = new Sequence[eventHandlers.length];
// 本批次消费由于添加在同一个节点之后,因此共享该屏障
final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);
// 创建单线程消费者(BatchEventProcessor)
for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++)
{
final EventHandler<? super T> eventHandler = eventHandlers[i];
final BatchEventProcessor<T> batchEventProcessor =
new BatchEventProcessor<>(ringBuffer, barrier, eventHandler);
if (exceptionHandler != null)
{
batchEventProcessor.setExceptionHandler(exceptionHandler);
}
// 添加到消费者信息仓库中
consumerRepository.add(batchEventProcessor, eventHandler, barrier);
processorSequences[i] = batchEventProcessor.getSequence();
}
// 更新网关序列(生产者只需要关注所有的末端消费者节点的序列)
updateGatingSequencesForNextInChain(barrierSequences, processorSequences);
return new EventHandlerGroup<>(this, consumerRepository, processorSequences);
}
/**
* 更新网关序列(当消费者链后端添加新节点时)
* @param barrierSequences 新节点依赖的网关序列(屏障序列),这些序列有了后继节点,就不再是网关序列了
* @param processorSequences 新增加的节点的序列,新增的在消费者链的末端,因此它们的序列就是新增的网关序列
*/
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);
}
}
}
EventHandlerGroup代码分享如下,可以看到,内部存入了当前消费者的所有Sequence,用来创建下一个节点的SequenceBarrier,串联动作通过then实现,并联动作通过add实现:
/**
* 事件处理器组,作为Disruptor构成中的一部分。
* <b>这个类很重要</b>
*
* 用于组织消费者之间的依赖关系。
* 建立消费者之间的依赖其实也就是建立消费者与前驱节点的Sequence之间的依赖
* 它会建立依赖消费者之间的依赖,也就是Barrier中的dependentSequence的由来。
*/
public class EventHandlerGroup<T>
{
/**
* 方便回调,用于创建具有依赖关系的消费者
* {@link Disruptor#createEventProcessors(Sequence[], EventHandler[])}
* {@link Disruptor#createEventProcessors(Sequence[], EventProcessorFactory[])}
*
*/
private final Disruptor<T> disruptor;
/**
* 所有消费者的信息,方便增加和查询
* (包含所有EventHandler的信息)
*/
private final ConsumerRepository<T> consumerRepository;
/**
* 当前EventHandlerGroup拥有的所有Sequence。
* 也隐含的表示了EventHandlerGroup所代表的所有消费者。
* 也就是EventHandlerGroup的所有EventHandler的后继消费者的依赖Sequences
* 其它代码里面的 dependentSequence / barrierSequences / sequencesToTrack 其实就是它啦。
*/
private final Sequence[] sequences;
EventHandlerGroup(
final Disruptor<T> disruptor,
final ConsumerRepository<T> consumerRepository,
final Sequence[] sequences)
{
this.disruptor = disruptor;
this.consumerRepository = consumerRepository;
this.sequences = Arrays.copyOf(sequences, sequences.length);
}
/**
* 创建一个合并了给定group的新的EventHandlerGroup。
* 用于建立消费者与合并后的group的sequence的依赖。
*/
public EventHandlerGroup<T> and(final EventHandlerGroup<T> otherHandlerGroup)
{
final Sequence[] combinedSequences = new Sequence[this.sequences.length + otherHandlerGroup.sequences.length];
System.arraycopy(this.sequences, 0, combinedSequences, 0, this.sequences.length);
System.arraycopy(
otherHandlerGroup.sequences, 0,
combinedSequences, this.sequences.length, otherHandlerGroup.sequences.length);
return new EventHandlerGroup<>(disruptor, consumerRepository, combinedSequences);
}
public EventHandlerGroup<T> and(final EventProcessor... processors)
{
Sequence[] combinedSequences = new Sequence[sequences.length + processors.length];
for (int i = 0; i < processors.length; i++)
{
consumerRepository.add(processors[i]);
combinedSequences[i] = processors[i].getSequence();
}
System.arraycopy(sequences, 0, combinedSequences, processors.length, sequences.length);
return new EventHandlerGroup<>(disruptor, consumerRepository, combinedSequences);
}
/**
* 添加一批EventHandler从RingBuffer中消费事件。
*
* 这些新增的EventHandler只能消费已经被当前EventHandlerGroup代表的所有消费者已经消费的事件。
*
* 这个方法对于构建链式消费来说很有用,会确立明确的先后顺序。
*/
@SafeVarargs
public final EventHandlerGroup<T> then(final EventHandler<? super T>... handlers)
{
return handleEventsWith(handlers);
}
/**
* 利用EventProcessorFactory添加一批EventProcessor从RingBuffer中消费数据。
* 这些新增的Processor只能消费已经被当前EventHandlerGroup代表的所有消费者已经消费的事件。
*
* 这个方法对于构建链式消费来说很有用,会确立明确的先后顺序。
*/
@SafeVarargs
public final EventHandlerGroup<T> then(final EventProcessorFactory<T>... eventProcessorFactories)
{
return handleEventsWith(eventProcessorFactories);
}
/**
* 创建一个WorkerPool消费从RingBuffer中消费事件。
* WorkerPool只会消费已经被当前EventHandlerGroup所代表的所有消费者已经消费的事件。
* 且每一个事件只会被WokerPool中的一个WorkHandler处理。
*
* 这个方法对于构建链式消费来说很有用,会确立明确的先后顺序。
*/
@SafeVarargs
public final EventHandlerGroup<T> thenHandleEventsWithWorkerPool(final WorkHandler<? super T>... handlers)
{
return handleEventsWithWorkerPool(handlers);
}
/**
* 添加一批EventHandler从RingBuffer中消费事件。
*
* 这些新增的EventHandler只能消费已经被当前EventHandlerGroup代表的所有消费者已经消费的事件。
* 这个方法对于构建链式消费来说很有用,会确立明确的先后顺序。
*/
@SafeVarargs
public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)
{
return disruptor.createEventProcessors(sequences, handlers);
}
/**
*
* 利用EventProcessorFactory添加一批EventProcessor从RingBuffer中消费数据。
* 这些新增的Processor只能消费已经被当前EventHandlerGroup代表的所有消费者已经消费的事件。
*
* 这个方法对于构建链式消费来说很有用,会确立明确的先后顺序。
*/
@SafeVarargs
public final EventHandlerGroup<T> handleEventsWith(final EventProcessorFactory<T>... eventProcessorFactories)
{
return disruptor.createEventProcessors(sequences, eventProcessorFactories);
}
/**
* 创建一个WorkerPool消费从RingBuffer中消费事件。
* WorkerPool只会消费已经被当前EventHandlerGroup所代表的所有消费者已经消费的事件。
* 且每一个事件只会被WokerPool中的一个WorkHandler处理。
*
* 这个方法对于构建链式消费来说很有用,会确立明确的先后顺序。
*/
@SafeVarargs
public final EventHandlerGroup<T> handleEventsWithWorkerPool(final WorkHandler<? super T>... handlers)
{
return disruptor.createWorkerPool(sequences, handlers);
}
/**
* Create a dependency barrier for the processors in this group.
*/
public SequenceBarrier asSequenceBarrier()
{
return disruptor.getRingBuffer().newBarrier(sequences);
}
}