Disruptor 是苹国外厂本易公司LMAX开发的一个高件能列,研发的初夷是解决内存队列的延识问顾在性能测试中发现竟然与10操作处于同样的数量级),基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCn演讲后,获得了业界关注,201年,企业应用软件专家Martin Fower专门撰写长文介绍。同年它还获得了Oradle官方的Duke大奖。目前,包括Apache StomCame、 L0g4 2在内的很多知名项目都应用了Disrupior以获取高性能。注意,这里所说的队列是系统内部的内存队列,而不是Kaka这样的分布式队列。
Github: https://github.com/LMAX-Exchange/disruptor
Disruptor实现了队列的功能并且是一个有界队列,可以用于生产者-消费者模型。
Disruptor的设计方案
Disruptor通过以下设计来解决队列速度慢的问题:
环形数组结构
为了避免垃圾回收,采用数组而非链表。同时,数组对处理器的缓存机制更加友好(空间局部性原理)。
元素位置定位
数组长度2n,通过位运算,加快定位的速度,下标采取递增的形式,不用担心index溢出的问题。index是ong类型,即使100万QPS的处理速度,也需要30万年才能用完.
无锁设计
每个生产者或者消费者线程,会先申请可以操作的元素在数组中的位置,申请到之后,直接在该位置写入或者读取数据。
利用缓存行填充解决了伪共享的问题
利用缓存行填充,定义了可为null的七个元素填充一个空的缓存行。
protected long p1, p2, p3, p4, p5, p6, p7;
实现了基于事件驱动的生产者消费者模型 (观察者模式)
消费者时刻关注着队列里有没有消息,一旦有新消息产生,消费者线程就会立刻把它消费
RingBuffer数据结构
使用RinaBufer来作为队列的数据结构,RinaBuffer就是一个可自定义大小的环形数组。除数组外还有一个席列号(seouence),用以指向下一个可用的元素,供生产者与消费者使用,原理图如下:
Disrupior要求没置数组长度为2的次幕。
在知道索引(ndex)下标的情况下,存与取数组上的元素时间复杂度只有0(1),而这个index我们可以通过序列号与数组长度取模来计算得出,index=sequence % entries.length。也可以用位运算来计算效率更高,此时aray.length必须是2的幂次方, index=sequeoe&(entres.length-1)
当所有位置都放满了,再放下一个时,就会把0号位置覆盖掉。
问题: 能覆盖数据是否会导致数据丢失呢?
要覆盖数据时,会执行一个策略,Disruptor给提供多种策略,比较常用的:
1,BlockingWaistrategy策路
常见且默认的等待策略,当这个队列里满了,不执行覆盖,而是阻塞等待,使用ReenranLock+Condition实现阻塞,最节省COU,但高并发场景下性能最差。适合CPU资源紧缺,吞吐量和延迟并不重要的场景。
2,Sleepinowaitstraterv策略
会在循环中不新等待数先进行自等待如果不功,则使用Thread,veld让出CPU 并最终使用LockSuppor.parkNanos(1L)进行线程休眠,以确保不占用太多的CPU资源。因此这个策略会产生比较高的平均延时。典型的应用场景就是异步日志。
3,YeldingWaistrate策略
这个策略用于低延时的场合。消费者线程会不新循环监控缓中区变化,在循环内部使用Thread,yed0让出CPU别的线理执行时间。如果要一个高性能的系统,并且对延时比较有严格的要求,可以考虑这种策略。
4,BusySpinwaitstrategy策略
采用死盾环,消费者线程会尽最大努力监控缓冲区的变化。对证时北常苛刻的场是使用。CPU核数以须大于消费者线理数量。推荐在线程绑定到固定的CPU的场景下使用。
Disruptor 核心概概念
RingBuffer (环形缓冲区): 基于数组的内存级别缓存,是创建sequencer(序号)与定义WaitStrategy(拒绝策略)的入口。
Disruptor (总体执行入口): 对RingBuffer的封装,持有RingBuffer、消费者线程池Executor、消费之集合ConsumerRepositorv等引用。
Sequence (序号分配器) :
对RingBufer中的元素进行序号标记,通过顺序递增的方式来管理进行交换的数据(事件EVent),一个Sequence可以跟踪标识某个事件的处理
进度,同时还能消除伪共享。
Sequencer (数据传输器) :Sequencer里面包含了Sequence,是Disruptor的核心,Seauencer有两个实现类: SingleProducerSequencer(单生产者实现)MultiProducerSeguencer(多生产者实现),Seguencer主要作用是实现生产者和消费者之间快速、正确传递数据的并发算法SequenceBarier(消费者屏): 用于控制RingBufer的Producer和Consumer之间的平衡关系,并且决定了Consumer是否还有可处理的事件的逻辑。WaitStrategy(消费者等待策略): 决定了消费者如何等待生产者将Event生产进Disruptor,WaitStrategy有多种实现策略Event: 从生产者到消费者过程中所处理的数据单元,Event由使用者自定义。
EventHandler: 由用户自定义实现,就是我们写消费者逻辑的地方,代表了Disruptor中的一个消费者的接口。
EventProcessor:这是个事件处理器接口,实现了Runnable,处理主要事件循环,处理Event,拥有消费者的Sequence 。