最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot?+?Disruptor實現特快高并發(fā)處理及使用Disruptor高速實現隊列的過程

 更新時間:2023年11月16日 10:16:07   作者:吳名氏.  
Disruptor是一個開源的Java框架,它被設計用于在生產者—消費者(producer-consumer problem,簡稱PCP)問題上獲得盡量高的吞吐量(TPS)和盡量低的延遲,這篇文章主要介紹了SpringBoot?+?Disruptor?實現特快高并發(fā)處理,使用Disruptor高速實現隊列,需要的朋友可以參考下

1 前言

工作中遇到項目使用Disruptor做消息隊列,對!你沒看錯,不是Kafka也不是rabbitmq。Disruptor有個最大的優(yōu)點就是快,還有一點它是開源的哦,下面做個簡單的記錄。

2 Disruptor介紹

Disruptor 是英國外匯交易公司LMAX開發(fā)的一個高性能隊列,研發(fā)的初衷是解決內存隊列的延遲問題(在性能測試中發(fā)現竟然與I/O操作處于同樣的數量級)。

基于 Disruptor 開發(fā)的系統單線程能支撐每秒 600 萬訂單,2010 年在 QCon 演講后,獲得了業(yè)界關注。

Disruptor是一個開源的Java框架,它被設計用于在生產者—消費者(producer-consumer problem,簡稱PCP)問題上獲得盡量高的吞吐量(TPS)和盡量低的延遲。

從功能上來看,Disruptor 是實現了“隊列”的功能,而且是一個有界隊列。那么它的應用場景自然就是“生產者-消費者”模型的應用場合了。

Disruptor是LMAX在線交易平臺的關鍵組成部分,LMAX平臺使用該框架對訂單處理速度能達到600萬TPS,除金融領域之外,其他一般的應用中都可以用到Disruptor,它可以帶來顯著的性能提升。

其實Disruptor與其說是一個框架,不如說是一種設計思路,這個設計思路對于存在“并發(fā)、緩沖區(qū)、生產者—消費者模型、事務處理”這些元素的程序來說,Disruptor提出了一種大幅提升性能(TPS)的方案。

Disruptor的github主頁:

https://github.com/LMAX-Exchange/disruptor

3 Disruptor 的核心概念

先從了解 Disruptor 的核心概念開始,來了解它是如何運作的。下面介紹的概念模型,既是領域對象,也是映射到代碼實現上的核心對象。

3.1 Ring Buffer

如其名,環(huán)形的緩沖區(qū)。曾經 RingBuffer 是 Disruptor 中的最主要的對象,但從3.0版本開始,其職責被簡化為僅僅負責對通過 Disruptor 進行交換的數據(事件)進行存儲和更新。在一些更高級的應用場景中,Ring Buffer 可以由用戶的自定義實現來完全替代。

3.2 Sequence Disruptor

通過順序遞增的序號來編號管理通過其進行交換的數據(事件),對數據(事件)的處理過程總是沿著序號逐個遞增處理。一個 Sequence 用于跟蹤標識某個特定的事件處理者( RingBuffer/Consumer )的處理進度。

雖然一個 AtomicLong 也可以用于標識進度,但定義 Sequence 來負責該問題還有另一個目的,那就是防止不同的 Sequence 之間的CPU緩存?zhèn)喂蚕?Flase Sharing)問題。

注:這是 Disruptor 實現高性能的關鍵點之一,網上關于偽共享問題的介紹已經汗牛充棟,在此不再贅述。

3.3 Sequencer

Sequencer 是 Disruptor 的真正核心。此接口有兩個實現類 SingleProducerSequencer、MultiProducerSequencer ,它們定義在生產者和消費者之間快速、正確地傳遞數據的并發(fā)算法。

3.4 Sequence Barrier

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

3.5 Wait Strategy

定義 Consumer 如何進行等待下一個事件的策略。(注:Disruptor 定義了多種不同的策略,針對不同的場景,提供了不一樣的性能表現)

3.6 Event

在 Disruptor 的語義中,生產者和消費者之間進行交換的數據被稱為事件(Event)。它不是一個被 Disruptor 定義的特定類型,而是由 Disruptor 的使用者定義并指定。

3.7 EventProcessor

EventProcessor 持有特定消費者(Consumer)的 Sequence,并提供用于調用事件處理實現的事件循環(huán)(Event Loop)。

3.8 EventHandler

Disruptor 定義的事件處理接口,由用戶實現,用于處理事件,是 Consumer 的真正實現。

3.9 Producer

即生產者,只是泛指調用 Disruptor 發(fā)布事件的用戶代碼,Disruptor 沒有定義特定接口或類型。

4 案例-demo

通過下面8個步驟,你就能將Disruptor Get回家啦:

4.1 添加pom.xml依賴

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

4.2 消息體Model

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

4.3 構造EventFactory

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

4.4 構造EventHandler-消費者

@Slf4j
public class HelloEventHandler implements EventHandler<MessageModel> {
    @Override
    public void onEvent(MessageModel event, long sequence, boolean endOfBatch) {
        try {
            //這里停止1000ms是為了確定消費消息是異步的
            Thread.sleep(1000);
            log.info("消費者處理消息開始");
            if (event != null) {
                log.info("消費者消費的信息是:{}",event);
            }
        } catch (Exception e) {
            log.info("消費者處理消息失敗");
        }
        log.info("消費者處理消息結束");
    }
}

4.5 構造BeanManager

/**
 * 獲取實例化對象
 */
@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);
    }
}

4.6 構造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次方(能將求模運算轉為位運算提高效率),否則將影響效率
        int bufferSize = 1024 * 256;
        //單線程模式,獲取額外的性能
        Disruptor<MessageModel> disruptor = new Disruptor<>(factory, bufferSize, executor,
                ProducerType.SINGLE, new BlockingWaitStrategy());
        //設置事件業(yè)務處理器---消費者
        disruptor.handleEventsWith(new HelloEventHandler());
        // 啟動disruptor線程
        disruptor.start();
        //獲取ringbuffer環(huán),用于接取生產者生產的事件
        RingBuffer<MessageModel> ringBuffer = disruptor.getRingBuffer();
        return ringBuffer;
    }
}

4.7 構造Mqservice和實現類-生產者

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);
        //獲取下一個Event槽的下標
        long sequence = messageModelRingBuffer.next();
        try {
            //給Event填充數據
            MessageModel event = messageModelRingBuffer.get(sequence);
            event.setMessage(message);
            log.info("往消息隊列中添加消息:{}", event);
        } catch (Exception e) {
            log.error("failed to add event to messageModelRingBuffer for : e = {},{}",e,e.getMessage());
        } finally {
            //發(fā)布Event,激活觀察者去消費,將sequence傳遞給改消費者
            //注意最后的publish方法必須放在finally中以確保必須得到調用;如果某個請求的sequence未被提交將會堵塞后續(xù)的發(fā)布操作或者其他的producer
            messageModelRingBuffer.publish(sequence);
        }
    }
}

4.8 構造測試類及方法

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

4.9 測試運行結果

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

5 總結

其實 生成者 -> 消費者 模式是很常見的,通過一些消息隊列也可以輕松做到上述的效果。不同的地方在于,Disruptor 是在內存中以隊列的方式去實現的,而且是無鎖的。這也是 Disruptor 為什么高效的原因。

到此這篇關于SpringBoot + Disruptor 實現特快高并發(fā)處理,使用Disruptor高速實現隊列的文章就介紹到這了,更多相關SpringBoot  Disruptor 高并發(fā)處理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java并發(fā)編程總結——慎用CAS詳解

    Java并發(fā)編程總結——慎用CAS詳解

    下面小編就為大家?guī)硪黄狫ava并發(fā)編程總結——慎用CAS詳解。小編覺得挺不錯的, 現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • 簡單談談RxJava和多線程并發(fā)

    簡單談談RxJava和多線程并發(fā)

    認識RxJava已經有一段時間了,但是一直沒有機會在項目中嘗試,最近在新的項目里引進了RxJava寫一些事件處理,在review代碼的時候發(fā)現了一些和多線程并發(fā)相關的問題,所以寫了這篇文章,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-03-03
  • Spring容器初始化擴展點之ApplicationContextInitializer詳解

    Spring容器初始化擴展點之ApplicationContextInitializer詳解

    ApplicationContextInitializer是Spring框架提供的一個接口,用于在Spring應用上下文刷新之前對其進行自定義初始化,本文介紹Spring容器初始化擴展點之ApplicationContextInitializer,感興趣的朋友一起看看吧
    2025-02-02
  • 詳解Java中的靜態(tài)代理模式

    詳解Java中的靜態(tài)代理模式

    這篇文章主要為大家介紹了Java中的靜態(tài)代理模式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2022-12-12
  • Java String字符串和Unicode字符相互轉換代碼詳解

    Java String字符串和Unicode字符相互轉換代碼詳解

    這篇文章主要介紹了Java String字符串和Unicode字符相互轉換代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-05-05
  • Spring?@Transactional事務失效的原因分析

    Spring?@Transactional事務失效的原因分析

    一個程序中不可能沒有事務,Spring中,事務的實現方式分為兩種:編程式事務和聲明式事務。日常項目中,我們都會使用聲明式事務?@Transactional來實現事務,本文來和大家聊聊什么情況會導致@Transactional事務失效
    2022-09-09
  • 基于Java編寫第一個區(qū)塊鏈項目

    基于Java編寫第一個區(qū)塊鏈項目

    區(qū)塊鏈是分布式數據存儲、點對點傳輸、共識機制、加密算法等計算機技術的新型應用模式,下面這篇文章主要給大家介紹了基于Java實現區(qū)塊鏈的相關資料,需要的朋友可以參考下
    2021-08-08
  • SpringBoot如何優(yōu)雅的處理校驗參數的方法

    SpringBoot如何優(yōu)雅的處理校驗參數的方法

    這篇文章主要介紹了SpringBoot如何優(yōu)雅的處理校驗參數的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的詳細教程

    使用Maven 搭建 Spring MVC 本地部署Tomcat的詳細教程

    這篇文章主要介紹了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • SpringBoot通過配置Swagger權限解決Swagger未授權訪問漏洞問題

    SpringBoot通過配置Swagger權限解決Swagger未授權訪問漏洞問題

    這篇文章主要介紹了SpringBoot通過配置Swagger權限解決Swagger未授權訪問漏洞問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評論

左贡县| 名山县| 东城区| 安仁县| 昌宁县| 柳河县| 子长县| 拉孜县| 舟山市| 石屏县| 屏东县| 松江区| 如皋市| 阜阳市| 昆山市| 东阿县| 南岸区| 宁海县| 天津市| 西乡县| 泸水县| 平原县| 汶上县| 军事| 普陀区| 开化县| 松桃| 安新县| 浑源县| 醴陵市| 乐亭县| 沁阳市| 行唐县| 罗山县| 册亨县| 盐城市| 肇庆市| 马鞍山市| 阳曲县| 滨州市| 子长县|