高效能無鎖佇列 Disruptor 初體驗

2022-07-14 09:03:09 字數 1746 閱讀 1559

最近一直在研究佇列的一些問題,今天樓主要分享乙個高效能的佇列 disruptor 。

它是英國外匯交易公司 lmax 開發的乙個高效能佇列,研發的初衷是解決記憶體佇列的延遲問題。基於 disruptor 開發的系統單執行緒能支撐每秒600萬訂單。

目前,包括 apache storm、log4j2 在內的很多知名專案都應用了disruptor以獲取高效能。在樓主公司內部使用 disruptor 與 netty 結合用來做 gps 實時資料的處理,效能相當強悍。本文從實戰角度來大概了解一下 disruptor 的實現原理。

disruptor通過以下設計來解決佇列速度慢的問題:

通過上面的介紹,我們大概可以了解到 disruptor 是乙個高效能的無鎖佇列,那麼該如何使用呢,下面樓主通過 disruptor 實現乙個簡單的生產者消費者模型,介紹 disruptor 的使用

首先,根據 disruptor 的事件驅動的程式設計模型,我們需要定義乙個事件來攜帶資料。

public class dataevent 

public long getvalue()

}

為了讓 disruptor 為我們預先分配這些事件,我們需要構造乙個 eventfactory 來執行構造

public class dataeventfactory implements eventfactory

}

一旦我們定義了事件,我們需要建立乙個處理這些事件的消費者。 在我們的例子中,我們要做的就是從控制台中列印出值。

public class dataeventhandler implements eventhandler

}

接下來我們需要初始化 disruptor ,並定義乙個生產者來生成訊息

public class disruptormanager ,佇列剩餘空間{}", datanum.get(), ringbuffer.remainingcapacity());

}}, new date(), 60 * 1000);

}/**

** @param message

*/public static void putdatatoqueue(long message)

// 往佇列中加事件

long next = ringbuffer.next();

try catch (exception e) ]出現異常=>{}", message, e.getstacktrace());

} finally

}public static void close()

}

最後我們來定義乙個 main 方法來執行**

public class eventmain }}

上面**具體感興趣的小夥伴請移步

然後我們可以看到控制台列印出來的資料

disruptor 通過精巧的無鎖設計實現了在高併發情形下的高效能。

另外在log4j 2中的非同步模式採用了disruptor來處理。在這裡樓主遇到乙個小問題,就是在使用log4j 2通過 tcp 模式往 logstash 發日誌資料的時候,由於網路問題導致鏈結中斷,從而導致 log4j 2 不停的往 ringbuffer 中寫資料,ringbuffer資料沒有消費者,導致伺服器記憶體跑滿。解決方案是設定 log4j 2 中 disruptor 佇列有界,或者換成 udp 模式來寫日誌資料(如果資料不重要的話)。

乙個高效能無鎖非阻塞鍊錶佇列

這個是乙個用c 11標準實現的無鎖非阻塞鍊錶佇列,通過增加乙個dummy節點,解偶合煉表頭指標和尾指標。使得當只有乙個生產者和乙個消費者時,進隊和出隊都無需加鎖,進隊操作的是尾指標,出隊操作的是頭指標,互不干涉。對於多個生產者且單個消費者時,只需要對尾指標加鎖保護,而頭指標不需要加鎖。反之,對於單生...

無鎖佇列 自旋鎖佇列 互斥鎖佇列效能對比測試

先大致介紹一下無鎖佇列。無鎖佇列的根本是cas函式 compareandswap,即比較並交換,函式功能可以用c 函式來說明 int compare and swap int reg,int oldval,int newval 它將reg的值與oldval的值進行對比,若相同則將reg賦新值。注意以...

mySQL無鎖佇列 go 無鎖佇列

無鎖佇列適用場景 兩個執行緒之間的互動資料,乙個執行緒生產資料,另外乙個執行緒消費資料,效率高 缺點 需要使用固定分配的空間,不能動態增加 減少長度,存在空間浪費和無法擴充套件空間問題 package main import fmt reflect strings time type loopque...