1、什么是Disruptor? Disruptor 是实现了“队列”的功能,而且是一个有界队列。那么它的应用场景自然就是“生产者-消费者”模型的应用场合了。 可以拿 JDK 的 BlockingQueue 做一个简单对比,以便更好地认识 Disruptor 是什么。 我们知道 BlockingQueue 是一个 FIFO 队列,生产者(Producer)往队列里发布(publish)一项事件(或称之为“消息”也可以)时,消费者(Consumer)能获得通知;如果没有事件时,消费者被堵塞,直到生产者发布了新的事件。 这些都是 Disruptor 能做到的,与之不同的是,Disruptor 能做更多: 同一个“事件”可以有多个消费者,消费者之间既可以并行处理,也可以相互依赖形成处理的先后次序(形成一个依赖图); 预分配用于存储事件内容的内存空间; 针对极高的性能目标而实现的极度优化和无锁的设计; 自己总结:Disruptor实现了‘队列’的功能,是‘生产者-消费者’模型的应用场合 它不仅仅能够实现生产者--->数据<---消费者,也能够实现同一'事件'可以有多个消费者并行处理,也可以相互依赖形成处理的先后顺序 2、Disruptor的核心概念: Ring Buffer:环形缓冲区,他是负责对通过Disruptor进行交换数据(事件)进行存储和更新 SequenceDisruptor:通过顺序递增的序号来编号,一个Sequence用于跟踪标识别某个特定的事件处理者,还有个作用是:防止不同的Sequence之间的CPU缓存伪共享的问题(注:这是Disruptor实现高性能的关键点) Sequencer:用来定义生产者和消费者之间快速、正确的传递数据的并发算法 Sequence Barrier:用于保持对RingBuffer的 main published Sequence 和Consumer依赖的其它Consumer的 Sequence 的引用。 Sequence Barrier 还定义了决定 Consumer 是否还有可处理的事件的逻辑。 wait Strategy:定义Consumer如何进行等待下个时间的策略 Event:生产者和消费者之间进行交换的数据被称为时间(自定义的) EventProcessor:持有特定消费者(consumer)的sequence,并提供调用事件处理实现的事件循环 EventHandler:Disrutor定义的时间处理接口(用户自己实现) Producer:生产者 整体的运行流程图在:https://www.cnblogs.com/haiq/p/4112689.html这个博客上 3、如何使用Disruptor: 3.1:定义时间 事件就是通过Disruptor进行交换的数据类型 public class LongEvent{ private long value; public void set(long value){ this.value = value; } } 3.2定义事件工厂 Disruptor通过EventFactory在RingBuffer中预创建Event的实例 public class LongEventFactory implements EventFactory<LongEvent>{ public LongEvent new Instance(){ return new LongEvent(); } } 3.3定义事件处理的具体实现 public class LongEventHandler implements EventHandler<LongEvent>{ public void onEvent(LongEvent event, long sequence, boolean endOfBatch){ System.out.println("Event:"+event): } } 3.4定义用于事件处理的线程池 Disruptor通过java.util.concurrent.ExecutorService提供的线程来触发Consumer的事件处理。例如: ExecutorService executor = Executors.newCachedThreadPool(); 3.5指定等待策略 Disruptor 定义了 com.lmax.disruptor.WaitStrategy 接口用于抽象 Consumer 如何等待新事件,这是策略模式的应用。 Disruptor 提供了多个 WaitStrategy 的实现,每种策略都具有不同性能和优缺点,根据实际运行环境的 CPU 的硬件特点选择恰当的策略,并配合特定的 JVM 的配置参数,能够实现不同的性能提升。 例如: BlockingWaitStrategy、SleepingWaitStrategy、YieldingWaitStrategy 等,其中, BlockingWaitStrategy 是最低效的策略,但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现; SleepingWaitStrategy 的性能表现跟 BlockingWaitStrategy 差不多,对 CPU 的消耗也类似,但其对生产者线程的影响最小,适合用于异步日志类似的场景; YieldingWaitStrategy 的性能是最好的,适合用于低延迟的系统。在要求极高性能且事件处理线数小于 CPU 逻辑核心数的场景中,推荐使用此策略;例如,CPU开启超线程的特性。 WaitStrategy BLOCKING_WAIT = new BlockingWaitStrategy(); WaitStrategy SLEEPING_WAIT = new SleepingWaitStrategy(); WaitStrategy YIELDING_WAIT = new YieldingWaitStrategy(); 3.6启动 Disruptor //生成数据的 EventFactory<LongEvent> eventFactory = new LongEventFactory(); //创建缓存池的 ExecutorService executor =Excutors.newSingleThreadExecutor(); int ringBufferSize = 1024*1024; //创建disruptor Disruptor<LongEvent> disruptor = new Disruptor<LognEvent)(eventFactory,ringBufferSize,executor,ProducerType.SINGLE,new YieldingWaitStrategy()); EventHandler<LongEvent> eventHandler = new LongEventHandler(); disruptor.handleEventsWith(eventHandler); disruptor.start(); 3.7发布事件 Disruptor的事件发布过程是一个两阶段提交的过程 第一步:先从RingBuffer获取下一个可以写入的事件序号; 第二步:获取对应的事件内容,将数据写入事件对象 第三步:将时间提交到RingBuffer RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer(); long sequence = ringBuffer.next();//请求的下一个事件序号 trt{ LongEvent event = ringBuffer.get(sequence);//获取改序号对应的事件对象 long data = getEventData();//从RingBuffer中获取到数据内容 event.set(data);//封装成实体 }finally{ ringBuffer.publish(sequence);//发布事件 } 3.8关闭 Disruptor disruptor.shutdown();//关闭 disruptor,方法会堵塞,直至所有的事件都得到处理; executor.shutdown();//关闭 disruptor 使用的线程池;如果需要的话,必须手动关闭, disruptor 在 shutdown 时不会自动关闭;
Disruptor并发框架的理解
最新推荐文章于 2022-03-09 17:02:51 发布