Disruptor
高性能队列Disruptor系列2--浅析Disruptor
目录
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服务器。
Disruptor的更多相关文章
- 架构师养成记--15.Disruptor并发框架
一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...
- 并发框架Disruptor浅析
1.引言 Disruptor是一个开源的Java框架,它被设计用于在生产者—消费者(producer-consumer problem,简称PCP)问题上获得尽量高的吞吐量(TPS)和尽量低的延迟.D ...
- LMAX Disruptor—多生产者多消费者中,消息复制分发的高性能实现
解决的问题 当我们有多个消息的生产者线程,一个消费者线程时,他们之间如何进行高并发.线程安全的协调? 很简单,用一个队列. 当我们有多个消息的生产者线程,多个消费者线程,并且每一条消息需要被所有的消费 ...
- Disruptor 极速体验
已经不记得最早接触到 Disruptor 是什么时候了,只记得发现它的时候它是以具有闪电般的速度被介绍的.于是在脑子里, Disruptor 和"闪电"一词关联了起来,然而却一直没 ...
- disruptor - Concurrent Programming Framework 并发编程框架
disruptor发布了Java的2.0版本(.Net版本见这里),disruptor是一个高性能的异步处理框架,或者可以认为是最快的消息框架(轻量的JMS),也可以认为是一个观察者模式实现,或者事件 ...
- 剖析Disruptor:为什么会这么快?(二)神奇的缓存行填充
原文链接:http://mechanitis.blogspot.com/2011/07/dissecting-disruptor-why-its-so-fast_22.html 需FQ 计算机入门 ...
- The LMAX disruptor Architecture--转载
原文地址: LMAX is a new retail financial trading platform. As a result it has to process many trades wit ...
- Disruptor 源码阅读笔记--转
原文地址:http://coderbee.net/index.php/open-source/20130812/400 一.Disruptor 是什么? Disruptor 是一个高性能异步处理框架, ...
- 构建高性能服务(三)Java高性能缓冲设计 vs Disruptor vs LinkedBlockingQueue--转载
原文地址:http://maoyidao.iteye.com/blog/1663193 一个仅仅部署在4台服务器上的服务,每秒向Database写入数据超过100万行数据,每分钟产生超过1G的数据.而 ...
- LMAX Disruptor – High Performance, Low Latency and Simple Too 转载
原文地址:http://www.symphonious.net/2011/07/11/lmax-disruptor-high-performance-low-latency-and-simple-to ...
随机推荐
- Java EE环境
Java EE环境,包括EJB容器和Web容器. (1)Web容器:只运行Web应用的容器,例如Tomcat就是开源的Web容器,它可以运行JSP.Servlet等. (2)EJB容器:运行在EJB组 ...
- ckeditor添加代码插入功能及高亮显示(插件)
Auto SyntaxHighlighter SyntaxHighlighter CKEditor Button 下载以上两个插件,启用 以下可有可无: (设置在编辑器的显示样式) ckeditor高 ...
- css选择器星号(*)
1.星号(*)选择器的优先级 css的(*)选择器,也是通用选择器,对所有的页面元素(html,title,style,body,div,p……)应用样式,级别最低 在选择器的级别中:在元素名< ...
- [转载+补充][PY3]——环境配置(2)——windows下安装pycharm并连接Linux的python环境
原文地址:<你所会用到的Python学习环境和工具> 1. 下载安装Pycharm专业版 具体方法略.Pycharm5激活方法参考http://www.cnblogs.com/snsdzj ...
- webHttpBinding
[ServiceContract] public interface IHanger { /// <summary> /// 根据请求的用户的所属的组织,决定工单发布到哪个吊挂产线 /// ...
- [转]微信小程序登录数据解密以及状态维持
本文转自:http://www.cnblogs.com/cheesebar/p/6689326.html 学习过小程序的朋友应该知道,在小程序中是不支持cookie的,借助小程序中的缓存我们也可以存储 ...
- C++(笔)002
#include <iostream> //预处理器编译指令 int main() //函数头:对函数和程序其它部份之间的接口作出总结 int:函数的返回类型 { using namesp ...
- 跨平台 GUI可视化 网络调试工具
mNetAssisthttp://blog.chinaunix.net/uid-21977056-id-4310527.htmlhttps://github.com/busyluo/mNetAssis ...
- css常用左右布局方案整理
实际项目开发过程中我们经常会遇到页面div左右布局的需求:左侧 div 固定宽度,右侧 div 自适应宽度,填充满剩余页面,下面整理几种常用的方案 1 左侧 div 设置 float 属性为 le ...
- javaweb之EL自定义函数
1.什么是EL自定义函数 EL自定义函数是在EL表达式中调用的某个java类的静态方法,这个静态方法需在web应用程序中进行配置才可以被EL表达式调用.EL自定义函数可以扩展EL表达式的功能,让EL表 ...