一、Disruptor基本原理

在多线程开发中,我们常常遇到这样一种场景:一些线程接受用户请求,另外一些线程处理这些请求。比如日志处理中的日志输入和告警。这种典型的生产者消费者场景十分常见,而生产者消费者模式的核心就是阻塞队列。由于阻塞队列会涉及大量的锁竞争和线程阻塞,都是非常耗费CPU的操作,因此阻塞队列的性能好坏能够在很大程度上决定上层应用的性能瓶颈。

JAVA中用BlockingQueue这个接口来描述阻塞队列,有数组实现的有界阻塞队列为 ArrayBlockingQueue,用链表实现的无界阻塞队列为LinkedBlockingQueue,除此之外还有优先级阻塞队列 PriorityBlockingQueue,这些阻塞队列除了自身特有逻辑外,都采用基于悲观锁的并发控制。这样的并发机制会有严重的锁冲突,大大影响并发性能。Disruptor满足了我们的要求。

锁是用来做并发最简单的方式,当然其代价也是最高的。内核态的锁的时候需要操作系统进行一次上下文切换,等待锁的线程会被挂起直至锁释放。

使用了Ringbuffer,内存屏障,乐观并发控制等众多优化手段后,Disrupter的阻塞队列与传统的阻塞队列相比有超过10倍的吞吐率。

Disruptor的主要设计思想是无锁的高并发,在设计上采用内存屏障的机制和CAS操作实现此思想。主流的并发程序 都离不开锁对资源的管控,或者尽量避开锁的使用。

其主要的实现原理总结有如下三点:

  • 采用消费者-生产者模型进行读写的分离。

  • 用循环缓存(实际是一个循环队列)实现了数据的暂存和读写速度的匹配。

  • 用内存屏障加序列号的方式实现了无锁的并发机制。

为什么Disruptor的速度这么快?

我们知道Disruptor速度很快,但是为什么呢?

Disruptor没有使用很影响性能锁 。取而代之的是,在需要确保操作是线程安全的(特别是,在多生产者的环境下,更新下一个可用的序列号)地方,我们使用CAS(Compare And Swap/Set)操作。这是一个CPU级别的指令,它的工作方式有点像乐观锁——CPU去更新一个值,但如果想改的值不是原来的值,操作就失败,反之则去更新这个值。

说句题外话,Java中AtomicInteger也使用了CAS操作来保证原子性。在并发控制中,CAS操作是十分重要的。

CAS操作是CPU级别的指令,在Java中CAS操作在Unsafe类中(Unsafe,见名知意,这个类是不安全的,不建议在实际开发的时候使用)。关于CAS操作的原理网上有很多,在此不过多说明了。

另一个重要的因素是Disruptor消除了伪共享。 下面引用网上的一段话,来解释下什么是伪共享。

缓存系统中是以缓存行(cache line)为单位存储的。缓存行是 2 的整数幂个连续字节,一般为 32-256 个字节。最常见的缓存行大小是 64个字节。

当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。缓存行上的写竞争是运行在 SMP 系统中并行线程实现可伸缩性最重要的限制因素。有人将伪共享描述成无声的性能杀手,因为从代码中很难看清楚是否会出现伪共享。

第三个原因是Disruptor采用了RingBuffer。Ring Buffer 是一个数组,它比链表要快,而且有一个容易预测的访问模式,数据可以在硬件层面预加载到高速缓存,极大的提高了数据访问的速度。

RingBuffer可以预先分配内存,并且保持数组元素永远有效。这意味着内存垃圾收集(GC)在这种情况下几乎什么也不用做。

二、Disuptor基本概念

  • RingBuffer:Ringbuffer是一个环形缓冲区,是Disruptor的核心。

  • Sequencer:序号管理器,使消费者和生产者之前快速正确地传输数据。

  • Sequence:RingBuffer中每个数据的序号,用于跟踪ringbuffer中任务的变化和消费者的消费情况。

  • SequenceBarrier:序号栅栏,管理和协调生产者的游标序号和各个消费者的序号,确保生产者不会覆盖消费者未来得及处理的消息,确保存在依赖的消费者之间能够按照正确的顺序处理。

  • Event:生产者和消费者之间进行交换的数据称为事件。

  • EventProcessor:事件处理器,监听RingBuffer的事件,并消费可用事件,从RingBuffer读取的事件会交由实际的生产者实现类来消费;它会一直侦听下一个可用的序号,直到该序号对应的事件已经准备好。

  • EventHandler:业务处理器,是实际消费者的接口,完成具体的业务逻辑实现,第三方实现该接口;代表着消费者。

  • Producer:生产者接口,第三方线程充当该角色,producer向RingBuffer写入事件。


本文引用了很多网上的博客内容,由衷地感谢他们乐于分享的精神。

Disruptor 极速体验

Disruptor3.0的实现细节

伪共享(False Sharing)

剖析Disruptor:为什么会这么快?(一)锁的缺点

Disruptor学习笔记(一):基本原理和概念的更多相关文章

  1. .NET Remoting学习笔记(一)概念

    目录 .NET Remoting学习笔记(一)概念 .NET Remoting学习笔记(二)激活方式 .NET Remoting学习笔记(三)信道 背景 自接触编程以来,一直听过这个名词Remotin ...

  2. 【转载】.NET Remoting学习笔记(一)概念

    目录 .NET Remoting学习笔记(一)概念 .NET Remoting学习笔记(二)激活方式 .NET Remoting学习笔记(三)信道 背景 自接触编程以来,一直听过这个名词Remotin ...

  3. Disruptor学习笔记

    前言 以前一直听说有Disruptor这个东西,都说性能很强大,所以这几天自己也看了一下. 下面是自己的学习笔记,另外推荐几篇自己看到写的比较好的博客: Disruptor——一种可替代有界队列完成并 ...

  4. 【原】Learning Spark (Python版) 学习笔记(一)----RDD 基本概念与命令

    <Learning Spark>这本书算是Spark入门的必读书了,中文版是<Spark快速大数据分析>,不过豆瓣书评很有意思的是,英文原版评分7.4,评论都说入门而已深入不足 ...

  5. Spring学习笔记一:基础概念

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6774310.html    一:Spring是什么 Spring的主要作用是作为对象的容器. 传统编程中,我们 ...

  6. Learning Spark (Python版) 学习笔记(一)----RDD 基本概念与命令

    <Learning Spark>这本书算是Spark入门的必读书了,中文版是<Spark快速大数据分析>,不过豆瓣书评很有意思的是,英文原版评分7.4,评论都说入门而已深入不足 ...

  7. [No000094]SVN学习笔记4-版本库概念与部分日常操作

    基本概念 版本库 Subversion 使用集中的数据库,它包含了所有的版本控制文件及其完整历史.这个数据库就是版本库.版本库通常位于运行 Subversion 服务器的文件服务器上,向 Subver ...

  8. UNET学习笔记3 - 网络系统的概念

    服务器和 HOST 在Unity游戏里,一个游戏一般有一个服务器和多个客户端组成,但也可以没有服务器,用某一个客户端来同时做服务器用,这种就叫Host 在Host上的客户端叫Local Client, ...

  9. C++学习笔记39:进程概念

    进程的基本概念 进程是描述程序执行过程和资源共享的基本单位 主要目的:控制和协调程序的执行 进程相关函数 用户与组ID函数 创建进程:system(),fork(),exec() 终止进程:kill( ...

随机推荐

  1. RHEL6 Systemtap 安装笔记

    以 RHEL6u3 为例 1  Systemtap 安装 yum install systemtap 跟systemtap有关的有6,7个,全装上,别偷懒 就用yum安装,别傻傻的去下rpm包,吃力不 ...

  2. java 原子类

    一.基本类原子操作 AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference<V>对boolean,Integer,long,refer ...

  3. hibernate注解(三)1+N问题

    一.什么时候会遇到1+N的问题? 前提:Hibernate默认表与表的关联方法是fetch="select",不是fetch="join",这都是为了懒加载而准 ...

  4. dedecms提取某栏目及子栏目名称到首页怎么弄

    我们建网站时有不同的需求,例如为页面创建一个栏目导航,用dedecms如何提取某栏目及子栏目名称和链接呢?如下图所示,先列出指定的顶级栏目,在下方再列出此栏目的所有子栏目. 之前ytkah说过dede ...

  5. Python3学习之路~2.3 字符串操作

    字符串操作 特性:不可修改 name="my \tname is alex" print(name.capitalize()) #首字母变大写 print('Alex LI'.ca ...

  6. 前端js如何生成一个对象,并转化为json字符串

    https://www.cnblogs.com/May-day/p/6841958.html 一,直接上代码 <script src="../../Content/jquery-2.0 ...

  7. [py]django模板继承

    参考 1.展示arr,d等数据类型 2.逻辑for if / url获取 3.获取内置变量 django模板继承 通过搞一个base.html 这个base.html可以包含两类 block片断 其他 ...

  8. for与while的特点及其if在什么情况下使用情况

    for和while的特点: 什么时候使用循环结构呢? 1:当对某些代码执行很多次时,使用循环结构完成. 2:当对一个条件进行一次判断时,可以使用if语句. 3:当对一个条件进行多次判断时,可以使用wh ...

  9. Fisher精确检验【转载】

    转自:https://en.wikipedia.org/wiki/Fisher%27s_exact_test https://www.cnblogs.com/Dzhouqi/p/3440575.htm ...

  10. 浅谈Android View滑动冲突

    引言 上一篇文章我们从源码的角度介绍了View事件分发机制,这一篇文章我们就通过介绍滑动冲突的规则和一个实例来更加深入的学习View的事件分发机制. 1.外部滑动方向和内部滑动方向不一致 考虑这样一种 ...