Disruptor-简单使用
前言
Disruptor是一个高性能的无锁并发框架,其主要应用场景是在高并发、低延迟的系统中,如金融领域的交易系统,游戏服务器等。其优点就是非常快,号称能支撑每秒600万订单。需要注意的是,Disruptor是单机框架,对标JDK中的Queue,而非可用于分布式系统的MQ
本文基于Disruptor v3.4.*版本
Demo
既然是简单使用,这阶段只需要关注:
- 生产者
- 消费者:EventHandler
- 消息的传递:消息的载体Event
简单例子
首先,我们定义消息的载体Event,生产者向消费者传递的消息通过Event承载
class LongEvent {
private long value;
public void set(long value) {
this.value = value;
}
@Override
public String toString() {
return "LongEvent{" + "value=" + value + '}';
}
}
然后定义Event生产工厂,这用于初始化Event
EventFactory<LongEvent> factory = new EventFactory<LongEvent>() {
@Override
public LongEvent newInstance() {
return new LongEvent();
}
};
接下来就可以构建Disruptor了,以下是完整代码
// 消息载体(event)
static class LongEvent {
private long value;
public void set(long value) {
this.value = value;
}
@Override
public String toString() {
return "LongEvent{" + "value=" + value + '}';
}
}
// 发布消息的转换器
public static void translate(LongEvent event, long sequence, ByteBuffer buffer)
{
event.set(buffer.getLong(0));
}
public static void main(String[] args) throws Exception {
// event生产工厂,初始化RingBuffer的时候使用
EventFactory<LongEvent> factory = new EventFactory<LongEvent>() {
@Override
public LongEvent newInstance() {
return new LongEvent();
}
};
// 指定RingBuffer的大小(必须是2的n次方)
int bufferSize = 1024;
// 构造Disruptor(默认使用多生产者模式、BlockingWaitStrategy阻塞策略)
Disruptor<LongEvent> disruptor = new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);
// Disruptor<LongEvent> disruptor = new Disruptor<>(factory, bufferSize, DaemonThreadFactory.INSTANCE, ProducerType.MULTI, new BlockingWaitStrategy());
// 设置消费者
EventHandler<LongEvent> handler = (event, sequence, endOfBatch) -> {
System.out.println("Event: " + event);
};
disruptor.handleEventsWith(handler);
// 启动disruptor,启动所有需要运行的线程
disruptor.start();
RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
ByteBuffer bb = ByteBuffer.allocate(8);
for (long i = 0; i < 100; i++) {
bb.putLong(i);
// 发布事件
ringBuffer.publishEvent(LongEventMain::translate, bb);
}
}
消费者组合(多使用场景)
Disruptor不仅可以当高性能的队列使用,还支持消费者的串行、并行消费等
以下只展示关键代码(设置消费者),其余部分参考上一节的简单demo
单链串行

disruptor.handleEventsWith(handlerA).then(handlerB);
并行

disruptor.handleEventsWith(handlerA, handlerB);
链内串行,多链并行

disruptor.handleEventsWith(handlerA).then(handlerC);
disruptor.handleEventsWith(handlerB).then(handlerD);
菱形(C、D都执行完才到E)

disruptor.handleEventsWith(handlerA).then(handlerC);
disruptor.handleEventsWith(handlerB).then(handlerD);
disruptor.after(handlerC, handlerD).then(handlerE);分组(AB都执行完才到CD)

disruptor.handleEventsWith(handlerA, handlerB).then(handlerC, handlerD);
分组不重复消费
组内竞争,组外串行:每个消息在每个分组中只有一个消费者能消费成功,如果就是分组A中只有HandlerA2能得到数据,分组B中只有HandlerB1获得

// 注意:此处的handler实现的是WorkHandler接口
disruptor.handleEventsWithWorkerPool(handlerA1, handlerA2, handlerA3)
.then(handlerB1, handlerB2, handlerB3);
分组不重复消费(菱形)

// handlerA、handlerB实现WorkHandler接口
// handlerC 实现EventHandler或WorkHandler接口均可
disruptor.handleEventsWithWorkerPool(handlerA1, handlerA2, handlerA3)
.then(handlerB1, handlerB2, handlerB3)
.then(handlerC);
等待策略
消费者速度比生产者快时,需要等待。因此就有了不同的等待策略以适应不同场景
BlockingWaitStrategy
默认策略。使用锁和 Condition 的等待、唤醒机制。速度慢,但节省CPU资源并且在不同部署环境中能提供更加一致的性能表现。
YieldingWaitStrategy
二段式,一阶段自旋100次,二阶段执行Thread.yield,需要低延迟的场景可使用此策略
SleepingWaitStrategy
三段式,一阶段自旋,二阶段执行Thread.yield,三阶段睡眠
BusySpinWaitStrategy
性能最高的策略,与 YieldingWaitStrategy 一样在低延迟场景使用,但是此策略要求消费者数量低于 CPU 逻辑内核总数
其他小技巧
清除消息载体 Event 中的数据
如果 Event 中存在大对象,应该在消费者链的末尾,添加一个清除数据的消费者,以帮助jvm垃圾回收。demo中的 LongEvent 是
private long value;所以没必要添加。
总结
本文介绍了 Disruptor 的简单使用,以及复杂场景下消费者的配置。下篇开坑 Disruptor 源码解析。
参考资料
Disruptor-简单使用的更多相关文章
- 高性能队列Disruptor系列2--浅析Disruptor
1. Disruptor简单介绍 Disruptor是一个由LMAX开源的Java并发框架.LMAX是一种新型零售金融交易平台,这个系统是建立在 JVM 平台上,核心是一个业务逻辑处理器,它能够在一个 ...
- Disruptor
高性能队列Disruptor系列2--浅析Disruptor 目录 1. Disruptor简单介绍2. 为什么Disruptor如此之快3. Disruptor结构分析 1. Disruptor ...
- Disruptor使用
Disruptor作者,介绍Disruptor能每秒处理600万订单.这是一个可怕的数字. disruptor之所以那么快,是因为内部采用环形队列和无锁设计.使用cas来进行并发控制.通过获取可用下标 ...
- 高性能队列Disruptor系列3--Disruptor的简单使用(译)
简单用法 下面以一个简单的例子来看看Disruptor的用法:生产者发送一个long型的消息,消费者接收消息并打印出来. 首先,我们定义一个Event: public class LongEvent ...
- Disruptor的简单介绍与应用
前言 最近工作比较忙,在工作项目中,看了很多人都自己实现了一套数据任务处理机制,个人感觉有点乱,且也方便他人的后续维护,所以想到了一种数据处理模式,即生产者.缓冲队列.消费者的模式来统一大家的实现逻辑 ...
- spring与disruptor集成的简单示例[z]
[z]https://www.jb51.net/article/135475.htm disruptor不过多介绍了,描述下当前的业务场景,两个应用A,B,应用 A 向应用 B 传递数据 . 数据传送 ...
- 架构师养成记--15.Disruptor并发框架
一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...
- 并发框架Disruptor浅析
1.引言 Disruptor是一个开源的Java框架,它被设计用于在生产者—消费者(producer-consumer problem,简称PCP)问题上获得尽量高的吞吐量(TPS)和尽量低的延迟.D ...
- LMAX Disruptor—多生产者多消费者中,消息复制分发的高性能实现
解决的问题 当我们有多个消息的生产者线程,一个消费者线程时,他们之间如何进行高并发.线程安全的协调? 很简单,用一个队列. 当我们有多个消息的生产者线程,多个消费者线程,并且每一条消息需要被所有的消费 ...
- Disruptor 极速体验
已经不记得最早接触到 Disruptor 是什么时候了,只记得发现它的时候它是以具有闪电般的速度被介绍的.于是在脑子里, Disruptor 和"闪电"一词关联了起来,然而却一直没 ...
随机推荐
- k8s配置ingress的https访问
一.部署步骤 1.安装nginx-ingress-controller 2.创建secret绑定证书 3.创建测试服务 4.创建ingress 5.测试https访问 二.安装nginx-ingres ...
- 高并发解决方案之 mysql悲观锁:select ... for update
select ... for update 场景:多个进程都先读后写咋办,需要的是让他们串行执行. 比如库存的减少.一般这些操作都是很长一串并且是开启事务的.如果库存刚开始读的时候是1,而立马另一个进 ...
- Jenkins集成appium自动化测试
一,引入问题 自动化测试脚本绝大部分用于回归测试,这就需要制定执行策略,如每天.代码更新后.项目上线前定时执行,才能达到最好的效果,这时就需要进行Jenkins集成. 不像web UI自动化测试可以使 ...
- 更改yum源
1)cd /etc/yum.repos.d/ 2)wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/C ...
- Unity学习笔记——坐标转换(2)
子物体与父物体 子物体与父物体的关系类似于人与地球的关系,地球无论自转还是公转,对于地球上的我们来说,前后左右的方向不会变,因此在Unity中当我们旋转或是移动父物体时,子物体跟随父物体变化,但tra ...
- JavaScript基础学习之二
目录 JavaScript HTML DOM事件 事件触发1 事件触发2 addEventListener() 事件冒泡或事件捕获? 事件委托 removeEventListener() 方法 事件对 ...
- 解决idea xml文件中的中文注释乱码
今天用idea编译xml文件的时候报错了,打开编译好的xml文件发现是中文乱码问题,按照百度上靠前的办法设置了一下,并没有解决乱码问题,在当前项目中直接设置就是不生效,最后删掉编译好的 target/ ...
- 解决com.alibaba.excel.exception.ExcelGenerateException: Can not close IO.
我在使用easycel导出到zip包中时,出现了这个问题.各种文件输出时产生的问题其实大同小异 查看了一些网上的文章,还有github上关于此bug的issue,总算是理清并解决了. 解决方法一 主要 ...
- C知识点
1.变量在内存中所占存储空间的首地址,称为该变量的地址:而变量在存储空间中存放的数据,即变量的值. C语言中,指针就是变量的地址.一个变量的值是另一个变量的地址,且变量类型相同,则称该变量为指针变量. ...
- [Mac技巧] 你真的会使用Mac的“聚焦搜索”吗?
Mac的"聚焦搜索"是对Mac整个磁盘的全局搜索,搜索起来极其便捷,但也常被使用者忽略使用. 以下列出比较常用的几个场景供使用者参考 场景一:文件在哪儿,要立即查看? 1.打开&q ...