目录
blockingQueue VS disruptor多模式对比
系列索引
- Disruptor源码解析一 Disruptor高性能之道
- Disruptor源码解析二 Sequence相关类解析
- Disruptor源码解析三 RingBuffer解析
- Disruptor源码解析四 消费者的组织串联
- Disruptor源码解析五 消费者的具体实现
- Disruptor源码解析六 示例与性能压测
前言
- 前面几个章节已经分享了disruptor的最主要的几个组件的主要实现和介绍,这里简单分享一个disruptor的具体使用,以及disruptor的性能对比blockingQueue在各种场景下的性能提升有多大。
- 本节的主要代码分享来自disruptor代码的perftest目录,是官方提供的压测case实现。
- 一般场景下,我们将blockQueue替换为disruptor,会得到极大的吞吐量提升。
perftest结构
上图中未展开的都是,一些实现类或者配置目录,展开的都是具体的压测CASE实现
- offheap ----disruptor堆内堆外内存性能对比测试目录
- queue ----基于blockingQueue实现的生产消费CASE, 用于和disruptor的实现对比
- raw ----只生产不消费(或者消费不处理)的处理记录
- support ----压测case用到的一些配置实现类,主要是event,生产者,消费者的相关实现
- sequenced ---基于disruptor的相关实现的生产消费CASE,与queue目录中的case对比
- translator ----生产者translator的相关压测
- workhandler workPool模式的消费者的相关性能压测
- AbstractPerfTestDisruptor disruptor压测case集成的基类
- AbstractPerfTestQueue blockingQueuey压测case集成的基类
压测CASE示例
perftest的重点应该在blockingQueue与disruptor的吞吐比较,性能指标计算方式为吞吐量,公式:
qps = 处理的消息数 / 处理总时间
在每个压测CASE上,基本都有生产消费的结构图,展示了本case的生产消费结构。
1V1的blockingQueueCase
blockQueue的一个最简单实现(单生产者单消费者):
注释中即说明了本个case的实现。P1(生产者) -> Q1(阻塞队列) -> EP1(消费者)
/**
* <pre>
* UniCast a series of items between 1 publisher and 1 event processor.
*
* +----+ +-----+
* | P1 |--->| EP1 |
* +----+ +-----+
*
* Queue Based:
* ============
*
* put take
* +----+ +====+ +-----+
* | P1 |--->| Q1 |<---| EP1 |
* +----+ +====+ +-----+
*
* P1 - Publisher 1
* Q1 - Queue 1
* EP1 - EventProcessor 1
*
* </pre>
*/
public final class OneToOneQueueThroughputTest extends AbstractPerfTestQueue
{
// BlockingQueue队列大小
private static final int BUFFER_SIZE = 1024 * 64;
// 生产次数
private static final long ITERATIONS = 1000L * 1000L * 10L;
// 消费者线程池
private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);
private final long expectedResult = ITERATIONS * 3L;
///
// 阻塞队列
private final BlockingQueue<Long> blockingQueue = new LinkedBlockingQueue<Long>(BUFFER_SIZE);
// 消费者,内部实现就是阻塞的take方法,当都处理完之后(处理次数等于ITERATIONS - 1),通过countDownLatch,来通知处理完毕
private final ValueAdditionQueueProcessor queueProcessor =
new ValueAdditionQueueProcessor(blockingQueue, ITERATIONS - 1);
///
@Override
protected int getRequiredProcessorCount()
{
return 2;
}
@Override
protected long runQueuePass() throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
queueProcessor.reset(latch);
Future<?> future = executor.submit(queueProcessor);
long start = System.currentTimeMillis();
// 这里就是生产者
for (long i = 0; i < ITERATIONS; i++)
{
blockingQueue.put(3L);
}
// 等待消费者消费完
latch.await();
// 计算吞吐吞吐量
long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);
// 关闭消费者
queueProcessor.halt();
// 关闭线程池
future.cancel(true);
PerfTestUtil.failIf(expectedResult, 0);
return opsPerSecond;
}
public static void main(String[] args) throws Exception
{
OneToOneQueueThroughputTest test = new OneToOneQueueThroughputTest();
test.testImplementations();
}
}
1V1的DisruptorCase
disruptor的一个最简单实现(单生产者单消费者):
注释中即说明了本个case的实现。P1(生产者) -> RB(ringBuffer) -> SB(SequenceBarrier) -> EP1(消费者)
/**
* <pre>
* UniCast a series of items between 1 publisher and 1 event processor.
*
* +----+ +-----+
* | P1 |--->| EP1 |
* +----+ +-----+
*
* Disruptor:
* ==========
* track to prevent wrap
* +------------------+
* | |
* | v
* +----+ +====+ +====+ +-----+
* | P1 |--->| RB |<---| SB | | EP1 |
* +----+ +====+ +====+ +-----+
* claim get ^ |
* | |
* +--------+
* waitFor
*
* P1 - Publisher 1
* RB - RingBuffer
* SB - SequenceBarrier
* EP1 - EventProcessor 1
*
* </pre>
*/
public final class OneToOneSequencedThroughputTest extends AbstractPerfTestDisruptor
{
// ringbuffer大小
private static final int BUFFER_SIZE = 1024 * 64;
// 生产次数
private static final long ITERATIONS = 1000L * 1000L * 100L;
// 消费者线程池
private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);
private final long expectedResult = PerfTestUtil.accumulatedAddition(ITERATIONS);
///
// 下面是disruptor的一些组件
// ringbuffer构造, yield等待策略
private final RingBuffer<ValueEvent> ringBuffer =
createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());
// sequenceBarrier构造, 默认依赖的是生产者
private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();
// 消费者处理器实现, 内部就是一个一个取出,处理
private final ValueAdditionEventHandler handler = new ValueAdditionEventHandler();
// 真实的消费者,代理了上面的消费者处理器
private final BatchEventProcessor<ValueEvent> batchEventProcessor =
new BatchEventProcessor<ValueEvent>(ringBuffer, sequenceBarrier, handler);
{
// 生产者需要依赖最后一个消费者的位置来看能不能生产
ringBuffer.addGatingSequences(batchEventProcessor.getSequence());
}
///
@Override
protected int getRequiredProcessorCount()
{
return 2;
}
@Override
protected long runDisruptorPass() throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
long expectedCount = batchEventProcessor.getSequence().get() + ITERATIONS;
handler.reset(latch, expectedCount);
executor.submit(batchEventProcessor);
long start = System.currentTimeMillis();
final RingBuffer<ValueEvent> rb = ringBuffer;
// 开始生产
for (long i = 0; i < ITERATIONS; i++)
{
long next = rb.next();
rb.get(next).setValue(i);
rb.publish(next);
}
// 等待消费完毕
latch.await();
// 计算吞吐量
long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);
// 消费者退出
waitForEventProcessorSequence(expectedCount);
batchEventProcessor.halt();
PerfTestUtil.failIfNot(expectedResult, handler.getValue());
return opsPerSecond;
}
private void waitForEventProcessorSequence(long expectedCount) throws InterruptedException
{
while (batchEventProcessor.getSequence().get() != expectedCount)
{
Thread.sleep(1);
}
}
public static void main(String[] args) throws Exception
{
OneToOneSequencedThroughputTest test = new OneToOneSequencedThroughputTest();
test.testImplementations();
}
}
blockingQueue VS disruptor多模式对比
下面抛出的qps都是在本地mac上运行官方perftest代码跑出来的,本地配置为:
单生产者单消费者:
* +----+ +-----+
* | P1 |--->| EP1 |
* +----+ +-----+
*
* Queue Based:
* ============
*
* put take
* +----+ +====+ +-----+
* | P1 |--->| Q1 |<---| EP1 |
* +----+ +====+ +-----+
*
* P1 - Publisher 1
* Q1 - Queue 1
* EP1 - EventProcessor 1
* ------------------------------------------
* Disruptor:
* ==========
* track to prevent wrap
* +------------------+
* | |
* | v
* +----+ +====+ +====+ +-----+
* | P1 |--->| RB |<---| SB | | EP1 |
* +----+ +====+ +====+ +-----+
* claim get ^ |
* | |
* +--------+
* waitFor
*
* P1 - Publisher 1
* RB - RingBuffer
* SB - SequenceBarrier
* EP1 - EventProcessor 1
BlockingQueue的Case:
OneToOneQueueThroughputTest
blockingQueue普通单生产者单消费者,生产者依次放入,消费者通过queue.take取数据,消费者执行的操作是加和
3,872,966 ops/sec
OneToOneQueueBatchedThroughputTest
blockingQueue单生产者单消费者,生产者依次放入,消费者批量消费数据,通过queue.drain取数据,消费者执行的操作是加和
7,824,726 ops/sec
Disruptor的Case:
OneToOneSequencedThroughputTest
disruptor普通的单生产者单消费者,生产者依次放入,消费者通过sequenceBarrier.waitFor获取,批量消费,消费者执行的操作是加和
169,491,525 ops/sec
OneToOneSequencedBatchThroughputTest
disruptor普通的单生产者单消费者,生产者批量放入,消费者通过sequenceBarrier.waitFor获取,批量消费,消费者执行的操作是加和
330,250,990 ops/sec
OneToOneSequencedLongArrayThroughputTest
disruptor普通的单生产者单消费者,生产者依次放入,消费者通过sequenceBarrier.waitFor获取,批量消费,消费者内部处理的事消除了伪共享的变量,消费者执行的操作是加和
1,375,419,744 ops/sec
单生产者多消费者(菱形)
* +-----+
* +----->| EP1 |------+
* | +-----+ |
* | v
* +----+ +-----+
* | P1 | | EP3 |
* +----+ +-----+
* | ^
* | +-----+ |
* +----->| EP2 |------+
* +-----+
*
*
* Queue Based:
* ============
* take put
* put +====+ +-----+ +====+ take
* +----->| Q1 |<---| EP1 |--->| Q3 |<------+
* | +====+ +-----+ +====+ |
* | |
* +----+ +====+ +-----+ +====+ +-----+
* | P1 |--->| Q2 |<---| EP2 |--->| Q4 |<---| EP3 |
* +----+ +====+ +-----+ +====+ +-----+
*
* P1 - Publisher 1
* Q1 - Queue 1
* Q2 - Queue 2
* Q3 - Queue 3
* Q4 - Queue 4
* EP1 - EventProcessor 1
* EP2 - EventProcessor 2
* EP3 - EventProcessor 3
*
*
* Disruptor:
* ==========
* track to prevent wrap
* +-------------------------------+
* | |
* | v
* +----+ +====+ +=====+ +-----+
* | P1 |--->| RB |<--------------| SB2 |<---| EP3 |
* +----+ +====+ +=====+ +-----+
* claim ^ get | waitFor
* | |
* +=====+ +-----+ |
* | SB1 |<---| EP1 |<-----+
* +=====+ +-----+ |
* ^ |
* | +-----+ |
* +-------| EP2 |<-----+
* waitFor +-----+
*
* P1 - Publisher 1
* RB - RingBuffer
* SB1 - SequenceBarrier 1
* EP1 - EventProcessor 1
* EP2 - EventProcessor 2
* SB2 - SequenceBarrier 2
* EP3 - EventProcessor 3
BlockingQueue的Case:
OneToThreeDiamondQueueThroughputTest
blockingQueue单生产者,后接3个菱形消费者,共4个blockingQueue
1,700,535 ops/sec
Disruptor的Case:
OneToThreeDiamondSequencedThroughputTest
disruptor单生产者,后接3个菱形消费者,一个ringbuffer解决
142,045,454 ops/sec
单生产者多消费者(串行)
*
* +----+ +-----+ +-----+ +-----+
* | P1 |--->| EP1 |--->| EP2 |--->| EP3 |
* +----+ +-----+ +-----+ +-----+
*
*
* Queue Based:
* ============
*
* put take put take put take
* +----+ +====+ +-----+ +====+ +-----+ +====+ +-----+
* | P1 |--->| Q1 |<---| EP1 |--->| Q2 |<---| EP2 |--->| Q3 |<---| EP3 |
* +----+ +====+ +-----+ +====+ +-----+ +====+ +-----+
*
* P1 - Publisher 1
* Q1 - Queue 1
* EP1 - EventProcessor 1
* Q2 - Queue 2
* EP2 - EventProcessor 2
* Q3 - Queue 3
* EP3 - EventProcessor 3
*------------------------------------------------------
* Disruptor:
* ==========
* track to prevent wrap
* +----------------------------------------------------------------+
* | |
* | v
* +----+ +====+ +=====+ +-----+ +=====+ +-----+ +=====+ +-----+
* | P1 |--->| RB | | SB1 |<---| EP1 |<---| SB2 |<---| EP2 |<---| SB3 |<---| EP3 |
* +----+ +====+ +=====+ +-----+ +=====+ +-----+ +=====+ +-----+
* claim ^ get | waitFor | waitFor | waitFor
* | | | |
* +---------+---------------------+---------------------+
*
* P1 - Publisher 1
* RB - RingBuffer
* SB1 - SequenceBarrier 1
* EP1 - EventProcessor 1
* SB2 - SequenceBarrier 2
* EP2 - EventProcessor 2
* SB3 - SequenceBarrier 3
* EP3 - EventProcessor 3
BlockingQueue的Case:
OneToThreePipelineQueueThroughputTest
blockingQueue,单生产者后接3个串行消费者,共3个blockngQueue
2,195,389 ops/sec
disruptor的Case:
OneToThreePipelineSequencedThroughputTest
disruptor,单生产者后接3个串行消费者,一个ringbuffer
121,065,375 ops/sec
单生产者多消费者(并行)
* +-----+
* +----->| EP1 |
* | +-----+
* |
* +----+ +-----+
* | P1 |--->| EP2 |
* +----+ +-----+
* |
* | +-----+
* +----->| EP3 |
* +-----+
*
*
* Queue Based:
* ============
* take
* put +====+ +-----+
* +----->| Q1 |<---| EP1 |
* | +====+ +-----+
* |
* +----+ +====+ +-----+
* | P1 |--->| Q2 |<---| EP2 |
* +----+ +====+ +-----+
* |
* | +====+ +-----+
* +----->| Q3 |<---| EP3 |
* +====+ +-----+
*
* P1 - Publisher 1
* Q1 - Queue 1
* Q2 - Queue 2
* Q3 - Queue 3
* EP1 - EventProcessor 1
* EP2 - EventProcessor 2
* EP3 - EventProcessor 3
* -------------------------------------------------------------
* Disruptor:
* ==========
* track to prevent wrap
* +--------------------+----------+----------+
* | | | |
* | v v v
* +----+ +====+ +====+ +-----+ +-----+ +-----+
* | P1 |--->| RB |<---| SB | | EP1 | | EP2 | | EP3 |
* +----+ +====+ +====+ +-----+ +-----+ +-----+
* claim get ^ | | |
* | | | |
* +---------+----------+----------+
* waitFor
*
* P1 - Publisher 1
* RB - RingBuffer
* SB - SequenceBarrier
* EP1 - EventProcessor 1
* EP2 - EventProcessor 2
* EP3 - EventProcessor 3
BlockingQueue的Case:
OneToThreeQueueThroughputTest
单生产者,多消费者,每个消费者一个blockingQueue, 执行的操作是加减操作
1,257,861 ops/sec
Disruptor的Case:
OneToThreeSequencedThroughputTest
单生产者,多消费者,一个ringBuffer,每个消费者依赖同一个SequenceBarrier, 执行的操作是加减操作
139,860,139 ops/sec
多生产者单消费者
* +----+
* | P1 |------+
* +----+ |
* v
* +----+ +-----+
* | P1 |--->| EP1 |
* +----+ +-----+
* ^
* +----+ |
* | P3 |------+
* +----+
*
*
* Queue Based:
* ============
*
* +----+ put
* | P1 |------+
* +----+ |
* v take
* +----+ +====+ +-----+
* | P2 |--->| Q1 |<---| EP1 |
* +----+ +====+ +-----+
* ^
* +----+ |
* | P3 |------+
* +----+
*
* P1 - Publisher 1
* P2 - Publisher 2
* P3 - Publisher 3
* Q1 - Queue 1
* EP1 - EventProcessor 1
*-----------------------------------------------------------
* Disruptor1:
* ==========
* track to prevent wrap
* +--------------------+
* | |
* | v
* +----+ +====+ +====+ +-----+
* | P1 |--->| RB |<---| SB | | EP1 |
* +----+ +====+ +====+ +-----+
* ^ get ^ |
* +----+ | | |
* | P2 |------+ +---------+
* +----+ | waitFor
* |
* +----+ |
* | P3 |------+
* +----+
*
* P1 - Publisher 1
* P2 - Publisher 2
* P3 - Publisher 3
* RB - RingBuffer
* SB - SequenceBarrier
* EP1 - EventProcessor 1
*-----------------------------------------------------------
* Disruptor2:
* ==========
* track to prevent wrap
* +--------------------+
* | |
* | |
* +----+ +====+ +====+ |
* | P1 |--->| RB |--->| SB |--+ |
* +----+ +====+ +====+ | |
* | v
* +----+ +====+ +====+ | +----+
* | P2 |--->| RB |--->| SB |--+>| EP |
* +----+ +====+ +====+ | +----+
* |
* +----+ +====+ +====+ |
* | P3 |--->| RB |--->| SB |--+
* +----+ +====+ +====+
*
* P1 - Publisher 1
* P2 - Publisher 2
* P3 - Publisher 3
* RB - RingBuffer
* SB - SequenceBarrier
* EP - EventProcessor
BlockingQueue的Case:
ThreeToOneQueueThroughputTest
多生产者,单消费者,一个blockingQueue,依次消费,执行加和操作
6,103,143 ops/sec
Disruptor的Case:
ThreeToOneSequencedThroughputTest
多生产者,单消费者,一个ringBuffer,每个生产者依次生产,依次批量消费,执行加和操作
8,389,261 ops/sec
ThreeToOneSequencedThroughputTest
多生产者,单消费者,一个ringBuffer,每个生产者批量生产,依次批量消费,执行加和操作
102,774,922 ops/sec
ThreeToThreeSequencedThroughputTest
多生产者,单消费者,每个生产者一个ringBuffer,每个生产者依次生产,依次批量消费,执行加和操作
490,018,148 ops/sec