高性能队列disruptor为什么这么快?
背景
Disruptor是LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCon演讲后,获得了业界关注。2011年,企业应用软件专家Martin Fowler专门撰写长文介绍。同年它还获得了Oracle官方的Duke大奖。
目前,包括Apache Storm、Camel、Log4j2在内的很多知名项目都应用了Disruptor以获取高性能。
我们先知道disruptor是干什么的,然后笔者带你们源码搞一波,再来看看在log4j2中的运用。
一、Disruptor是什么?
可以这样总结,Disruptor是LMAX开源的、用于替代并发线程间数据交换的环形队列的、基本无锁的(只有部分等待策略存在)、高性能的线程间通讯框架。
Disruptor唯一可能遇到Java锁的时候,就是在消费者等待可用事件进行消费时。而Disruptor为这个等待过程,编写了包括使用锁和不使用锁的多种策略,可根据不同场景和需求进行选择。
开源:https://github.com/LMAX-Exchange/disruptor
二、Disruptor为什么这么快
1、环形队列RingBuffer
一个环形队列,意味着首尾相连,对列可以循环使用,使用数组来保存。环形队列在JVM生命周期中通常是永生的,GC的压力更小。

我们来解释一下这个图:当前有一个consumer,停留在位置12,这时producer假设在位置3,这时producer的下一步是如何处理的呢?producer会尝试读取4,发现下一个可以获取,所以可以安全获取,并且通知一个阻塞的consumer起来活动。如此一直到下一圈11都是安全的(这里我们假设生产者比较快),当producer尝试访问12时发现不能继续,于是自旋等待;当consumer消费时,会调用barrier的waitFor方法,waitFor看到前面最近的安全节点已经到了下一圈的11,于是consumer可以无锁的去消费当前12到下一圈11所有数据,可以想象,这种方式比起synchronized要快上很多倍。
2、弃用锁机制使用CAS
在高度竞争的情况下,锁的性能将超过原子变量的性能,但是更真实的竞争情况下,原子变量的性能将超过锁的性能。同时原子变量不会有死锁等活跃性问题。能不用锁,就不使用锁,如果使用,也要将锁的粒度最小化。
唯一使用锁的就是消费者的等待策略实现类中,下图。补充一句,生产者的等到策略就是LockSupport.parkNanos(1),再自旋判断。
| 名称 | 措施 | 适用场景 |
|---|---|---|
| BlockingWaitStrategy | 加锁 | CPU资源紧缺,吞吐量和延迟并不重要的场景 |
| BusySpinWaitStrategy | 自旋 | 通过不断重试,减少切换线程导致的系统调用,而降低延迟。推荐在线程绑定到固定的CPU的场景下使用 |
| PhasedBackoffWaitStrategy | 自旋 + yield + 自定义策略 | CPU资源紧缺,吞吐量和延迟并不重要的场景 |
| SleepingWaitStrategy | 自旋 + yield + sleep | 性能和CPU资源之间有很好的折中。延迟不均匀 |
| TimeoutBlockingWaitStrategy | 加锁,有超时限制 | CPU资源紧缺,吞吐量和延迟并不重要的场景 |
| YieldingWaitStrategy | 自旋 + yield + 自旋 | 性能和CPU资源之间有很好的折中。延迟比较均匀 |
3、解决伪共享,采用缓存行填充

abstract class SingleProducerSequencerPad extends AbstractSequencer
{
protected long p1, p2, p3, p4, p5, p6, p7; SingleProducerSequencerPad(int bufferSize, WaitStrategy waitStrategy)
{
super(bufferSize, waitStrategy);
}
} public final class SingleProducerSequencer extends SingleProducerSequencerFields
{
protected long p1, p2, p3, p4, p5, p6, p7;
//..省略
}
Java中通过填充缓存行,来解决伪共享问题的思路,现在可能已经是老生常谈,连Java8中都新增了sun.misc.Contended注解来避免伪共享问题。但在Disruptor刚出道那会儿,用缓存行来优化Java数据结构,这恐怕还很新潮。
4、还有一些细节性的
1)通过sequence & (bufferSize - 1)定位元素的index比普通的求余取模(%)要快得多。sequence >>> indexShift 快速计算出sequence/bufferSize的商flag(其实相当于当前sequence在环形跑道上跑了几圈,在数据生产时要设置好flag。
2)合理使用Unsafe,CPU级别指令。实现更加高效地内存管理和原子访问。
至于一些更细节的,下面源码搞起来,还是很简单的。
源码分析:Disruptor源码解读
参考:
https://tech.meituan.com/disruptor.html
https://www.jianshu.com/p/c3c108c3dcfd
高性能队列disruptor为什么这么快?的更多相关文章
- 高性能队列Disruptor系列1--传统队列的不足
在前一篇文章Java中的阻塞队列(BlockingQueue)中介绍了Java中的阻塞队列.从性能上我们能得出一个结论:数组优于链表,CAS优于锁.那么有没有一种队列,通过数组的方式实现,而且采用无锁 ...
- 高性能队列——Disruptor
背景 Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级).基于Disruptor开发的系统单线程能 ...
- 高性能队列Disruptor系列2--浅析Disruptor
1. Disruptor简单介绍 Disruptor是一个由LMAX开源的Java并发框架.LMAX是一种新型零售金融交易平台,这个系统是建立在 JVM 平台上,核心是一个业务逻辑处理器,它能够在一个 ...
- 高性能队列Disruptor的使用
一.什么是 Disruptor 从功能上来看,Disruptor 是实现了"队列"的功能,而且是一个有界队列.那么它的应用场景自然就是"生产者-消费者"模型的应 ...
- 高性能队列Disruptor系列3--Disruptor的简单使用(译)
简单用法 下面以一个简单的例子来看看Disruptor的用法:生产者发送一个long型的消息,消费者接收消息并打印出来. 首先,我们定义一个Event: public class LongEvent ...
- 高性能无锁队列 Disruptor 初体验
原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 最近一直在研究队列的一些问题,今天楼主要分享一个高性能的队列 Disr ...
- Disruptor 为什么这么快?
为什么Disruptor不使用队列来实现RingBuffer 队列有两个指针,一个指向队头,一个指向队尾.如果有超过一个生产者想要往队列里放东西,尾指针就将成为一个冲突点,因为有多个线程要更新它. ...
- 从构建分布式秒杀系统聊聊Disruptor高性能队列
前言 秒杀架构持续优化中,基于自身认知不足之处在所难免,也请大家指正,共同进步.文章标题来自码友 简介 LMAX Disruptor是一个高性能的线程间消息库.它源于LMAX对并发性,性能和非阻塞算法 ...
- JUC并发编程与高性能内存队列disruptor实战-下
并发理论 JMM 概述 Java Memory Model缩写为JMM,直译为Java内存模型,定义了一套在多线程读写共享数据时(成员变量.数组)时,对数据的可见性.有序性和原子性的规则和保障:JMM ...
随机推荐
- io计算
http://www.cnblogs.com/yalong_xiang/archive/2011/11/15/2249530.html ぬ儱←OWEN★ windows下如何查看磁盘IO性能 复制 ...
- Struts2.3动态调用报 No result defined for action 错误
struts 2.3.16 採用动态调用发现不工作报404 not found,网上查找原因: 1.由于:struts2中默认不同意使用DMI 所以:须要在配置文件里打开: <constant ...
- Java实现二叉排序树的插入、查找、删除
import java.util.Random; /** * 二叉排序树(又称二叉查找树) * (1)能够是一颗空树 * (2)若左子树不空,则左子树上全部的结点的值均小于她的根节点的值 * (3)若 ...
- 打开google 新地址
还在为谷歌打不开而发愁吗? 那就试试这个吧 91.213.30.151
- SSH-struts2的异常处理
在学习j2se的时候学习过利用java的exception类去处理异常.在struts2框架中也提供了对于异常的处理.简单说就是当Action发生异常时.能够在struts2.xml文件里进行配置,将 ...
- 算法基础:正整数指定规则排序问题(Golang实现)
给定字符串内有非常多正整数,要求对这些正整数进行排序.然后返回排序后指定位置的正整数 排序要求:依照每一个正整数的后三位数字组成的整数进行从小到大排序 1)假设不足三位,则依照实际位数组成的整数进行比 ...
- 多button事件处理
private void ButtonClick(object sender, RoutedEventArgs e) { Button cmd = (Button)e.OriginalSource; ...
- field load respone data
问题: AJAX 使用谷歌浏览器 POST 请求报如下错误 field load respone data 使用 火狐 浏览器就正常 调试1: 发现其实我请求的回调函数能打印出来数据,但是,在netw ...
- [翻译角]Headline English: A Captain Should Be Pitch Perfect at a Multitude of Skills (ESLPOD Blog)
以下转自www.eslpod.com,翻译为本人添加.其余版权均归原网站所有. ESLPOD是一个英语学习网站,我最初知道这个网站,是因为“奶爸”<把你的英语用起来>(电子版3元)一书的推 ...
- 千万数据条 用户特征数据 写入mysql
from mysql_tool import * import copy s = ''' INSERT INTO `qqzone`.`myu` (`id`, `uid`, `age`, `gender ...