Ring Buffer 有什么特別?


原文地址: http://mechanitis.blogspot.com/2011/06/dissecting-disruptor-whats-so-special.html​ 作者是 Trisha Gee, LMAX 公司的一位女工程師。

最近我們開源了 LMAX Disruptor​,它是讓我們的交易流程變得如此之快的關鍵。為什么要開源它?因為我們意識到大家對高性能編程的傳統認知 ... 有些不對勁。我們找到了一個更好的,更快的在線程間共享數據的方法,如果不把它分享給大家就太自私了。而且,這會使我們看起來很酷。

從這個 網站​ 你可以下載一份解釋什么是 Disruptor,以及它為什么如此巧妙和飛快的技術文檔。我從這里得到了一些寫作幫助,其實我真正做的只是在上面加了一些標點和重新組織了一些我不明白的句子,這太簡單了。

我發現要把這些東西一次性解釋清楚有些困難,所以我准備一小段一小段的解釋它們,以適合我的 NADD​ 聽眾。

首先 - Ring Buffer。我對 Disruptor 的最初印象只有 Ring Buffer。后來我漸漸明白 Ring Buffer 結構是這個模式的中心,關鍵之處是 Disruptor 如何控制對它的訪問。

Ring Buffer 究竟是什么?

正如名字描述那樣 - 它是一個環 (圓形,首尾相接的),你可以把它當作一個緩存 (buffer),用來在一個線程上下文與另一個線程上下文之間傳遞數據。

Disruptor 全解析(1):Ring Buffer 有什么特別?

(好吧,我是用 Paint 畫的。我嘗試畫草圖,希望強迫症沒有摻和進來要求我畫出完美的圓和直線)。
所以基本上 Ring Buffer 就是擁有一個序號指向下一個可用元素的數組。

Disruptor 全解析(1):Ring Buffer 有什么特別?

如果你持續向 buffer 中寫入數據(應該也會從里面讀數據),這個序號會一直增長,直到繞過整個環。

Disruptor 全解析(1):Ring Buffer 有什么特別?

要找到數組中當前序號指向的元素,你可以用 mod 運算。

sequence mod array length = array index

因此對於上面的 Ring Buffer,這個算法就是(用 JAVA 的 mod 語法):12 % 10 = 2。很簡單。

其實圖片里畫着 10 個元素完全是一個意外。2 的 N 次方個元素會更好,因為計算機是用二進制思考的。
接下來呢?

如果你從 Wikipedia 查到 Circular Buffers​,你會看到它與我們的實現方式有一個重要的差別-沒有指向末尾的指針。我們只有下一個可用的序號。這是刻意的-選擇 Ring Buffer 的根本原因是需要支持可靠的消息通信。我們需要把服務發出的消息存儲起來,那么當另一個服務發來一個 NAK (拒絕應答信號)​​ 說他們沒有收到消息的時候,我們可以重新發送給他們。

Ring Buffer 看起來很理想。它用序號來指出 buffer 的末尾在哪里,而且當它收到一個 NAK 信號的時候,可以重發從那一點到當前序號之間的所有消息:

Disruptor 全解析(1):Ring Buffer 有什么特別?

我們所實現的 Ring Buffer 與傳統隊列的區別是:buffer 里的對象不會被銷毀-它們留在那兒直到下次被覆蓋寫入。這是與 Wikipedia 上的版本相比我們的實現不需要尾指針的原因。在我們的實現中,確定 Ring Buffer 是否重疊的工作,是由數據結構之外來完成的(這是生產者與消費者行為的一部分-如果你來不及等我寫博客說明它,可以自己檢出 Disruptor 代碼​​)。

Ring Buffer 這么棒是因為...?

 

我們使用 Ring Buffer 這種數據結構,是因為它給我們提供了可靠的消息傳遞特性。這個理由就足夠了,不過它還有一些其他的優點。

首先,Ring Buffer 比鏈表要快,因為它是數組,而且有一個容易預測的訪問模式。這很不錯,對 CPU 高速緩存友好 (CPU-cache-friendly)-數據可以在硬件層面預加載到高速緩存,因此 CPU 不需要經常回到主內存 RAM 里去尋找 Ring Buffer 的下一條數據。

第二點,Ring Buffer 是一個數組,你可以預先分配內存,並保持數組元素永遠有效。這意味着內存垃圾收集(GC)在這種情況下幾乎什么也不用做。此外,也不像鏈表那樣每增加一條數據都要創建對象-當這些數據從鏈表里刪除時,這些對象都要被清理掉。

文章缺少的部分

我沒有提到如何避免環重疊,以及怎么向 Ring Buffer 讀、寫數據的細節。你也會注意到我在拿它和鏈表那樣的數據結構相比較,我想沒人會認為鏈表是實際問題的解決方案。
有趣的部分來自於拿 Disruptor 和隊列之類的實現相比較。隊列通常關注於維護隊列的頭和尾,添加和消費消息一類的東西。所有這些東西我還沒有在 Ring Buffer 一節真正提到。這是因為 Ring Buffer 本身並不負責這些事情,我們把這些問題挪到了數據結構的外部。
你可以到這個 網站​ 閱讀論文或檢出代碼獲得更詳細的信息。也可以去看 Mike 和 Martin去年在 QCon San Francisco 的演講​。或者,再等我 5 分鍾來想想怎么講后面剩下的東西。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM