当前位置: 首页 > 科技观察

Disruptor的使用方法(一)Ringbuffer的特色

时间:2023-03-14 18:22:30 科技观察

最近我们开源了LMAXDisruptor,这是我们交易系统中吞吐量最快的(LMAX是一种新型的交易平台,号称可以处理百万级订单)其次用单线程)是关键原因。我们为什么要开源它?我们意识到关于高性能编程领域的一些传统智慧有点偏离。我们找到了一种更好更快的方式来在线程之间共享数据,不公开与业界共享是自私的。同时,开源也让我们感觉更酷。从这个站点,您可以下载一份文档,解释Disruptor是什么以及它为何如此高效。这篇文档的写作过程我并没有过多的参与,只是简单地插入了一些标点符号,重新组织了一些我看不懂的句子,但很高兴我的写作水平还是从中得到了提升。我发现一次解释所有内容有点困难,所以我将逐条解释它们以适合我的NADD观众。首先介绍ringbuffer。我对Disruptor的最初印象是环形缓冲区。但后来我意识到,虽然ringbuffer是整个模式(Disruptor)的核心,但Disruptor对ringbuffer的访问控制策略才是真正的关键。环形缓冲区究竟是什么?好吧,顾名思义,它就是一个环(end-to-endring),你可以把它当作一个缓冲区,在不同的上下文(线程)之间传递数据。(好吧,这是我用绘图板手绘的,我正在尝试画草图,希望我的强迫症不要让我画出完美的圆和线)基本上,ringbuffer有一个索引,指向array下一个可用元素。(校对注:下图右图为序号,指向数组的下标4。)随着你不断填充这个buffer(也可能有相应的读),序号会不断的增加增加直到绕过环。要在数组中找到当前序号指向的元素,可以使用mod运算:sequencemodarraylength=arrayindex以上面的ringbuffer为例(java的mod语法):12%10=2。简单的。事实上,上图中的ringbuffer只有10个slot完全是个意外。如果槽数为2的N次方,则更有利于基于二进制的计算机进行计算。(校对注:如果2的N次方换算成二进制,就是1000,100,10,1这样的数,sequence&(arraylength-1)=arrayindex,比如一共有8个slot,3&(8-1)=3,HashMap就是用这种方法来定位数组元素的,比取模更快。)那又如何呢?如果你阅读维基百科中关于环形缓冲区的条目,你会发现我们的实现与它最大的区别是没有尾指针。我们只是维护一个指向下一个可用位置的序列号。这种实现是经过深思熟虑的——我们选择使用环形缓冲区的最初原因是为了提供可靠的消息传递。我们需要保存服务发送过的消息,这样当另一个服务通过nak(校对注:拒绝信号)告诉我们消息没有成功接收时,我们可以重新发送给他们。听起来环形缓冲区非常适合这种情况。它维护一个指向末尾的序列号。当它收到一个nak(校对注:拒绝信号)请求时,它可以重新发送从那个点到当前序号的所有消息:我们实现的ringbuffer和常用队列之间的区别是我们不删除里面的数据buffer,也就是说,这些数据一直保存在buffer中,直到有新的数据覆盖它们。这就是为什么与维基百科版本相比我们不需要尾指针。ringbuffer本身不控制是否需要重叠(确定重叠是否是生产者-消费者行为模式的一部分——如果你等着我写关于它们的博客,请自己查看Disruptor项目)。为什么这么好?ringbuffer之所以采用这种数据结构,是因为它在可靠的消息传递方面有很好的表现。这已经足够了,但它还有其他一些优点。首先,因为它是一个数组,所以它比链表更快,并且具有易于预测的访问模式。(译者注:数组中元素的内存地址是连续存储的)。这是CPU缓存友好的——即在硬件层面,数组中的元素是预加载的,所以在ringbuffer中,CPU不需要时不时去主存加载数组中的下一个元素.(校对注:因为只要一个元素被加载到cacheline中,其他几个相邻的元素也会被加载到同一个cacheline中)其次,可以为数组预分配内存,使数组对象一直存在(除非程序终止)。这意味着不需要在垃圾收集上花费大量时间。另外,与链表不同的是,每添加一个对象都需要创建一个节点对象——相应地,当一个节点被删除时,需要进行相应的内存清理操作。遗漏的部分我在这篇文章中没有介绍如何避免ringbuffer重叠,以及如何读写ringbuffer。你可能已经注意到,我把ringbuffer比作链表这样的数据结构,因为我不认为链表是解决实际问题的标准答案。当您将Disruptor与基于队列的实现进行比较时,事情会变得有趣。队列通常专注于维护队列的头尾元素,添加和删除元素等。所有这些我在ringbuffer中没有提到,这是因为ringbuffer不负责这些事情,我们将这些操作移到了数据结构(ringbuffer)外部原文链接:http://ifeve.com/ringbuffer/翻译链接:http://ifeve.com/dissecting-disruptor-whats-so-special/