基本知识
序列生产器Sequencer
RingBuffer
本质上是一个环状数组,数组大小固定。但是序列号会不断增加,然后取模得到数组下标,覆盖原有的数据。这样就可以无限增长。当生产者生产速度快于消费者时,要等待。。同理,消费者超前后,也要等待。。所有的消费和生产都依赖这个唯一的序列号。 序列生产器,分别有MultiProducerSequencer 和 SingleProducerSequencer两个实现类。在AbstractSequencer中,维护了消费者的Sequence(序列对象)和生产者自己的Sequence(序列对象);以及维护了生产者与消费者序列冲突时候的等待策略WaitStrategy;
public interface Sequenced {
int getBufferSize();//数据结构中事件槽的个数(就是RingBuffer的容量)
boolean hasAvailableCapacity(int var1);//判断是否还有给定的可用容量
long remainingCapacity();//获取剩余容量
long next();//申请下一个序列值,用来发布事件
long next(int var1);//申请n个序列值
//尝试申请下一个序列值用来发布事件,这个是无阻塞的方法。所谓的无阻塞就是 申请之前调hasAvailableCapacity判断能否申请,若不,直接扔异常出来
long tryNext() throws InsufficientCapacityException;
long tryNext(int var1) throws InsufficientCapacityException;
void publish(long var1);//在给定的序列值上发布事件,当填充好事件后会调用这个方法
void publish(long var1, long var3);
}
//Cursored接口很简单,只提供一个获取当前序列值的方法
public interface Cursored {
long getCursor();
}
//序列生产器(框架中针对序列的使用,提供了专门的接口)
//Sequencer接口的很多功能是提供给事件发布者用的。通过Sequencer可以得到一个SequenceBarrier,是提供给事件处理者用的
public interface Sequencer extends Cursored, Sequenced {
long INITIAL_CURSOR_VALUE = -1L;//序列初始值
void claim(long var1);//声明一个序列,这个方法在初始化RingBuffer的时候被调用
boolean isAvailable(long var1);//判断一个序列是否被发布,并且发布到序列上的事件是可处理的。非阻塞方法。
//这些控制序列一般是其他组件的序列,当前实例可以通过这些序列来查看其他组件的序列使用情况。
void addGatingSequences(Sequence... var1);
boolean removeGatingSequence(Sequence var1);
//基于给定的追踪序列创建一个序列栅栏,这个栅栏是提供给消费者在判断Ringbuffer上某个事件是否能处理时使用的
SequenceBarrier newBarrier(Sequence... var1);
long getMinimumSequence();
long getHighestPublishedSequence(long var1, long var3);
<T> EventPoller<T> newPoller(DataProvider<T> var1, Sequence... var2);
}
复制代码
生产者怎么生产的
生产者生产时并不是直接与RingBuffer
交互,而是通过控制Sequencer
从而控制ringbuffer
来进行交互。比如:先要获取一个序列号,然后填充,再发布。
//**单个生产者case**
// this.ringBuffer = disruptor.start();//这里会返回一个ringBuffer
long sequence = ringBuffer.next();//拿序列
TreasureEvent event = ringBuffer.get(sequence);
ringBuffer.publish(sequence);//发布
//源码
public long next() {//ringBuffer中拿序列。到序列管理器中拿。走到序列管理器的实现类SingleProducerSequencer
return this.sequencer.next();
}
public long next() {
return this.next(1);
}
public long next(int n) {
if(n < 1) {
throw new IllegalArgumentException("n must be > 0");
} else {
long nextValue = this.nextValue;//生产者序列当前的位置
long nextSequence = nextValue + (long)n;//nextSequence生产者序列下一步要到的位置
long wrapPoint = nextSequence - (long)this.bufferSize;
long cachedGatingSequence = this.cachedValue;//事件处理者申请的序列值
if(wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue) {
//想象一个环,发布者怎么才能申请到一个序列呢
//发布者申请的序列值大于处理者之前的序列值 发布者要申请的序列值减去环的长度要小于事件处理者的序列值
this.cursor.setVolatile(nextValue);
long minSequence;
while(wrapPoint > (minSequence = Util.getMinimumSequence(this.gatingSequences, nextValue))) {
this.waitStrategy.signalAllWhenBlocking();
LockSupport.parkNanos(1L);//不能申请的时候阻塞一下
}
this.cachedValue = minSequence;
}
this.nextValue = nextSequence;
return nextSequence;
}
}
复制代码
//多个生产者
public final class MultiProducerSequencer extends AbstractSequencer {
private static final Unsafe UNSAFE = Util.getUnsafe();
private static final long BASE;
private static final long SCALE;
private final Sequence gatingSequenceCache = new Sequence(-1L);//用来标识事件处理者的序列
private final int[] availableBuffer;//用来标示每个槽(数组位置)的状态
private final int indexMask;
private final int indexShift;
public MultiProducerSequencer(int bufferSize, WaitStrategy waitStrategy) {
super(bufferSize, waitStrategy);//初始化父类
this.availableBuffer = new int[bufferSize];//初始化availableBuffer
this.indexMask = bufferSize - 1;
this.indexShift = Util.log2(bufferSize);
this.initialiseAvailableBuffer();
}
public long next(int n) {
if(n < 1) {
throw new IllegalArgumentException("n must be > 0");
} else {
long current;
long next;
do {
while(true) {
//获取事件发布者发布序列
current = this.cursor.get();
next = current + (long)n; //新序列位置
long wrapPoint = next - (long)this.bufferSize;//代表申请的序列绕一圈以后的位置
//获取事件处理者处理到的序列值
long cachedGatingSequence = this.gatingSequenceCache.get();
/* 1.事件发布者要申请的序列值大于事件处理者当前的序列值且事件发布者要申请的序列值减去环的长度要小于事件处 理者的序列值。2.满足(1),可以申请给定的序列。 3.不满足(1),就需要查看一下当前事件处理者的最小的序列值(可能有多个事件处理者)。如果最小序列值大于等于 当前事件处理者的最小序列值大了一圈,那就不能申请了序列(申请了就会被覆盖)*/
//wrapPoint > cachedGatingSequence 代表绕一圈并且位置大于事件处理者处理到的序列
//cachedGatingSequence > current 说明事件发布者的位置位于事件处理者的后面
if(wrapPoint <= cachedGatingSequence && cachedGatingSequence <= current) {
break;
}
//获取最小的事件处理者序列
long gatingSequence = Util.getMinimumSequence(this.gatingSequences, current);
if(wrapPoint > gatingSequence) {
this.waitStrategy.signalAllWhenBlocking();
LockSupport.parkNanos(1L);
} else {
this.gatingSequenceCache.set(gatingSequence);
}
}
} while(!this.cursor.compareAndSet(current, next));
return next;
}
}
复制代码
单生产者和多生产者的区别:
1:SingleProducerSequencer内部维护cachedValue(事件消费者序列),nextValue(事件发布者序列)。并且采用padding填充。这个类是线程不安全的。 2:MultiProducerSequencer每次获取序列都是从Sequence中获取的。Sequence中针对value的操作都是原子的。
3: 怎么防止多个生产者获取的是一个序列?
public long tryNext(int n) throws InsufficientCapacityException
{
if (n < 1)
{
throw new IllegalArgumentException("n must be > 0");
}
long current;
long next;
do
{
current = cursor.get();
next = current + n;
if (!hasAvailableCapacity(gatingSequences, n, current))
{
throw InsufficientCapacityException.INSTANCE;
}
}
while (!cursor.compareAndSet(current, next));
return next;
}
//通过do/while循环的条件cursor.compareAndSet(current, next),来判断每次申请的空间是否已经被其他生产者占据。假如已经被占据,该函数会返回失败,While循环重新执行,申请写入空间。
复制代码
数据中心RingBuffer
作为生产者和消费者的枢纽,本质可以理解为一个队列。
我们先看下内部结构
EventSequencer扩展了Sequenced,提供了一些序列功能;同时扩展了DataProvider,提供了按序列值来获取数据的功能。
EventSink主要是提供发布事件(就是往队列上放数据)的功能,接口上定义了以各种姿势发布事件的方法。
通过上面的接口,我们大致了解了RingBuffer的功能。 现在我们看下内部结构
1.底层用数组实现,数据大小是2的幂;
2.环形能覆盖,避免GC带来性能损耗;
3.与常规RingBuffer拥有2个首尾指针的方式不同,Disruptor的RingBuffer只有一个指针(或称序号),指向数组下一个可写入的位置,该序号在Disruptor源码中就是Sequencer中的cursor,由生产者通过Sequencer控制RingBuffer的写入。为了避免未消费事件的写入覆盖,Sequencer需要监听所有消费者的消息处理进度,也就是gatingSequences。RingBuffer通过这种方式实现了事件缓存的无锁设计。
消费者如何消费的
消费者并不直接与环交互而是通过序列栅栏来与环交互
sequenceBarrier
向环获取序列号,然后消费。这里涉及订阅模式和依赖模式。
//事件处理
//等ringbuffer中的事件变的可处理时,开始处理。一个事件处理器关联一个线程
public interface EventProcessor extends Runnable {
Sequence getSequence();
void halt();
boolean isRunning();
}
//看一个事件处理的实现
public final class BatchEventProcessor<T> implements EventProcessor {
//表示当前事件处理器的运行状态
private final AtomicBoolean running = new AtomicBoolean(false);
//异常处理器
private ExceptionHandler<? super T> exceptionHandler = new FatalExceptionHandler();
private final DataProvider<T> dataProvider; //数据提供者。(RingBuffer)
private final SequenceBarrier sequenceBarrier; //序列栅栏
private final EventHandler<? super T> eventHandler; //真正处理事件的回调接口。
private final Sequence sequence = new Sequence(-1L);//事件处理器使用的序列。
private final TimeoutHandler timeoutHandler;//超时处理器。
//用构造函数来初始上面的值
public BatchEventProcessor(DataProvider<T> dataProvider, SequenceBarrier sequenceBarrier, EventHandler<? super T> eventHandler) {
this.dataProvider = dataProvider;
this.sequenceBarrier = sequenceBarrier;
this.eventHandler = eventHandler;
if(eventHandler instanceof SequenceReportingEventHandler) {
((SequenceReportingEventHandler)eventHandler).setSequenceCallback(this.sequence);
}
this.timeoutHandler = eventHandler instanceof TimeoutHandler?(TimeoutHandler)eventHandler:null;
}
//实现的方法
public Sequence getSequence() {
return this.sequence;
}
public void halt() {
this.running.set(false);//设置运行状态为false。
this.sequenceBarrier.alert(); //通知序列栅栏。
}
public boolean isRunning() {
return this.running.get();
}
//重点
public void run() {
if(!this.running.compareAndSet(false, true)) {//当前处理器状态的判断
throw new IllegalStateException("Thread is already running");
} else {
this.sequenceBarrier.clearAlert(); //先清除序列栅栏的通知状态。
this.notifyStart(); //如果eventHandler实现了LifecycleAware,这里会对其进行一个启动通知。
T event = null;
long nextSequence = this.sequence.get() + 1L;//获取要申请的序列值。
try {
while(true) {
try {
long availableSequence; //通过序列栅栏来等待可用的序列值。
for(availableSequence = this.sequenceBarrier.waitFor(nextSequence); nextSequence <= availableSequence; ++nextSequence) {//获取事件。
event = this.dataProvider.get(nextSequence);
//将事件交给eventHandler处理。
this.eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
}
//处理完毕后,设置当前处理完成的最后序列值。
this.sequence.set(availableSequence);
} catch (TimeoutException var11) {
//如果发生超时,通知一下超时处理器(如果eventHandler同时实现了timeoutHandler,会将其设置为当前的超时处理器)
this.notifyTimeout(this.sequence.get());
} catch (AlertException var12) {
//如果捕获了序列栅栏变更通知,并且当前事件处理器停止了,那么退出主循环。
if(!this.running.get()) {
return;
}
} catch (Throwable var13) {
//其他的异常都交给异常处理器进行处理。
this.exceptionHandler.handleEventException(var13, nextSequence, event);
//处理异常后仍然会设置当前处理的最后的序列值,然后继续处理其他事件。
this.sequence.set(nextSequence);
++nextSequence;
}
}
} finally {
//主循环退出后,如果eventHandler实现了LifecycleAware,这里会对其进行一个停止通知。
this.notifyShutdown();
//设置事件处理器运行状态为停止。
this.running.set(false);
}
}
}
//从上面可以看出:BatchEventProcessor内部会记录自己消费的序列、运行状态。需要外界输入的是:RingBuffer,sequenceBarrier,事件处理器
// BatchEventProcessor是一个线程任务。实际处理是一个线程来处理一批任务。那能不能用多个线程共同处理一批任务呢?看下EventProcessor处理的WorkProcessor实现。也即Work模式
复制代码
public final class WorkProcessor<T> implements EventProcessor {
private final AtomicBoolean running = new AtomicBoolean(false);
private final Sequence sequence = new Sequence(-1L);
private final RingBuffer<T> ringBuffer;
private final SequenceBarrier sequenceBarrier;
private final WorkHandler<? super T> workHandler;
private final ExceptionHandler<? super T> exceptionHandler;
private final Sequence workSequence;
private final EventReleaser eventReleaser = new EventReleaser() {
public void release() {
WorkProcessor.this.sequence.set(9223372036854775807L);
}
};
private final TimeoutHandler timeoutHandler;
public WorkProcessor(RingBuffer<T> ringBuffer, SequenceBarrier sequenceBarrier, WorkHandler<? super T> workHandler, ExceptionHandler<? super T> exceptionHandler, Sequence workSequence) {
this.ringBuffer = ringBuffer;//外部提供
this.sequenceBarrier = sequenceBarrier;//外部提供
this.workHandler = workHandler;//外部提供
this.exceptionHandler = exceptionHandler;//外部提供
this.workSequence = workSequence;//外部提供
if(this.workHandler instanceof EventReleaseAware) {
((EventReleaseAware)this.workHandler).setEventReleaser(this.eventReleaser);
}
this.timeoutHandler = workHandler instanceof TimeoutHandler?(TimeoutHandler)workHandler:null;
}
//看下属性,和BatchEventProcessor基本差不多。多了workSequence和exceptionHandler需要外部提供。
//我们主要看下run()的实现
public void run() {
//状态设置与检测
if(!this.running.compareAndSet(false, true)) {
throw new IllegalStateException("Thread is already running");
} else {
this.sequenceBarrier.clearAlert();
this.notifyStart();
boolean processedSequence = true;
long cachedAvailableSequence = -9223372036854775808L;
long nextSequence = this.sequence.get();
Object event = null;
while(true) {
while(true) {
try { //判断上一个事件是否已经处理完毕。
if(processedSequence) {
processedSequence = false;
do { //原子的获取下一要处理事件的序列值。
nextSequence = this.workSequence.get() + 1L;
this.sequence.set(nextSequence - 1L);
} while(!this.workSequence.compareAndSet(nextSequence - 1L, nextSequence));
}
//检查序列值是否需要申请。这一步是为了防止和事件生产者冲突。
if(cachedAvailableSequence >= nextSequence) {
event = this.ringBuffer.get(nextSequence);//从RingBuffer上获取事件
this.workHandler.onEvent(event);//委托给workHandler处理事件。
processedSequence = true;//设置事件处理完成标识。
} else { //如果需要申请,通过序列栅栏来申请可用的序列。
cachedAvailableSequence = this.sequenceBarrier.waitFor(nextSequence);
}
} catch (TimeoutException var8) {
this.notifyTimeout(this.sequence.get());
} catch (AlertException var9) {
if(!this.running.get()) {
this.notifyShutdown();
this.running.set(false);
return;
}
} catch (Throwable var10) {
this.exceptionHandler.handleEventException(var10, nextSequence, event);
processedSequence = true;
}
}
}
}
}
//work模式是多个处理器(WorkProcessor))处理一批任务,那么就会存在多个处理器(WorkProcessor))竞争一个任务。利用workSequence,所有处理者都使用这一个workSequence,通过对workSequence的原子处理,来保证不会处理相同的事件
复制代码
//事件处理者如何等待发布者发布事件
//生产者维护一个Squence(这个Squence消费者也持有。消费者会每次消费都会去更新这个值)。生产者生产时会拿到当前队列的Cursor,生产好时,更新Cursor.那么消费者再消费时会得到当前的Cursor,然后再进行消费.
//Cursor表示生产到哪里了。Squence表示消费到哪里了。
//参考
https://brokendreams.iteye.com/blog/2255720
https://blog.csdn.net/zhxdick/article/category/6121943
https://in355hz.iteye.com/blog/1797829
https://yq.aliyun.com/articles/553297
复制代码
对用户提供交互Disruptor
public class Disruptor<T> {
private final RingBuffer<T> ringBuffer;
private final Executor executor;//消费者处理线程池
private final ConsumerRepository<T> consumerRepository;
private final AtomicBoolean started;
private ExceptionHandler<? super T> exceptionHandler;//消费者事件异常处理方法
//上面几个属性通过构造方法初始化
public Disruptor(EventFactory<T> eventFactory, int ringBufferSize, ThreadFactory threadFactory) {
this(RingBuffer.createMultiProducer(eventFactory, ringBufferSize), new BasicExecutor(threadFactory));
}
public Disruptor(EventFactory<T> eventFactory, int ringBufferSize, ThreadFactory threadFactory, ProducerType producerType, WaitStrategy waitStrategy) {
this(RingBuffer.create(producerType, eventFactory, ringBufferSize, waitStrategy), new BasicExecutor(threadFactory));
}
//最终用这个函数给ringBuffer,executor赋值
private Disruptor(RingBuffer<T> ringBuffer, Executor executor) {
this.consumerRepository = new ConsumerRepository();
this.started = new AtomicBoolean(false);
this.exceptionHandler = new ExceptionHandlerWrapper();
this.ringBuffer = ringBuffer;
this.executor = executor;
}
//上面我们构建好了事件队列了,那么现在看看如何构建事件处理者呢
public EventHandlerGroup<T> handleEventsWith(EventHandler... handlers) {
return this.createEventProcessors(new Sequence[0], handlers);
}
EventHandlerGroup<T> createEventProcessors(Sequence[] barrierSequences, EventHandler<? super T>[] eventHandlers) {
this.checkNotStarted();
Sequence[] processorSequences = new Sequence[eventHandlers.length];
SequenceBarrier barrier = this.ringBuffer.newBarrier(barrierSequences);
int i = 0;
for(int eventHandlersLength = eventHandlers.length; i < eventHandlersLength; ++i) {
EventHandler<? super T> eventHandler = eventHandlers[i];
BatchEventProcessor<T> batchEventProcessor = new BatchEventProcessor(this.ringBuffer, barrier, eventHandler);
if(this.exceptionHandler != null) {
batchEventProcessor.setExceptionHandler(this.exceptionHandler);
}
this.consumerRepository.add(batchEventProcessor, eventHandler, barrier);
processorSequences[i] = batchEventProcessor.getSequence();
}
this.updateGatingSequencesForNextInChain(barrierSequences, processorSequences);
return new EventHandlerGroup(this, this.consumerRepository, processorSequences);
}
}
复制代码