SpringBoot disruptor高性能隊列使用
Disruptor是一個高性能隊列,常見的還有kafka、rabbitmq等,下面體驗一下~
1、Disruptor簡介
Disruptor 是英國外匯交易公司LMAX開發(fā)的一個高性能隊列,研發(fā)的初衷是解決內(nèi)存隊列的延遲問題(在性能測試中發(fā)現(xiàn)竟然與I/O操作處于同樣的數(shù)量級)。基于 Disruptor 開發(fā)的系統(tǒng)單線程能支撐每秒 600 萬訂單,2010 年在 QCon 演講后,獲得了業(yè)界關(guān)注。
其特點(diǎn)簡單總結(jié)如下:
- 開源的java框架,用于生產(chǎn)者-消費(fèi)者場景;
- 高吞吐量和低延遲;
- 有界隊列;
disruptor在github網(wǎng)址為:https://github.com/LMAX-Exchange/disruptor

2、Disruptor概念
- Ring Buffer:環(huán)形的緩沖區(qū),環(huán)形數(shù)組中的元素采用覆蓋方式,避免了jvm的GC;
- Sequence Disruptor:通過順序遞增的序號來編號管理通過其進(jìn)行交換的數(shù)據(jù)(事件),對數(shù)據(jù)(事件)的處理過程總是沿著序號逐個遞增處理;
- Sequencer:Sequencer 是 Disruptor 的真正核心。此接口有兩個實現(xiàn)類 SingleProducerSequencer、MultiProducerSequencer ,它們定義在生產(chǎn)者和消費(fèi)者之間快速、正確地傳遞數(shù)據(jù)的并發(fā)算法;
- Sequence Barrier:用于保持對RingBuffer的 main published Sequence 和Consumer依賴的其它Consumer的 Sequence 的引用;
- Wait Strategy:定義 Consumer 如何進(jìn)行等待下一個事件的策略;
- Event:在 Disruptor 的語義中,生產(chǎn)者和消費(fèi)者之間進(jìn)行交換的數(shù)據(jù)被稱為事件(Event)。它不是一個被 Disruptor 定義的特定類型,而是由 Disruptor 的使用者定義并指定;
- EventProcessor:EventProcessor 持有特定消費(fèi)者(Consumer)的 Sequence,并提供用于調(diào)用事件處理實現(xiàn)的事件循環(huán)(Event Loop);
- EventHandler:定義的事件處理接口,由用戶實現(xiàn),用于處理事件,是 Consumer 的真正實現(xiàn);
- Producer:生產(chǎn)者,只是泛指調(diào)用 Disruptor 發(fā)布事件的用戶代碼,Disruptor 沒有定義特定接口或類型;
3、springboot+disruptor實例
在pom.xml文件中添加依賴
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
消息體Model
@Data
public class MessageModel {
private String message;
}
構(gòu)造EventFactory
public class HelloEventFactory implements EventFactory<MessageModel> {
@Override
public MessageModel newInstance() {
return new MessageModel();
}
}
構(gòu)造消費(fèi)者
@Slf4j
public class HelloEventHandler implements EventHandler<MessageModel> {
@Override
public void onEvent(MessageModel event, long sequence, boolean endOfBatch) {
try {
//這里停止1000ms是為了確定消費(fèi)消息是異步的
Thread.sleep(1000);
log.info("消費(fèi)者處理消息開始");
if (event != null) {
log.info("消費(fèi)者消費(fèi)的信息是:{}",event);
}
} catch (Exception e) {
log.info("消費(fèi)者處理消息失敗");
}
log.info("消費(fèi)者處理消息結(jié)束");
}
}
構(gòu)造MQManager
@Configuration
public class MqManager {
@Bean("messageModel")
public RingBuffer<MessageModel> messageModelRingBuffer() {
//定義用于事件處理的線程池, Disruptor通過java.util.concurrent.ExecutorSerivce提供的線程來觸發(fā)consumer的事件處理
ExecutorService executor = Executors.newFixedThreadPool(2);
//指定事件工廠
HelloEventFactory factory = new HelloEventFactory();
//指定ringbuffer字節(jié)大小,必須為2的N次方(能將求模運(yùn)算轉(zhuǎn)為位運(yùn)算提高效率),否則將影響效率
int bufferSize = 1024 * 256;
//單線程模式,獲取額外的性能
Disruptor<MessageModel> disruptor = new Disruptor<>(factory, bufferSize, executor, ProducerType.SINGLE, new BlockingWaitStrategy());
//設(shè)置事件業(yè)務(wù)處理器---消費(fèi)者
disruptor.handleEventsWith(new HelloEventHandler());
//啟動disruptor線程
disruptor.start();
//獲取ringbuffer環(huán),用于接取生產(chǎn)者生產(chǎn)的事件
RingBuffer<MessageModel> ringBuffer = disruptor.getRingBuffer();
return ringBuffer;
}
}
構(gòu)造生產(chǎn)者
@Configuration
public class MqManager {
@Bean("messageModel")
public RingBuffer<MessageModel> messageModelRingBuffer() {
//定義用于事件處理的線程池, Disruptor通過java.util.concurrent.ExecutorSerivce提供的線程來觸發(fā)consumer的事件處理
ExecutorService executor = Executors.newFixedThreadPool(2);
//指定事件工廠
HelloEventFactory factory = new HelloEventFactory();
//指定ringbuffer字節(jié)大小,必須為2的N次方(能將求模運(yùn)算轉(zhuǎn)為位運(yùn)算提高效率),否則將影響效率
int bufferSize = 1024 * 256;
//單線程模式,獲取額外的性能
Disruptor<MessageModel> disruptor = new Disruptor<>(factory, bufferSize, executor, ProducerType.SINGLE, new BlockingWaitStrategy());
//設(shè)置事件業(yè)務(wù)處理器---消費(fèi)者
disruptor.handleEventsWith(new HelloEventHandler());
//啟動disruptor線程
disruptor.start();
//獲取ringbuffer環(huán),用于接取生產(chǎn)者生產(chǎn)的事件
RingBuffer<MessageModel> ringBuffer = disruptor.getRingBuffer();
return ringBuffer;
}
}
測試
/**
* 項目內(nèi)部使用Disruptor做消息隊列
* @throws Exception
*/
@Test
public void sayHelloMqTest() throws Exception{
helloEventProducer.sayHelloMq("Hello world!");
log.info("消息隊列已發(fā)送完畢");
//這里停止2000ms是為了確定是處理消息是異步的
Thread.sleep(2000);
}
運(yùn)行結(jié)果如下

4、小結(jié)
引用disruptor作為內(nèi)部的高性能隊列,應(yīng)用于生產(chǎn)者-消費(fèi)者模式中還是非常nice的,后面若有工程需求可以嘗試一下。
到此這篇關(guān)于SpringBoot disruptor高性能隊列使用的文章就介紹到這了,更多相關(guān)SpringBoot disruptor內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot解決BigDecimal傳到前端后精度丟失問題
這篇文章將通過示例詳細(xì)為大家介紹SpringBoot如何解決BigDecimal傳到前端后精度丟失問題,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-06-06
java.lang.String和java.util.NClob互相轉(zhuǎn)換方式
這篇文章主要介紹了java.lang.String和java.util.NClob互相轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
MyBatis加載映射文件和動態(tài)代理的實現(xiàn)
本文主要介紹了MyBatis加載映射文件和動態(tài)代理的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
SpringBoot配置使用H2數(shù)據(jù)庫的簡單教程
H2是一個Java編寫的關(guān)系型數(shù)據(jù)庫,它可以被嵌入Java應(yīng)用程序中使用,或者作為一個單獨(dú)的數(shù)據(jù)庫服務(wù)器運(yùn)行。本文將介紹SpringBoot如何配置使用H2數(shù)據(jù)庫2021-05-05
如何利用反射生成?MyBatisPlus中QueryWrapper動態(tài)條件
這篇文章主要介紹了如何利用反射生成?MyBatisPlus中QueryWrapper動態(tài)條件,分享在MyBatisPlus中經(jīng)常會用到代碼來構(gòu)造查詢條件等內(nèi)容,需要的小伙伴可以參考一下2022-02-02

