1. Disruptor简单介绍

Disruptor是一个由LMAX开源的Java并发框架。LMAX是一种新型零售金融交易平台,这个系统是建立在 JVM 平台上,核心是一个业务逻辑处理器,它能够在一个线程里每秒处理 6 百万订单。业务逻辑处理器完全是运行在内存中(in-memory),使用事件源驱动方式(event sourcing),具有低延迟,高吞吐的特性。

disruptor有多快?官方给出了和ArrayBlockingQueue的比较图表:

Disruptor可以用来解决并发编程中的一个普遍的问题: 消息队列的处理(producer和consumer)。

2. 为什么Disruptor如此之快

Disruptor 相对于传统方式的优点:

  • 无锁,没有竞争
  • 所有访问者都记录自己的序号的实现方式,允许多个生产者与多个消费者共享相同的数据结构
  • 缓存行填充,解决伪共享,提高cache命中率
  • 环形数组RingBuffer,避免GC开销

3. Disruptor结构分析

在了解disruptor如何工作之前,我们先看一下disruptor一些重要组件的介绍(翻译自官方文档,略有修改):

  • Ring Buffer:Ring Buffer通常被认为是Disruptor的主要方面,但是从3.0开始Ring Buffer只负责数据(Events)的存储和更新。对于一些高级用例,完全可以由用户自己替换。
  • Sequence:Disruptor利用Sequences来标志一个特定的组件,每一个消费者(EventProcessor)都维护一个Sequence。Disruptor中大多数的并发代码都是依赖于这些Sequence的移动,生产者对RingBuffer的互斥访问,生产者与消费者之间的协调以及消费者之间的协调,都是通过Sequence实现。几乎每一个重要的组件都包含Sequence。由于需要在线程间共享,所以Sequence是引用传递,并且是线程安全的;再次,Sequence支持CAS操作;最后,为了提高效率,Sequence通过padding来避免伪共享。
  • Sequencer:Sequencer是Disruptor的真正的核心,此接口有两个实现类 SingleProducerSequencer、MultiProducerSequencer ,它们定义在生产者和消费者之间快速、正确地传递数据的并发算法。
  • Sequence Barriers:Sequence Barriers是由Sequencer创建的,包含Sequencer主发布的Sequence的引用和任何一个依赖消费者的Sequences。它包含了判断是否有任何事件可供消费者处理的逻辑。
  • Wait Strategy:等待策略决定了消费者会等待event被生产者放入Disruptor。Disruptor提供了多个等待策略的实现。1. BusySpinWaitStrategy:自旋等待,类似Linux Kernel使用的自旋锁。低延迟但同时对CPU资源的占用也多。2. BlockingWaitStrategy :使用锁和条件变量。CPU资源的占用少,延迟大。3. SleepingWaitStrategy :在多次循环尝试不成功后,选择让出CPU,等待下次调度,多次调度后仍不成功,尝试前睡眠一个纳秒级别的时间再尝试。这种策略平衡了延迟和CPU资源占用,但延迟不均匀。5. YieldingWaitStrategy :在多次循环尝试不成功后,选择让出CPU,等待下次调度。平衡了延迟和CPU资源占用,但延迟比较均匀。6. PhasedBackoffWaitStrategy :上面多种策略的综合,CPU资源的占用少,延迟大。
  • Event:数据从生产者传递给消费者的数据单元。
  • EventProcessor:处理Disruptor中的events的主事件循环,拥有消费者Sequence的所有权。其中BatchEventProcessor即实现了有效率的event loop,而且可以回调给实现了EventHandler接口的类。
  • EventHandler:Disruptor 定义的事件处理接口,由用户实现,用于处理事件,是Consumer的真正实现。
  • Producer:即生产者,只是泛指调用 Disruptor 发布事件的用户代码,Disruptor 没有定义特定接口或类型。

将这些元素放入Disruptor的context中,Disruptor的整体结构图如下:

多播事件

Queue和Disruptor之间最大的差异。当有多个消费者监听在同一Disruptor的所有事件,一个单一的事件只会被发送到一个单一的消费者。Disruptor一个使用的case是当你需要对同样的数据进行不一样的操作的时候。LMAX典型的例子是,我们有三个操作,日志(输入数据写入持久性日志文件),复制(将输入数据发送到另一台机器以确保有数据的远程复制),和业务逻辑(实际处理工作)。普通的Executor-style处理,可能是利用WorkPool并行的来处理这些不同的事件。这样却不是实现这个目标最有效的途径。

如上图所示,我们有三个EventHandler(JournalConsumer, ReplicationConsumer and ApplicationConsumer)监听着Disruptor,每一个Handler都会顺序的收到Disruptor里所有可用的消息,这样就使得这些消费者可以并行的处理这些消息了。

为了支持现实中并行处理的应用,必须支持消费者之间的协调。回到上面的例子,防止业务逻辑的消费还在继续,日志和复制的消费者已经完成了他们的任务是必须的。我们把这个概念称为门,或者更准确地说,这个行为的超级集合的特征叫做门。门发生在两个地方。首先,我们需要确保生产者不超过消费者。这是通过添加有关消费者到Disruptor时通过调用RingBuffer.addgatingconsumers() 实现的。其次,通过实现一个SequenceBarrier(内存屏障)的结构可以实现必须先完成某些操作的需求。

参考图1,有三个消费者监听唤醒队列中的事件,在图中有一个依赖图,ApplicationConsumer依赖于 JournalConsumer 和 ReplicationConsumer,这就说明 JournalConsumer 和 ReplicationConsumer可以互相自由的并发,这层依赖关系可以从 ApplicationConsumer的 SequenceBarrier连接到 JournalConsumer和 ReplicationConsumer的 Sequences看出来。值得注意的是 Sequencer和下游消费者之间的关系。作用之一就是确保发布不会覆盖Ring Buffer。为了做到这一点,下游消费者没有一个序列比RingBuffer的Sequence还要小,比RingBuffer的size还要小,然而,利用这个依赖图可以做一些有意思的操作,因为ApplicationConsumers Sequence是小于JournalConsumer 和 ReplicationConsumer(这就是依赖图所保证的),Sequencer只用关注ApplicationConsumer的Sequence即可,其实一般意义上,Sequencer只用知道消费者的Sequences依赖树中的叶子节点即可。

事件预分配

Disruptor的设计的一个目标就是能被用在一个低延迟的环境中。在低延迟系统中,必须减少或移除内存分配操作,基于Java开发的目的就是减少垃圾回收。(在低延迟的C/C++系统中,大内存分配也存在问题,因为内存分配器也会存在竞争)

为了实现低延迟,Disruptor允许用户对事件的内存进行预分配,在构造过程和用户提供的EventFactory中都会在Disruptor 的 RingBuffer中为每个实体分配。当发布新数据到Disruptor中,API就会允许用户获取构造方法的对象,以至于可以调用方法或者更新字段。Disruptor对这些操作提供并发安全性的保障。

可选的无锁操作

另一个关键的实现低延迟的细节就是在Disruptor中利用无锁的算法,所有内存的可见性和正确性都是利用内存屏障或者CAS操作。使用CAS来保证多线程安全,与大部分并发队列使用的锁相比,CAS显然要快很多。CAS是CPU级别的指令,更加轻量,不必像锁一样需要操作系统提供支持,所以每次调用不需要在用户态与内核态之间切换,也不需要上下文切换。

只有一个用例中锁是必须的,那就是BlockingWaitStrategy(阻塞等待策略),唯一的实现方法就是使用Condition实现消费者在新事件到来前等待。许多低延迟系统使用忙等待去避免Condition的抖动,然而在系统忙等待的操作中,性能可能会显著降低,尤其是在CPU资源严重受限的情况下,例如虚拟环境下的WEB服务器。

参考资料:
LMAX Disruptor
Spark性能优化指南——基础篇- - 美团点评技术团队
Disruptor入门

高性能队列Disruptor系列2--浅析Disruptor的更多相关文章

  1. 高性能队列Disruptor系列1--传统队列的不足

    在前一篇文章Java中的阻塞队列(BlockingQueue)中介绍了Java中的阻塞队列.从性能上我们能得出一个结论:数组优于链表,CAS优于锁.那么有没有一种队列,通过数组的方式实现,而且采用无锁 ...

  2. 高性能队列Disruptor系列3--Disruptor的简单使用(译)

    简单用法 下面以一个简单的例子来看看Disruptor的用法:生产者发送一个long型的消息,消费者接收消息并打印出来. 首先,我们定义一个Event: public class LongEvent ...

  3. 高性能队列——Disruptor

    背景 Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级).基于Disruptor开发的系统单线程能 ...

  4. 高性能队列disruptor为什么这么快?

    背景 Disruptor是LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级).基于Disruptor开发的系统单线程能支撑每秒600万 ...

  5. Disruptor 系列(一)快速入门

    Disruptor 系列(一)快速入门 Disruptor:是一个开源的并发框架,能够在 无锁 的情况下实现网络的 Queue 并发操作,所以处理数据的能力比 Java 本身提供的并发类容器要大的多, ...

  6. Disruptor系列(三)— 组件原理

    前言 前两篇文章都是从github wiki中翻译而来,旨在能够快速了解和上手使用Disruptor.但是为了能够掌握该技术的核心思想,停留在使用层面还远远不够,需要了解其设计思想,实现原理,故这篇从 ...

  7. Disruptor系列(一)— disruptor介绍

    本文翻译自Disruptor在github上的wiki文章Introduction,原文可以看这里. 一.前言 作为程序猿大多数都有对技术的执着,想在这个方面有所提升.对于优秀的事物保持积极学习的心态 ...

  8. disruptor笔记之三:环形队列的基础操作(不用Disruptor类)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. Disruptor 系列(二)使用场景

    Disruptor 系列(二)使用场景 今天用一个订单问题来加深对 Disruptor 的理解.当系统中有订单产生时,系统首先会记录订单信息.同时也会发送消息到其他系统处理相关业务,最后才是订单的处理 ...

随机推荐

  1. Python魔法方法总结及注意事项

    1.何为魔法方法: Python中,一定要区分开函数和方法的含义: 1.函数:类外部定义的,跟类没有直接关系的:形式: def func(*argv): 2.方法:class内部定义的函数(对象的方法 ...

  2. 全球移动互联网大会gmic 2017为什么值得参加?

    长城会CEO郝义认为,"科学产业化将会推动科学复兴,"而本次GMIC 北京 2017也将首次引入了高规格科学家闭门峰会,专门设置G-Summit全球科学创新峰会,以"科学 ...

  3. IOS开发常见错误

    . 问题表现:什么情况?方法居然无法拉线? 问题简述:ios的空间拉线到一个.h .m文件中 居然多次拖动无效.. 问题解决:ios的空间响应单单在代码中创建一个方法是没用的,这个时候通常跟空间是没有 ...

  4. npm 常用命令详解

    本文以Windows平台上做测试,以gulp为示例做教程,出自作者白树,转载请声明出处! 目录 npm是什么 npm install 安装模块 npm uninstall 卸载模块 npm updat ...

  5. 原生JS-----论数据类型检测

    常见的数据类型检测的方法: 一.最为基础的typeof 二.不可不知的instanceof 三.比instanceof更好的constructor 四.检测值或者表达式的结果是否为NaN 五.易用的j ...

  6. JavaScript常用的方法和函数(setInterval和setTimeout)

    1.setInterval:计时器 可以按照指定的周期(以毫秒为单位)来调用函数或计算表达式 调用格式:setinterval(fun,time) 说明:fun为函数体,time为数值,这两个参数是必 ...

  7. Power Pivot表属性无法切换回表预览模式的问题

    近期Office365用户升级后解决了在Power Pivot中输入中文的问题,但是同时也带来了一个新的问题就是表属性窗口默认为“查询编辑器”模式,且无法切换回“表预览”模式. 本文和您分享在这种情况 ...

  8. 电商的噩梦?实体商家的福音——VR全景智慧城市

    我们不知道未来网络购物的样子,但对当前电商平台的问题是清楚的.从消费者角度来看,网购的顾虑主要在于商品的质量难以保证.物流效率不够高,以及网络购物的"眼见不为实". 正因为可以很好 ...

  9. RegExp(正则表达式)常用知识点小结

    原文地址:→看过来 正则表达式用到的地方很多,但是每次很久不用就全忘光了,每次都要重新看一遍文档,为了节省时间,把它的一些基本要点画总结在一张图片中,这样方便以后查看. PS:细节的东西还是需要看详细 ...

  10. tomcat产生大量TIME_WAIT连接

    http://blog.csdn.net/jiangguilong2000/article/details/12523771