Disruptor是一个开源的并发框架,提供了类似于Java中有界队列的功能,主要用于生产消费者场景。与Java原生并发队列不同的是,Disruptor高度优化,在单机上可以轻松跑到千万级别的tps与ns级别的延时
Disruptor的设计思想
- 无锁:加锁会带来线程的切换,这个是非常耗时的,Disruptor使用了CAS和自旋,提高了性能。同样也使用了序号栅栏和序号配合使用避免了锁和CAS操作。
- 消除伪共享:现代处理器的缓存用法对于成功的高性能操作至关重要。我们的操作系统用64字节的缓存行进行缓存操作。如果有两个变量在相同的缓存行中,且这两个变量是被不同线程写入,这是就会存在写入争用问题,导致缓存行失效。Disruptor用在Long变量的左右增加其他7个填充Long变量,让变量单独存在一个缓存行中,消除了伪共享。
- 环形缓冲:Disruptor中使用了环形结构,无需浪费大量的空间存储,可以循环利用。底层使用数组结构,而不是使用链表,性能要更好,每个元素都是在在启动时预分配的。所有的元素在Disruptor实例生存周期中都将重用并一直存在。元素在消费者消费完成之后,生产者会对当前未知的元素进行重用。这样避免了垃圾的产生。
Disruptor Quick Start
我们先写一个hello world 程序。要实现Disruptor需要四步:
- 建立一个工厂Event类,用于创建Event类实例对象。
- 需要有一个监听事件类,用于处理数据(Event类)。
- 实例化Disruptor实例,配置一系列参数,编写Disruptor核心组件。
- 编写生产者组件,向Disruptor容器中去投递数据。
首先我们创建Event类。
public class OrderEvent {
private long value;
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
}
创建工厂类,返回一个未赋值的OrderEvent实例。
public class OrderEventFactory implements EventFactory<OrderEvent> {
@Override
public OrderEvent newInstance() {
return new OrderEvent();
}
}
编写一个消费者,这里需要实现一个接口。
public class OrderEventHandler implements EventHandler<OrderEvent> {
@Override
public void onEvent(OrderEvent orderEvent, long l, boolean b) throws Exception {
System.out.println("消费者" + orderEvent.getValue());
}
}
编写生产者,这里需要接收RingBuffer实例,用来发送消息。
public class OrderEventProducer {
private RingBuffer<OrderEvent> ringBuffer;
public OrderEventProducer(RingBuffer<OrderEvent> ringBuffer) {
this.ringBuffer = ringBuffer;
}
public void sendData(long value) {
//1 在生产者发送消息时,首先需要从我们的ringBuffer里面 获取一个可用的序号
long sequence = ringBuffer.next();
try {
//2 根据这个序号,找到具体的"OrderEvent"元素。注意:此时获取的OrderEvent对象是一个没有被赋值的"空对象"
OrderEvent orderEvent = ringBuffer.get(sequence);
//3 进行实际的赋值操作
orderEvent.setValue(value);
} finally {
//提交发布操作
ringBuffer.publish(sequence);
}
}
}
主方法中根据上面的步骤实现Disruptor简单的生产和消费。
public class Main {
public static void main(String[] args) {
//准备参数工作
OrderEventFactory orderEventFactory = new OrderEventFactory();
int ringBufferSize = 1024 * 1024;
ThreadFactory springThreadFactory = new CustomizableThreadFactory("springThread-pool-");
/**
* 1 orderEventFactory: 消息(Event)工厂对象
* 2 ringBufferSize: 容器的长度
* 3 threadFactory: 线程池工厂
* 4 ProducerType: 单生产者或多生产者
* 5 waitStrategy: 等待策略
*/
//1. 实例化Disruptor对象
Disruptor<OrderEvent> disruptor = new Disruptor(orderEventFactory,
ringBufferSize,
springThreadFactory,
ProducerType.SINGLE,
new BlockingWaitStrategy());
//2. 添加消费者监听(构建Disruptor与消费者的一个关联关系)
disruptor.handleEventsWith(new OrderEventHandler());
//3. 启动disruptor
disruptor.start();
//4. 获取实际存储数据的容器:RingBuffer
RingBuffer<OrderEvent> ringBuffer = disruptor.getRingBuffer();
//5. 创建生产者
OrderEventProducer producer = new OrderEventProducer(ringBuffer);
for(long i=0;i<100;i++) {
producer.sendData(i);
}
//6. 关闭资源
disruptor.shutdown();
}
}
启动之后打印消费日志。
消费者0
消费者1
消费者2
...
消费者98
消费者99
Disruptor 串行消费和并行消费
首先我们创建Event类,模拟交易信息。
public class Trade {
private String id;
private String name;
private double price;
private AtomicInteger count = new AtomicInteger(0);
public String getName() {
return name;
}
public String getId() {
return id;
}
public AtomicInteger getCount() {
return count;
}
public double getPrice() {
return price;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setCount(AtomicInteger count) {
this.count = count;
}
public void setPrice(double price) {
this.price = price;
}
}
交易信息生产者。TradePubshlisher中使用Disruptor进行生产event,通过循环设置一次发送的event数量,需要传入的对象要实现EventTranslator接口。
public class TradePubshlisher implements Runnable {
private CountDownLatch latch;
private Disruptor<Trade> disruptor;
private static int PUBLISH_COUNT = 10;
public TradePubshlisher(CountDownLatch latch, Disruptor<Trade> disruptor) {
this.latch = latch;
this.disruptor = disruptor;
}
@Override
public void run() {
//新的提交任务方式
for(int i=0;i<PUBLISH_COUNT;i++) {
disruptor.publishEvent(new TradeEventTranslator());
}
latch.countDown();
}
}
class TradeEventTranslator implements EventTranslator<Trade> {
private Random random = new Random();
@Override
public void translateTo(Trade trade, long l) {
this.generateTrade(trade);
}
private void generateTrade(Trade event) {
event.setPrice(random.nextDouble() * 9999);
}
}
创建5个消费者。这里可以通过两种方式实现,实现EventHandler接口或实现WorkHandler。
public class Handler1 implements EventHandler<Trade>, WorkHandler<Trade> {
@Override
public void onEvent(Trade trade, long l, boolean b) throws Exception {
this.onEvent(trade);
}
@Override
public void onEvent(Trade trade) throws Exception {
System.err.println("handler 1 : SET NAME");
trade.setName("H1");
Thread.sleep(1000);
}
}
public class Handler2 implements EventHandler<Trade> {
@Override
public void onEvent(Trade trade, long l, boolean b) throws Exception {
System.err.println("handler 2 : SET ID");
trade.setId(UUID.randomUUID().toString());
Thread.sleep(2000);
}
}
public class Handler3 implements EventHandler<Trade> {
@Override
public void onEvent(Trade trade, long l, boolean b) throws Exception {
System.err.println("handler 3 : NAME: " + trade.getName() + ", ID: " + trade.getId() + " INSTANCE" +