Dissecting the Disruptor: What’s so special about a ring buffer?

原文地址:http://mechanitis.blogspot.com/2011/06/dissecting-disruptor-whats-so-special.html(因被墙移到墙内) 作者:Trisha

Recently we open sourced the LMAX Disruptor, the key to what makes our exchange so fast.  Why did we open source it?  Well, we’ve realised that conventional wisdom around high performance programming is… a bit wrong. We’ve come up with a better, faster way to share data between threads, and it would be selfish not to share it with the world.  Plus it makes us look dead clever.

On the site you can download a technical article explaining what the Disruptor is and why it’s so clever and fast.  I even get a writing credit on it, which is gratifying when all I really did is insert commas and re-phrase sentences I didn’t understand.

However I find the whole thing a bit much to digest all at once, so I’m going to explain it in smaller pieces, as suits my NADD audience.

First up – the ring buffer.  Initially I was under the impression the Disruptor was just the ring buffer.  But I’ve come to realise that while this data structure is at the heart of the pattern, the clever bit about the Disruptor is controlling access to it.

What on earth is a ring buffer?
Well, it does what it says on the tin – it’s a ring (it’s circular and wraps), and you use it as a buffer to pass stuff from one context (one thread) to another:

(OK, I drew it in Paint.  I’m experimenting with sketch styles and hoping my OCD doesn’t kick in and demand perfect circles and straight lines at precise angles).

So basically it’s an array with a pointer to the next available slot.

As you keep filling up the buffer (and presumable reading from it too), the sequence keeps incrementing, wrapping around the ring:

To find the slot in the array that the current sequence points to you use a mod operation:

sequence mod array length = array index

So for the above ring buffer (using Java mod syntax): 12 % 10 = 2. Easy.

Actually it was a total accident that the picture had ten slots.  Powers of two work better because computers think in binary.

So what?
If you look at Wikipedia’s entry on Circular Buffers, you’ll see one major difference to the way we’ve implemented ours – we don’t have a pointer to the end.  We only have the next available sequence number.  This is deliberate – the original reason we chose a ring buffer was so we could support reliable messaging.  We needed a store of the messages the service had sent, so when another service sent anak to say they hadn’t received some messages, it would be able to resend them.

The ring buffer seems ideal for this.  It stores the sequence to show where the end of the buffer is, and if it gets a nak it can replay everything from that point to the current sequence:

The difference between the ring buffer as we’ve implemented it, and the queues we had traditionally been using, is that we don’t consume the items in the buffer – they stay there until they get over-written.  Which is why we don’t need the “end” pointer you see in the Wikipedia version.  Deciding whether it’s OK to wrap or not is managed outside of the data structure itself (this is part of the producer and consumer behaviour – if you can’t wait for me to get round to blogging about it, check out the Disruptor site).

And it’s so great because…?
So we use this data structure because it gives us some nice behaviour for reliable messaging.  It turns out though that it has some other nice characteristics.

Firstly, it’s faster than something like a linked list because it’s an array, and has a predictable pattern of access.  This is nice and CPU-cache-friendly – at the hardware level the entries can be pre-loaded, so the machine is not constantly going back to main memory to load the next item in the ring.

Secondly, it’s an array and you can pre-allocate it up front, making the objects effectively immortal.  This means the garbage collector has pretty much nothing to do here.  Again, unlike a linked list which creates objects for every item added to the list – these then all need to be cleaned up when the item is no longer in the list.

The missing pieces
I haven’t talked about how to prevent the ring wrapping, or specifics around how to write stuff to and read things from the ring buffer.  You’ll also notice I’ve been comparing it to a data structure like a linked list, which I don’t think anyone believes is the answer to the world’s problems.

The interesting part comes when you compare the Disruptor with an implementation like a queue.  Queues usually take care of all the stuff like the start and end of the queue, adding and consuming items, and so forth.  All the stuff I haven’t really touched on with the ring buffer.  That’s because the ring buffer itself isn’t responsible for these things, we’ve moved these concerns outside of the data structure.

For more details you’re just going to have to read the paper or check out the code.  Or watch Mike and Martin at QCon San Francisco last year.  Or wait for me to have a spare five minutes to get my head around the rest of it. 

时间: 2024-07-30 23:10:07

Dissecting the Disruptor: What’s so special about a ring buffer?的相关文章

Dissecting the Disruptor: How do I read from the ring buffer?

The next in the series of understanding the Disruptor pattern developed at LMAX. After the last post we all understand ring buffers and how awesome they are.  Unfortunately for you, I have not said anything about how to actually populate them or read

Dissecting the Disruptor: Why it’s so fast (part one) – Locks Are Bad

原文地址:http://mechanitis.blogspot.com/2011/07/dissecting-disruptor-why-its-so-fast.html(因前方有墙,所以我移到墙内) Martin Fowler has written a really good article describing not only the Disruptor, but also how it fits into the architecture at LMAX.  This gives so

Dissecting the Disruptor: Why it’s so fast (part two) – Magic cache line padding

原文地址:http://mechanitis.blogspot.com/2011/07/dissecting-disruptor-why-its-so-fast_22.html(因有墙移到墙内) We mention the phrase Mechanical Sympathy quite a lot, in fact it's even Martin's blog title.  It's about understanding how the underlying hardware oper

Dissecting the Disruptor: Demystifying Memory Barriers

原文地址:http://mechanitis.blogspot.com/2011/08/dissecting-disruptor-why-its-so-fast.html (因有墙,移到墙内) My recent slow-down in posting is because I've been trying to write a post explaining memory barriersand their applicability in the Disruptor. The proble

Dissecting the Disruptor: Writing to the ring buffer

原文地址:http://mechanitis.blogspot.com/2011/07/dissecting-disruptor-writing-to-ring.html(因被墙移到墙内)  作者:Trisha This is the missing piece in the end-to-end view of the Disruptor.  Brace yourselves, it's quite long.  But I decided to keep it in a single blo

并发译文翻译计划(二)

Doug Lea 的文献 Synchronizer Framework  译者:ClarenceAu (已翻译完成,在校对) Fork/Join  译者:Alex(陆续发表中) Java Concurrency Constructs 译者:萧欢(已翻译完成) Cancellation 译者:丁一  (已翻译完成) 以下文章来自:https://code.google.com/p/disruptor/wiki/BlogsAndArticles 如何使用Disruptor What's so spe

如何使用Disruptor(二)如何从Ringbuffer读取

英文原文:http://ifeve.com/dissecting-the-disruptor-how-do-i-read-from-the-ring-buffer/ 作者:Trisha  译者:古圣昌  校对:方腾飞 从上一篇文章中我们都了解了什么是Ring Buffer以及它是如何的特别.但遗憾的是,我还没有讲述如何使用Disruptor向Ring Buffer写数据和从Ring Buffer中读取数据. ConsumerBarrier与消费者 这里我要稍微反过来介绍,因为总的来说读取数据这一

剖析Disruptor:为什么会这么快?(一)锁的缺点

原文:http://ifeve.com/disruptor-locks-are-bad/ 作者:Trisha's  译者:张文灼,潘曦  整理和校对:方腾飞,丁一 Martin Fowler写了一篇非常好的文章,里面不仅提到了Disruptor,而且还解释了Disruptor 如何应用在LMAX的架构里.里面有提及了一些目前没有涉及的概念,但最经常问到的问题是 "Disruptor究竟是什么?". 目前我正准备在回答这个问题,但首先回答"为什么它会这么快?" 这些问题持续出现,但是我不能没有说它

解析Disruptor的依赖关系

原文地址:http://ifeve.com/dissecting-disruptor-wiring-up/ 作者:Trisha   译者:廖涵  校对:方腾飞 现在我已经讲了 RingBuffer​ 本身,如何从它 读取​ 以及如何向它 写入​.从逻辑上来说,下一件要做的事情就是把所有的东西拼装到在一起. 我前面提到过多生产者的情况--他们通过 ProducerBarrier 保证写入操作顺序与可控.我也提到过简单场景下的多消费者数据访问.更多的消费者的场景会变得更加复杂,我们​ 实现了一些聪明