什么是Disruptor
Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题,基于Disruptor开发的系统单线程能支撑每秒600万订单。除金融领域之外,其他应用也可以使用Disruptor来提升性能,目前,包括Apache Storm、Camel、Log4j2在内的很多知名项目都应用了Disruptor。
其实Disruptor与其说是一个框架不如说是一种设计思路,这个设计思路对于存在“并发、缓冲区、生产者—消费者模型、事务处理”这些元素的程序来说,Disruptor提出了一种大幅提升性能(TPS)的方案。
那么,Disruptor和传统的常用的一些生产者消费者模型,到底有哪些优势呢?
常见队列
| 队列 | 有界性 | 锁 | 数据结构 |
|---|---|---|---|
| ArrayBlockingQueue | bounded | 加锁 | arraylist |
| LinkedBlockingQueue | optionally-bounded | 加锁 | linkedlist |
| ConcurrentLinkedQueue | unbounded | 无锁 | linkedlist |
| LinkedTransferQueue | unbounded | 无锁 | linkedlist |
| PriorityBlockingQueue | unbounded | 加锁 | heap |
| DelayQueue | unbounded | 加锁 | heap |
平时常见的用来实现生产消费模型如上,实际的生产的环境,考虑线程安全+有界(防止生产过快,大量占用内存,发生OOM),符合条件的只有ArrayBlockingQueue,但是看过ArrayBlockingQueue源码的同学都清楚,内部是通过加锁的方式实现的线程安全,同时会产生“伪共享”的问题(不展开讨论)
为什么不用MQ
说实话,开始我也没太GET到这个点,使用市面上常见的MQ也能很好的实现生产消费模型,而且,我相信大家平时也有很多基于MQ设计的经验,优点就不细说了。后来和老大的一次谈话才明白核心的问题,耗时,耗时,耗时,重要的事情说三遍。对于交易所来说,要尽量减少用户成单的时间,引入MQ,会比Disruptor来说大概多20ms(没亲自验证)的耗时(毕竟一个是纯内存,一个要加上双端的网络通信时间),而对于用户来说,可能会因为这部分耗时损失一部分利益。
Disruptor核心设计
可以看到,整个设计围绕RingBuffer展开,生产者把消息写入RingBuffer中,消费者消费RingBuffer里的数据”,那么,由此会想到一些问题
- 单个生产者如何写这个“环”
- 单个消费者如何消费这个“环”
- 多个生产者如何写这个“环”
- 多个消费者如何消费这个“环”
- 生产速度过快,是否会产生覆盖?
- 消费速度过快,该怎样等待消息的生产?
以上问题,后续系列文章,将会一一解答。