成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring Boot 使用 Disruptor 做內(nèi)部高性能消息隊(duì)列

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

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

圖片

Disruptor介紹

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

Disruptor 的核心概念

先從了解 Disruptor 的核心概念開始,來了解它是如何運(yùn)作的。下面介紹的概念模型,既是領(lǐng)域?qū)ο螅彩怯成涞酱a實(shí)現(xiàn)上的核心對(duì)象。

Ring Buffer

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

Sequence Disruptor

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

Sequencer

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

Sequence Barrier

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

Wait Strategy

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

Event

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

EventProcessor

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

EventHandler

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

Producer

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

圖片

案例-demo

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

1.添加pom.xml依賴

<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.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)者處理消息開始");
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通過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());

// 啟動(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)者處理消息開始
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)者 模式是很常見的,通過一些消息隊(duì)列也可以輕松做到上述的效果。不同的地方在于,Disruptor 是在內(nèi)存中以隊(duì)列的方式去實(shí)現(xiàn)的,而且是無鎖的。這也是 Disruptor 為什么高效的原因。

責(zé)任編輯:武曉燕 來源: 碼猿技術(shù)專欄
相關(guān)推薦

2022-12-09 08:40:56

高性能內(nèi)存隊(duì)列

2024-10-30 15:43:56

2017-07-11 15:26:57

LocalMQ RocketMQ高性能

2025-06-27 10:41:04

Redis數(shù)據(jù)庫集群

2024-08-15 06:51:31

2024-10-25 08:41:18

消息隊(duì)列RedisList

2025-01-15 07:54:02

2024-07-31 08:31:13

2024-04-29 18:55:16

緩存Spring性能

2024-12-31 07:56:33

Disruptor內(nèi)存有界隊(duì)列消費(fèi)模式

2024-01-10 08:17:50

HikariCP數(shù)據(jù)庫Spring

2025-02-06 10:00:52

RedisSpring高性能

2023-10-23 11:40:44

SpringBootDisruptor

2021-09-15 09:02:20

Spring 6Spring BootJava

2021-09-03 06:46:34

Spring 6pring Boot 項(xiàng)目

2024-03-22 12:10:39

Redis消息隊(duì)列數(shù)據(jù)庫

2021-03-11 06:01:41

Linux消息隊(duì)列

2017-10-11 15:08:28

消息隊(duì)列常見

2017-05-25 10:50:16

Python高性能服務(wù)

2025-05-29 01:33:00

微服務(wù)架構(gòu)系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品一区二区三区久久 | 国产第1页 | 成年人网站国产 | 日本高清中文字幕 | 久久久精品一区 | 日韩一区二区在线观看 | 国产农村妇女精品一区 | 亚洲欧美一区二区三区1000 | 国产综合在线视频 | 国产欧美精品 | 久久久久国产精品一区二区 | 亚洲最大av | 国产视频日韩 | 国产探花在线精品一区二区 | 国产精品一区网站 | 亚洲高清中文字幕 | 久久久久久久久久久蜜桃 | 久久综合久久综合久久综合 | 免费特级黄毛片 | 精品国产不卡一区二区三区 | 日韩欧美在线一区二区 | 久久精品一区二区视频 | 中文字幕高清 | 日本在线免费观看 | 日韩最新网站 | 狠狠躁天天躁夜夜躁婷婷老牛影视 | 99精品久久久久久 | 色888www视频在线观看 | 亚洲一区二区综合 | 91色综合| 国产电影精品久久 | 99av成人精品国语自产拍 | 欧美午夜一区二区三区免费大片 | 日日碰狠狠躁久久躁96avv | 国产精品1区2区3区 中文字幕一区二区三区四区 | 欧美日韩在线视频观看 | 国产精品无 | 亚洲乱码一区二区三区在线观看 | 激情六月丁香 | 国产jizz女人多喷水99 | 欧美电影一区 |