Disruptor源码解析六 示例与性能压测

目录

前言

perftest结构

压测CASE示例

1V1的blockingQueueCase

1V1的DisruptorCase

blockingQueue VS 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值