是什么导致这种性能下降?

时间:2015-02-20 13:53:55

标签: java multithreading performance disruptor-pattern

我使用Disruptor框架对某些数据执行快速Reed-Solomon纠错。这是我的设置:

          RS Decoder 1
        /             \
Producer-     ...     - Consumer
        \             /
          RS Decoder 8 
  • 生产者从磁盘读取2064字节的块到字节缓冲区。
  • 8位RS解码器消费者并行执行Reed-Solomon纠错。
  • 使用者将文件写入磁盘。

在disruptor DSL术语中,设置如下:

        RsFrameEventHandler[] rsWorkers = new RsFrameEventHandler[numRsWorkers];
        for (int i = 0; i < numRsWorkers; i++) {
            rsWorkers[i] = new RsFrameEventHandler(numRsWorkers, i);
        }
        disruptor.handleEventsWith(rsWorkers)
                .then(writerHandler);

当我没有磁盘输出消费者(没有.then(writerHandler)部分)时,一旦添加消费者,测量的吞吐量就是80 M / s,即使它写入{{1或者甚至不写,但它被声明为依赖消费者,性能下降到50-65 M / s。

我已经使用Oracle Mission Control对其进行了分析,这就是CPU使用率图表所示:

没有额外的消费者: Without an additional consumer

增加一位消费者: With additional consumer

图中的灰色部分是什么?它来自哪里?我想它与线程同步有关,但我无法在Mission Control中找到任何其他统计信息来指示任何此类延迟或争用。

2 个答案:

答案 0 :(得分:3)

您的假设是正确的,这是一个线程同步问题。

来自API Documentation for EventHandlerGroup<T>.then(强调我的)

  

设置批处理程序以使用环形缓冲区中的事件。这些处理程序只会在此组中的每个 EventProcessor处理完事件后处理事件。

     

此方法通常用作链的一部分。例如,如果处理程序A必须在处理程序B之前处理事件:

这必然会降低吞吐量。想想它就像一个漏斗:

Event Funnel

消费者必须wait才能完成每个EventProcessor,然后才能完成瓶颈。

答案 1 :(得分:2)

根据你所展示的内容,我可以在这看到两种可能性。您可能会受到其中一个或两个的影响,我建议您同时测试它们。 1)IO处理瓶颈。 2)写入缓冲区的多个线程的争用。

IO处理

根据显示的数据,您已声明只要启用IO组件,吞吐量就会降低,内核时间也会增加。在您的消费者线程正在编写时,这很容易成为IO等待时间。执行write()调用的上下文切换比什么都不做要贵得多。您的Decoder现在的上限是消费者的最高速度。要测试此假设,您可以删除write()来电。换句话说,打开输出文件,准备输出字符串,然后发出写调用。

建议

  • 尝试删除Consumer中的write()调用,看看它是否缩短了内核时间。
  • 您是否按顺序写入单个平面文件 - 如果没有,请尝试此
  • 您是否正在使用智能批处理(即:缓冲直到endOfBatch标志,然后一次性写入)以确保尽可能高效地捆绑IO?

多个作家的争用

根据你的描述,我怀疑你的Decoder正在从破坏者那里读取,然后写回到同一个缓冲区。这将导致多个写入器的问题,即写入内存的CPU上的争用。我建议的一件事是有两个破坏者戒指:

  1. Producer写入#1
  2. Decoder从#1读取,执行RS解码并将结果写入#2
  3. Consumer从#2读取,并写入磁盘
  4. 假设您的RB足够大,这将导致通过内存的良好清洁行走。

    这里的关键是没有Decoder个线程(可能在不同的核心上运行)写入Producer所拥有的同一个内存。只有2个内核执行此操作,除非磁盘速度是瓶颈,否则您可能会看到吞吐量提高。

    我在这里有一篇博客文章,它更详细地描述了如何实现这一目标,包括示例代码。 http://fasterjava.blogspot.com.au/2013/04/disruptor-example-udp-echo-service-with.html

    其他想法

    • 了解您正在使用的WaitStrategy,机器中有多少物理CPU等也是有帮助的。
    • 考虑到最大延迟将是IO写入,您应该能够通过移动到不同的WaitStrategy来显着降低CPU利用率。
    • 假设您使用的是合理的新硬件,您应该能够仅使用此设置使IO设备饱和。
    • 您还需要确保文件位于不同的物理设备上以实现合理的性能。