前言
Disruptor的高性能,是多种技术结合以及本身架构的结果。本文主要讲源码,涉及到的相关知识点需要读者自行去了解,以下列出:
- 锁和CAS
- 伪共享和缓存行
- volatile和内存屏障
原理
此节结合demo来看更容易理解:传送门
下图来自官方文档
官方原图有点乱,我翻译一下
在讲原理前,先了解 Disruptor 定义的术语
-
Event
存放数据的单位,对应 demo 中的
LongEvent
-
Ring Buffer
环形数据缓冲区:这是一个首尾相接的环,用于存放 Event ,用于生产者往其存入数据和消费者从其拉取数据
-
Sequence
序列:用于跟踪进度(生产进度、消费进度)
-
Sequencer
Disruptor的核心,用于在生产者和消费者之间传递数据,有单生产者和多生产者两种实现。
-
Sequence Barrier
序列屏障,消费者之间的依赖关系就靠序列屏障实现
-
Wait Strategy
-
等待策略,消费者等待生产者将发布的策略
-
Event Processor
事件处理器,循环从 RingBuffer 获取 Event 并执行 EventHandler。
-
Event Handler
事件处理程序,也就是消费者
-
Producer
生产者
Ring Buffer
环形数据缓冲区(RingBuffer),逻辑上是首尾相接的环,在代码中用数组来表示Object[]
。Disruptor生产者发布分两步
- 步骤一:申请写入 n 个元素,如果可以写入,这返回最大序列号
- 步骤二:根据序列号去 RingBuffer 中获取 Event,修改并发布
RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
// 获取下一个可用位置的下标(步骤1)
long sequence = ringBuffer.next();
try {
// 返回可用位置的元素
LongEvent event = ringBuffer.get(sequence);
// 设置该位置元素的值
event.set(l);
} finally {
// 发布
ringBuffer.publish(sequence);
}
复制代码
这两个步骤由 Sequencer 完成,分为单生产者和多生产者实现
Sequencer
单生产者
如果申请 2 个元素,则如下图所示(圆表示 RingBuffer)
// 一般不会有以下写法,这里为了讲解源码才使用next(2)
// 向RingBuffer申请两个元素
long sequence = ringBuffer.next(2);
for (long i = sequence-1; i <= sequence; i++) {
try {
// 返回可用位置的元素
LongEvent event = ringBuffer.get(i);
// 设置该位置元素的值
event.set(1);
} finally {
ringBuffer.publish(i);
}
}
复制代码
next 申请成功的序列,cursor 消费者最大可用序列,gatingSequence 表示能申请的最大序列号。红色表示待发布,绿色表示已发布。申请相当于占位置,发布需要一个一个按顺序发布
如果 RingBuffer 满了呢,在上图步骤二的基础上,生产者发布了3个元素,消费者消费1个。此时生产者再申请 2个元素,就会变成下图所示
只剩下 1 个空间,但是要申请 2个元素,此时程序会自旋等待空间足够。
接下来结合代码看,单生产者的 Sequencer 实现为 SingleProducerSequencer,先看看构造方法
abstract class SingleProducerSequencerPad extends AbstractSequencer
{
protected long p1, p2, p3, p4, p5, p6, p7;
SingleProducerSequencerPad(int bufferSize, WaitStrategy waitStrategy)
{
super(bufferSize, waitStrategy);
}
}
abstract class SingleProducerSequencerFields extends SingleProducerSequencerPad
{
SingleProducerSequencerFields(int bufferSize, WaitStrategy waitStrategy)
{
super(bufferSize, waitStrategy);
}
long nextValue = Sequence.INITIAL_VALUE;
long cachedValue = Sequence.INITIAL_VALUE;
}
public final class SingleProducerSequencer extends SingleProducerSequencerFields
{
protected long p1, p2, p3, p4, p5, p6,