欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot項(xiàng)目使用Disruptor做內(nèi)部消息隊(duì)列的實(shí)現(xiàn)

 更新時(shí)間:2023年07月27日 15:05:43   作者:不二天次  
本文主要介紹了springboot項(xiàng)目使用Disruptor做內(nèi)部消息隊(duì)列的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、背景

工作中遇到項(xiàng)目使用Disruptor做消息隊(duì)列,對(duì)你沒(méi)看錯(cuò),不是Kafka,也不是rabbitmq;Disruptor有個(gè)最大的優(yōu)點(diǎn)就是快,還有一點(diǎn)它是開(kāi)源的哦,下面做個(gè)簡(jiǎn)單的記錄.

二、Disruptor介紹

  • Disruptor 是英國(guó)外匯交易公司LMAX開(kāi)發(fā)的一個(gè)高性能隊(duì)列,研發(fā)的初衷是解決內(nèi)存隊(duì)列的延遲問(wèn)題(在性能測(cè)試中發(fā)現(xiàn)竟然與I/O操作處于同樣的數(shù)量級(jí))?;?Disruptor 開(kāi)發(fā)的系統(tǒng)單線程能支撐每秒 600 萬(wàn)訂單,2010 年在 QCon 演講后,獲得了業(yè)界關(guān)注。
  • Disruptor是一個(gè)開(kāi)源的Java框架,它被設(shè)計(jì)用于在生產(chǎn)者—消費(fèi)者(producer-consumer problem,簡(jiǎn)稱PCP)問(wèn)題上獲得盡量高的吞吐量(TPS)和盡量低的延遲。
  • 從功能上來(lái)看,Disruptor 是實(shí)現(xiàn)了“隊(duì)列”的功能,而且是一個(gè)有界隊(duì)列。那么它的應(yīng)用場(chǎng)景自然就是“生產(chǎn)者-消費(fèi)者”模型的應(yīng)用場(chǎng)合了。
  • Disruptor是LMAX在線交易平臺(tái)的關(guān)鍵組成部分,LMAX平臺(tái)使用該框架對(duì)訂單處理速度能達(dá)到600萬(wàn)TPS,除金融領(lǐng)域之外,其他一般的應(yīng)用中都可以用到Disruptor,它可以帶來(lái)顯著的性能提升。
  • 其實(shí)Disruptor與其說(shuō)是一個(gè)框架,不如說(shuō)是一種設(shè)計(jì)思路,這個(gè)設(shè)計(jì)思路對(duì)于存在“并發(fā)、緩沖區(qū)、生產(chǎn)者—消費(fèi)者模型、事務(wù)處理”這些元素的程序來(lái)說(shuō),Disruptor提出了一種大幅提升性能(TPS)的方案。

Disruptor的github主頁(yè):https://github.com/LMAX-Exchange/disruptor

三、Disruptor 的核心概念

先從了解 Disruptor 的核心概念開(kāi)始,來(lái)了解它是如何運(yùn)作的。下面介紹的概念模型,既是領(lǐng)域?qū)ο?,也是映射到代碼實(shí)現(xiàn)上的核心對(duì)象。

1. Ring Buffer
如其名,環(huán)形的緩沖區(qū)。曾經(jīng) RingBuffer 是 Disruptor 中的最主要的對(duì)象,但從3.0版本開(kāi)始,其職責(zé)被簡(jiǎn)化為僅僅負(fù)責(zé)對(duì)通過(guò) Disruptor 進(jìn)行交換的數(shù)據(jù)(事件)進(jìn)行存儲(chǔ)和更新。在一些更高級(jí)的應(yīng)用場(chǎng)景中,Ring Buffer 可以由用戶的自定義實(shí)現(xiàn)來(lái)完全替代。

2. Sequence Disruptor
通過(guò)順序遞增的序號(hào)來(lái)編號(hào)管理通過(guò)其進(jìn)行交換的數(shù)據(jù)(事件),對(duì)數(shù)據(jù)(事件)的處理過(guò)程總是沿著序號(hào)逐個(gè)遞增處理。一個(gè) Sequence 用于跟蹤標(biāo)識(shí)某個(gè)特定的事件處理者( RingBuffer/Consumer )的處理進(jìn)度。雖然一個(gè) AtomicLong 也可以用于標(biāo)識(shí)進(jìn)度,但定義 Sequence 來(lái)負(fù)責(zé)該問(wèn)題還有另一個(gè)目的,那就是防止不同的 Sequence 之間的CPU緩存?zhèn)喂蚕?Flase Sharing)問(wèn)題。
(注:這是 Disruptor 實(shí)現(xiàn)高性能的關(guān)鍵點(diǎn)之一,網(wǎng)上關(guān)于偽共享問(wèn)題的介紹已經(jīng)汗牛充棟,在此不再贅述)。

3. Sequencer
Sequencer 是 Disruptor 的真正核心。此接口有兩個(gè)實(shí)現(xiàn)類 SingleProducerSequencer、MultiProducerSequencer ,它們定義在生產(chǎn)者和消費(fèi)者之間快速、正確地傳遞數(shù)據(jù)的并發(fā)算法。

4. Sequence Barrier
用于保持對(duì)RingBuffer的 main published Sequence 和Consumer依賴的其它Consumer的 Sequence 的引用。 Sequence Barrier 還定義了決定 Consumer 是否還有可處理的事件的邏輯。

5. Wait Strategy
定義 Consumer 如何進(jìn)行等待下一個(gè)事件的策略。 (注:Disruptor 定義了多種不同的策略,針對(duì)不同的場(chǎng)景,提供了不一樣的性能表現(xiàn))

6. Event
在 Disruptor 的語(yǔ)義中,生產(chǎn)者和消費(fèi)者之間進(jìn)行交換的數(shù)據(jù)被稱為事件(Event)。它不是一個(gè)被 Disruptor 定義的特定類型,而是由 Disruptor 的使用者定義并指定。

7. EventProcessor
EventProcessor 持有特定消費(fèi)者(Consumer)的 Sequence,并提供用于調(diào)用事件處理實(shí)現(xiàn)的事件循環(huán)(Event Loop)。

8. EventHandler
Disruptor 定義的事件處理接口,由用戶實(shí)現(xiàn),用于處理事件,是 Consumer 的真正實(shí)現(xiàn)。

9. Producer
即生產(chǎn)者,只是泛指調(diào)用 Disruptor 發(fā)布事件的用戶代碼,Disruptor 沒(méi)有定義特定接口或類型。

四、案例-demo

通過(guò)下面8個(gè)步驟,你就能將Disruptor Get回家啦:

1、添加pom.xml依賴

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.4</version>
</dependency>

2、消息體Model

/**
 * 消息體
 */
@Data
public class MessageModel {
    private String message;
}

3、構(gòu)造EventFactory

public class HelloEventFactory implements EventFactory<MessageModel> {
    @Override
    public MessageModel newInstance() {
        return new MessageModel();
    }
}

4、構(gòu)造EventHandler-消費(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)者處理消息開(kāi)始");
            if (event != null) {
                log.info("消費(fèi)者消費(fèi)的信息是:{}",event);
            }
        } catch (Exception e) {
            log.info("消費(fèi)者處理消息失敗");
        }
        log.info("消費(fèi)者處理消息結(jié)束");
    }
}

5、構(gòu)造BeanManager

/**
?* 獲取實(shí)例化對(duì)象
?*/
@Component
public class BeanManager implements ApplicationContextAware {
? ? private static ApplicationContext applicationContext = null;
? ? @Override
? ? public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
? ? ? ? this.applicationContext = applicationContext;
? ? }
? ? public static ApplicationContext getApplicationContext() { return applicationContext; }
? ? public static Object getBean(String name) {
? ? ? ? return applicationContext.getBean(name);
? ? }
? ? public static <T> T getBean(Class<T> clazz) {
? ? ? ? return applicationContext.getBean(clazz);
? ? }
}

6、構(gòu)造MQManager

@Configuration
public class MQManager {
? ? @Bean("messageModel")
? ? public RingBuffer<MessageModel> messageModelRingBuffer() {
? ? ? ? //定義用于事件處理的線程池, Disruptor通過(guò)java.util.concurrent.ExecutorSerivce提供的線程來(lái)觸發(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());
? ? ? ? // 啟動(dòng)disruptor線程
? ? ? ? disruptor.start();
? ? ? ? //獲取ringbuffer環(huán),用于接取生產(chǎn)者生產(chǎn)的事件
? ? ? ? RingBuffer<MessageModel> ringBuffer = disruptor.getRingBuffer();
? ? ? ? return ringBuffer;
? ? }

7、構(gòu)造Mqservice和實(shí)現(xiàn)類-生產(chǎn)者

public interface DisruptorMqService {
? ? /**
? ? ?* 消息
? ? ?* @param message
? ? ?*/
? ? void sayHelloMq(String message);
}
@Slf4j
@Component
@Service
public class DisruptorMqServiceImpl implements DisruptorMqService {
? ? @Autowired
? ? private RingBuffer<MessageModel> messageModelRingBuffer;
? ? @Override
? ? public void sayHelloMq(String message) {
? ? ? ? log.info("record the message: {}",message);
? ? ? ? //獲取下一個(gè)Event槽的下標(biāo)
? ? ? ? long sequence = messageModelRingBuffer.next();
? ? ? ? try {
? ? ? ? ? ? //給Event填充數(shù)據(jù)
? ? ? ? ? ? MessageModel event = messageModelRingBuffer.get(sequence);
? ? ? ? ? ? event.setMessage(message);
? ? ? ? ? ? log.info("往消息隊(duì)列中添加消息:{}", event);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? log.error("failed to add event to messageModelRingBuffer for : e = {},{}",e,e.getMessage());
? ? ? ? } finally {
? ? ? ? ? ? //發(fā)布Event,激活觀察者去消費(fèi),將sequence傳遞給改消費(fèi)者
? ? ? ? ? ? //注意最后的publish方法必須放在finally中以確保必須得到調(diào)用;如果某個(gè)請(qǐng)求的sequence未被提交將會(huì)堵塞后續(xù)的發(fā)布操作或者其他的producer
? ? ? ? ? ? messageModelRingBuffer.publish(sequence);
? ? ? ? }
? ? }
}

8、構(gòu)造測(cè)試類及方法

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class DemoApplicationTests {
? ? @Autowired
? ? private DisruptorMqService disruptorMqService;
? ? /**
? ? ?* 項(xiàng)目?jī)?nèi)部使用Disruptor做消息隊(duì)列
? ? ?* @throws Exception
? ? ?*/
? ? @Test
? ? public void sayHelloMqTest() throws Exception{
? ? ? ? disruptorMqService.sayHelloMq("消息到了,Hello world!");
? ? ? ? log.info("消息隊(duì)列已發(fā)送完畢");
? ? ? ? //這里停止2000ms是為了確定是處理消息是異步的
? ? ? ? Thread.sleep(2000);
? ? }
}

測(cè)試運(yùn)行結(jié)果

2020-04-05 14:31:18.543  INFO 7274 --- [           main] c.e.u.d.d.s.Impl.DisruptorMqServiceImpl  : record the message: 消息到了,Hello world!
2020-04-05 14:31:18.545  INFO 7274 --- [           main] c.e.u.d.d.s.Impl.DisruptorMqServiceImpl  : 往消息隊(duì)列中添加消息:MessageModel(message=消息到了,Hello world!)
2020-04-05 14:31:18.545  INFO 7274 --- [           main] c.e.utils.demo.DemoApplicationTests      : 消息隊(duì)列已發(fā)送完畢
2020-04-05 14:31:19.547  INFO 7274 --- [pool-1-thread-1] c.e.u.d.disrupMq.mq.HelloEventHandler    : 消費(fèi)者處理消息開(kāi)始
2020-04-05 14:31:19.547  INFO 7274 --- [pool-1-thread-1] c.e.u.d.disrupMq.mq.HelloEventHandler    : 消費(fèi)者消費(fèi)的信息是:MessageModel(message=消息到了,Hello world!)
2020-04-05 14:31:19.547  INFO 7274 --- [pool-1-thread-1] c.e.u.d.disrupMq.mq.HelloEventHandler    : 消費(fèi)者處理消息結(jié)束

五、總結(jié)

其實(shí) 生成者 -> 消費(fèi)者 模式是很常見(jiàn)的,通過(guò)一些消息隊(duì)列也可以輕松做到上述的效果。不同的地方在于,Disruptor 是在內(nèi)存中以隊(duì)列的方式去實(shí)現(xiàn)的,而且是無(wú)鎖的。這也是 Disruptor 為什么高效的原因。

到此這篇關(guān)于springboot項(xiàng)目使用Disruptor做內(nèi)部消息隊(duì)列的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)springboot Disruptor內(nèi)部消息隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java開(kāi)發(fā)崗位面試被問(wèn)到嵌套類怎么辦

    Java開(kāi)發(fā)崗位面試被問(wèn)到嵌套類怎么辦

    本篇文章主要介紹了深入理解Java嵌套類和內(nèi)部類,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-07-07
  • Spring如何通過(guò)@Lazy注解解決構(gòu)造方法循環(huán)依賴問(wèn)題

    Spring如何通過(guò)@Lazy注解解決構(gòu)造方法循環(huán)依賴問(wèn)題

    循環(huán)依賴其實(shí)就是循環(huán)引用,也就是兩個(gè)或則兩個(gè)以上的bean互相持有對(duì)方,最終形成閉環(huán),這篇文章主要給大家介紹了關(guān)于Spring如何通過(guò)@Lazy注解解決構(gòu)造方法循環(huán)依賴問(wèn)題的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • Java經(jīng)典面試題匯總:Java Web

    Java經(jīng)典面試題匯總:Java Web

    本篇總結(jié)的是Java Web相關(guān)的面試題,后續(xù)會(huì)持續(xù)更新,希望我的分享可以幫助到正在備戰(zhàn)面試的實(shí)習(xí)生或者已經(jīng)工作的同行,如果發(fā)現(xiàn)錯(cuò)誤還望大家多多包涵,不吝賜教,謝謝
    2021-07-07
  • Java中的for循環(huán)結(jié)構(gòu)及實(shí)例

    Java中的for循環(huán)結(jié)構(gòu)及實(shí)例

    這篇文章主要介紹了Java中的for循環(huán)結(jié)構(gòu)及實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Linux centos7環(huán)境下jdk安裝教程

    Linux centos7環(huán)境下jdk安裝教程

    這篇文章主要為大家詳細(xì)介紹了Linux centos7環(huán)境下jdk的安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Java中Bean轉(zhuǎn)Map問(wèn)題歸納總結(jié)

    Java中Bean轉(zhuǎn)Map問(wèn)題歸納總結(jié)

    Java Bean轉(zhuǎn)Map的坑很多,最常見(jiàn)的就是類型丟失和屬性名解析錯(cuò)誤的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Java中Bean轉(zhuǎn)Map問(wèn)題歸納總結(jié)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • java關(guān)于持久層面試題目整理

    java關(guān)于持久層面試題目整理

    在本篇文章里小編給大家分享的是一篇關(guān)于java關(guān)于持久層面試題目整理內(nèi)容,需要的朋友們可以學(xué)習(xí)下。
    2020-03-03
  • Java中的SecretKeyFactory類使用詳解

    Java中的SecretKeyFactory類使用詳解

    這篇文章主要介紹了Java中的SecretKeyFactory類使用詳解,SecretKeyFactory表示私密密鑰的工廠,密鑰工廠用來(lái)將密鑰(類型 Key 的不透明加密密鑰)轉(zhuǎn)換為密鑰規(guī)范(底層密鑰材料的透明表示形式),需要的朋友可以參考下
    2024-01-01
  • netty服務(wù)端輔助類ServerBootstrap創(chuàng)建邏輯分析

    netty服務(wù)端輔助類ServerBootstrap創(chuàng)建邏輯分析

    這篇文章主要介紹了netty服務(wù)端輔助類ServerBootstrap創(chuàng)建邏輯分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • 構(gòu)建springboot自動(dòng)生成mapper文件和dao接口項(xiàng)目的步驟和配置方法

    構(gòu)建springboot自動(dòng)生成mapper文件和dao接口項(xiàng)目的步驟和配置方法

    這篇文章主要介紹了構(gòu)建springboot自動(dòng)生成mapper文件和dao接口項(xiàng)目的步驟和配置方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05

最新評(píng)論