一、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. Oracle HA 之 测试RAC的功能

    作用:在oracle数据库instance级别的冗余,其中只要有一个instance可用即可保证可用性,但是不能保准数据级别的错误. 数据库文件需要放置在共享存储上,理论上一个实例对应一个数据库,实例 ...

  2. python3学习笔记(4)_function-参数

    #python学习笔记 17/07/10 # !/usr/bin/evn python3 # -*- coding:utf-8 -*- import math #函数 函数的 定义 #定义一个求绝对值 ...

  3. 2018/03/10 每日一个Linux命令 之 find

    每日一个Linux命令 2018-03-10 Linux 命令 find find [查找目录] [定义条件]   今天很累了,本来不想写了,但想到自己订的学习计划必须坚持下去,每天完成.   fin ...

  4. CDN工作过程(第二种版本)

    作者:代希刚链接:https://www.zhihu.com/question/36514327/answer/121026637来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  5. 前端 HTML 常用标签 head标签相关内容

    HTML常用标签 head标签 我们首先来介绍一下head标签的主要内容和作用,文档的头部描述了文档的各种属性和信息,包括文档的标题.编码方式及URL等信息,这些信息大部分是用于提供索引,辩认或其他方 ...

  6. 给JSON中put的value=null时,这对key=value会被隐藏掉。

    当我们在JSON里像这样json.put("key",null);put值进去的话,这个键值对就会被隐藏掉例如下面的例子: <pre name="code" ...

  7. 如何修改WordPress网站默认登录地址wp-admin

    使用过WordPress程序建网站的学员都知道,我们使用Wordpress建好的网站,它的网站登录后台就是“网站域名/wp-admin”.如下图: 为了网站安全,如何修改Wordpress网站默认登录 ...

  8. python3内置函数大全(顺序排列)

    python3内置函数大全 内置函数 (1)abs(),   绝对值或复数的模 1 print(abs(-6))#>>>>6 (2)all() 接受一个迭代器,如果迭代器的所有 ...

  9. KMP(http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2772)

    #include <stdio.h>#include <string.h>#include <stdlib.h>char a[1000001],b[1000001] ...

  10. 使用POI读取/创建Execl(.xlsx)文件

    最近项目中用到了解析Execl表格的功能,在网上百度了一下自己写了一个小Demo.由于项目中使用的是Execl2007,就是后缀为.xlsx的,所以只研究了解析和创建Execl2007的文件,解析Ex ...