首页 » java » 正文

LMAX的Disruptor的RingBuffer学习笔记

并发queue实现的传统方法

链表:节点分散,不利于cache和批量读取,分配节点需要大量GC,size/head/tail有大量的竞争,存在CPU缓存的伪竞争问题。

数组:size/head/tail一样有大量的竞争,传统方法是在所有的写操作上做互斥,效率低下,这几个字段写在一起存在CPU缓存的伪竞争。

减少竞争点

RingBuffer也是个数组,不过,减少了竞争点,如果有多个producer, 即使使用CAS,写入标识仍然有竞争,如果只有一个producer则写就没有竞争,而Consumer只记录自己的读取标识位,并不断地监听写标识位作为界限。

Lock-free

不适用传统的重量级别的锁,而是使用CAS的乐观锁。

解决伪竞争

双核心CPU都有64字节的缓存,假如每个都加载了引用r1, r2, 一个更新r1, 一个更新r2,CPU会在硬件级别做互斥,而并没有必要的互斥操作,r1和r2没有任何关系,所以,叫做伪互斥,RingBuffer通过在r1后面填充字节来解决伪互斥问题,也就是读写指针上来填充满64字节的CPU缓冲区。

等待策略

生产者快于消费者,或者消费者快于生产者,并且填满了Ringbuffer或者RingBuffer为空,则需要等待,等待策略如下:

BlockingWaitStrategy:默认的,最传统和最安全的,但是效率低下,占用CPU最少

SleepingWaitStrategy:占用CPU高,适合异步写日志,处理延迟高,因为要睡眠
YieldingWaitStrategy:占用CPU高,超线程开启,释放CPU服务其他线程
BusySpinWaitStrategy:占用CPU高,超线程未开启,独占CPU

后三者通过占用大量CPU时间来提高整体的吞吐量,提高效率,其实就是需要等待的时候没有阻塞和挂起,而是不断地轮询,占用CPU确实非常高。

参考

官网,等待策略的介绍:https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started
原理介绍:http://www.360doc.com/content/15/0131/11/11962419_445188581.shtml
多生产者效率要远低于单生产者:http://stackoverflow.com/questions/18997398/lmax-disruptor-is-too-slow-in-multi-producer-mode-compared-to-single-producer-mo
伪竞争压测结果:http://ifeve.com/false-sharing/
伪竞争原理:http://ifeve.com/disruptor-cacheline-padding/
使用样例:http://www.jdon.com/42466
代替菱形结构:http://ifeve.com/dissecting-disruptor-wiring-up-cn/
实现原理:http://huangyunbin.iteye.com/blog/1944232
坑,CPU利用率极高:http://maoyidao.iteye.com/blog/1663193
实现原理:http://www.tuicool.com/articles/eIbUzeu/

重点知识

1. 缓存填充解决为伪竞争。
2. sleep等待策略占用CPU太高,默认是10ns,可调得更长,或者更换等待策略。
3. LMAX是一个新型的交易平台,号称能够单线程每秒处理数百万的订单。还有一个衡量,微妙级别的延迟,可以达到100k的吞吐量。

本文共 1 个回复

Comments are closed.