1、起源

    Disruptor最初由lmax.com开发,2010年在Qcon公开发表,并于2011年开源,其官网定义为:“High Performance Inter-Thread Messaging Library”,即:线程间的高性能消息框架。其实JDK已经为我们提供了很多开箱即用的线程间通信的消息队列,如:ArrayBlockingQueue、LinkedBlockingQueue、ConcurrentLinkedQueue等,这些都是基于无锁的CAS设计。

    那么Disruptor为什么还有存在的意义呢?其实无锁并不代表没有竞争,所以当高并发写或者读的时候,这些工具类一样会面临资源争用的极限性能问题。而lmax.com作为一家顶级外汇交易商,其交易系统需要处理的并发量非常巨大,对响应延迟也非常敏感。在这种背景下,Disruptor诞生了,它的核心思想就是:把多线程并发写的线程安全问题转化为线程本地写,即:不需要做同步。同时,lmax公司基于Disruptor构建的交易系统也多次斩获金融界大奖。

2、发展

框架很轻量

Disruptor非常轻量,整个框架最新版3.4.2也才70多个类,但性能却非常强悍。得益于其优秀的设计,和对计算机底层原理的运用,官网说的:mechanical sympathy,我翻译成硬件偏向或者面向硬件编程。同时它跟我们常见的MQ不一样,这里说的线程间其实就是同一个进程内,不同线程间的消息传递,跟JDK中的那些阻塞和并发队列的用法是一样的,也就是说它们不会夸进程。

性能很厉害

  • 比JDK的ArrayBlockingQueue性能高近一个数量级
  • 单线程每秒能处理超 600W 的数据(处理600W并非是消费者消费完600W的数据,而是说Disruptor能在1秒内将600W数据发送给消费者,换句话说,不是600W的TPS,而是每秒600W的派发。再有,其实600W是Disruptor刚发布时硬件的水平了,现在在个人PC上也能轻松突破2000W)(为什么这里要强调单线程呢??为什么单线程的性能反而会更高呢??)
  • 基于事件驱动模型,不用消费者主动拉取消息

应用很广泛

Apache Storm、Apache Camel、Log4j2(见:org.apache.logging.log4j.core.async. AsyncLoggerDisruptor)等都在用。(怎么最快在你的项目里用上Disruptor呢?日志框架换成Log4j2,然后打开异步就可以了)

3、核心类

主要核心类只有这6个:

简单使用方法可以参考: https://github.com/hiccup234/web-advanced/blob/master/disruptor-client/src/main/java/top/hiccup/disruptor/SampleTest.java

4、有多快?

    JDK自带的队列都是优秀程序员的智慧结晶,性能也是非常的强悍,下图是其特点对比和总结:

    同时Disruptor在这样强悍的基础上把性能提升了近一个数量级,这是非常了不起的(-- 就像要把我的存款增长10倍相对容易,但要让东哥的身价再涨一番就难了)通过上图我们可以看到,无锁的方式一般都是无界的(无法保证队列的长度在确定的范围内),加锁的方式,可以实现有界队列。
    但是,在稳定性要求特别高的系统中,为了防止生产者速度过快,导致内存溢出,只能选择有界队列。所以我们综合一下,JDK的一众队列中,跟Disruptor最匹配的就是ArrayBlockingQueue了。

没有对比就没有伤害

这是我本机测试的几个队列的性能对比,测试程序见:https://github.com/hiccup234/web-advanced/tree/master/disruptor-client

可见Disruptor在单线程情况下吞吐量竟能达到2500W以上,远远超过其他队列。在多生产者的情况下,这几个队列的吞吐量却是一样的(说明队列在多线程环境下,性能瓶颈并不在其本身)

再看Log4j2官网的性能测试截图:

大家注意最右边的64线程,吞吐量比最左边的单线程高了不少,为什么这里多线程的吞吐量反而更好?是上面我的多线程测试程序有问题吗?

    其实不是的,这是Disruptor更有魅力的一个特点:RingBuffer有一个重载的next方法,即:一次为当前线程分配多个事件槽,一个线程一次性批量生产多个事件。这样在极限性能的情况下就可以大大减少线程间的上下文的切换,毕竟线程调度对JVM来说是很重的一个操作,也是上上图中各队列的多线程性能瓶颈所在。

5、为什么那么快?

    Disruptor为什么这么快呢?我主要总结了这3点:

  • 预分配
  • 无锁(CAS)以及减小锁竞争
  • 缓存行和伪共享

预分配思想

预分配其实是一个空间换时间的思想,常见的如:JVM启动时的堆内存分配,线程创建对象时堆内存中的TLAB分配,Redis中的动态字符串结构SDS,甚至Java语言中动态数组ArrayList等等。
Disruptor中对预分配思想的实践有:

  1. RingBuffer中的fill方法,创建Disruptor时就填充整个RingBuffer,而不是每次生产者生产事件时再去创建事件对象(这样可以避免JVM大量创建和回收对象,对GC造成压力)
  2. 生产者生产事件时,可以一次性取出多个事件槽,批量生产和批量发布

无锁(CAS)以及减小锁竞争

其实,在任何并发环境中开销最大的操作都是:争用写访问,因为我们可以把读和写分离开,可以做共享锁,但是只能是独占。JDK的阻塞队列包括并发队列中都存在对写操作的独占访问,这也是他们的多线程性能瓶颈所在。当然,Disruptor中也存在写访问争用,但是它通过巧妙的办法,减弱了这种争用的激烈程度(RingBuffer的next(int n)就是个例子),而且通过无锁的CAS操作,避免了庞大的线程切换开销。
Disruptor使用CAS操作的场景,大家可以对比ConcurrentLinkedQueue,这里就不再赘述了。

缓存行和伪共享

再看看CPU与内存的速度差多少倍?如果说CPU是一辆高速飞奔的高铁,那么当前内存就像旁边蹒跚踱步的老人。然而,更气人的是,CPU的每个指令周期中的读指令写数据都要依赖内存(与CPU速度对等的是寄存器)。

    那么如何解决CPU与内存如此大的速度差异呢?聪明的计算机科学家早就想到了办法:加一个缓存层,即CPU高速缓存。
加了缓存后又引出另外一个问题:局部性原理,即2/8原则,80%的计算用20%的指令访问20%的数据。同时,CPU读高速缓存和读内存的速度差了100倍,所以缓存的命中率越高系统的性能越厉害。高速缓存的存放一般都是按缓存行(一个缓存行64Byte)管理的,同一个缓存行里不同数据存在伪共享的问题,具体描述大家可以参考https://github.com/hiccup234/misc/blob/master/src/main/java/top/hiccup/jdk/vm/jmm/FalseSharingTest.java
    那么Disruptor是怎么解决伪共享的问题呢?答案是:缓存行填充,其实这不是Disrutpor的发明,我们打开老点的JDK的JUC包下的Exchanger就可以看到大神Doug Lea的神来之笔:

新版的JDK已经换成了@sun.misc.Contended注解,也更优雅。

再谈RingBuffer

RingBuffer是整个Disruptor的精神内核所在,通过查看源码,我们可以知道RingBuffer是要利用缓存行来守护indexMask、entries、bufferSize、sequencer不被伪共享换出。

Ringbuffer是一个首尾相连的环,或者叫循环队列,但是它自己没有尾指针,跟正常的循环队列不一样,底层数据结构采用数组实现。

  1. 减少竞争点,比如不删除数据,所以不需要尾指针(整个队列的尾指针由消费者维护)
  2. 重复利用数组,不需要GC事件对象
  3. 使用数组存储数据,可以利用CPU缓存每次都加载一个cacheline的特性,同时也可以避开伪共享的问题

6、总结

    Disruptor其实还有一些其他的特性,如:Sequences(类似AtomicLong)、Sequencer、多播事件(类似MQ的Fanout交换机)以及RingBuffer持有的首指针,消费者持有的尾指针的控制和同步问题等等,大家可以对照源码分析和整理。

高性能内存队列Disruptor--原理分析的更多相关文章

  1. JUC并发编程与高性能内存队列disruptor实战-下

    并发理论 JMM 概述 Java Memory Model缩写为JMM,直译为Java内存模型,定义了一套在多线程读写共享数据时(成员变量.数组)时,对数据的可见性.有序性和原子性的规则和保障:JMM ...

  2. JUC并发编程与高性能内存队列disruptor实战-上

    JUC并发实战 Synchonized与Lock 区别 Synchronized是Java的关键字,由JVM层面实现的,Lock是一个接口,有实现类,由JDK实现. Synchronized无法获取锁 ...

  3. 消息队列NetMQ 原理分析4-Socket、Session、Option和Pipe

    消息队列NetMQ 原理分析4-Socket.Session.Option和Pipe 前言 介绍 目的 Socket 接口实现 内部结构 Session Option Pipe YPipe Msg Y ...

  4. 消息队列NetMQ 原理分析1-Context和ZObject

    前言 介绍 NetMQ是ZeroMQ的C#移植版本,它是对标准socket接口的扩展.它提供了一种异步消息队列,多消息模式,消息过滤(订阅),对多种传输协议的无缝访问. 当前有2个版本正在维护,版本3 ...

  5. 消息队列NetMQ 原理分析2-IO线程和完成端口

    消息队列NetMQ 原理分析2-IO线程和完成端口 前言 介绍 目的 IO线程 初始化IO线程 Proactor 启动Procator线程轮询 处理socket 获取超时时间 从完成端口获取处理完的状 ...

  6. 消息队列NetMQ 原理分析3-命令产生/处理和回收线程

    消息队列NetMQ 原理分析3-命令产生/处理和回收线程 前言 介绍 目的 命令 命令结构 命令产生 命令处理 创建Socket(SocketBase) 创建连接 创建绑定 回收线程 释放Socket ...

  7. 消息队列NetMQ 原理分析5-StreamEngine、Encord和Decord

    消息队列NetMQ 原理分析5-StreamEngine,Encord和Decord 前言 介绍 目的 StreamEngine 发送数据 接收数据 流程分析 Encoder V2Encoder V1 ...

  8. [转载]linux内存映射mmap原理分析【转】

    转自:http://www.cnblogs.com/wanpengcoder/articles/5306688.html 转自:http://blog.csdn.net/yusiguyuan/arti ...

  9. 高性能无锁队列 Disruptor 初体验

    原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 最近一直在研究队列的一些问题,今天楼主要分享一个高性能的队列 Disr ...

随机推荐

  1. aws基础架构学习笔记

    文章大纲 Aws 的优势 架构完善的框架(WAF) Aws 学习笔记 Aws架构中心 Aws 的优势 4.速度优势 5.全球优势 数分钟内实现全球部署 Aws全球基础设施 Aws 数据中心 来自多家O ...

  2. Xcode查看iOS崩溃与崩溃日志分析

    一.造成崩溃的原因 1.代码中存在bug 2.Watchdog 超时机制 3.用户强制退出 4.低内存终止 5.其他违法系统规则的操作,大部分是内存问题 二.崩溃的类型 1.信号错误类 (1)EXC_ ...

  3. IntelliJ IDEA项目断开版本管理解决方案

    今天使用idea时打开项目突然发现项目不受svn管理(项目目录依然受svn管理,只是idea脱管了),如遇到可用以下方法: 图片示例: 1. 2. 希望能帮到你

  4. 63)PHP,登录验证

    首先辨析两种状态:   你的用户名和密码通过验证  只能表明你能登录,但是不能保证你登录了. 管理员信息合法和管理员处于的登录状态是两个概念:管理员信息合法证明你的用户名和密码是正确的, 但是管理员信 ...

  5. 吴裕雄 python 神经网络——TensorFlow 卷积神经网络手写数字图片识别

    import os import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data INPUT_N ...

  6. 将list转成tree

    using System;using System.Collections.Generic;using System.Linq; namespace Infrastructure{ /// <s ...

  7. Java 的 LinkedList 的底层数据结构

    1. 数据结构--LinkedList源码摘要 public class LinkedList<E> extends AbstractSequentialList<E> imp ...

  8. VSAN磁盘扩容与收缩(二)

  9. Linux主机下如何查询自己使用的公网IP

    curl http://members.3322.org/dyndns/getip 可以解析出自己是使用哪个公网IP访问外网的

  10. Alfresco的安装配置(Centos6系统中安装)

    Alfresco是一款开源的企业内容管理系统(ECMS),为企业提供了日常的文档管理.协同工作.工作记录管理.知识管理.网络内容管理.图片管理等多种功能. Alfresco是目前应用最广泛的开源企业知 ...