當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]是不是平常聽到說消息隊(duì)列啊,JMS啊,MQ啊、kafka啊巴啦啦的一堆術(shù)語,聽不懂?關(guān)系混亂?今天就讓我們來一起來看看他們都是什么吧。1消息隊(duì)列介紹首先舉個(gè)收快遞的栗子,傳統(tǒng)的收快遞,快遞小哥把我們的快遞送到我們的手里。他需要什么條件嗯?快遞小哥有時(shí)間送,我們有時(shí)間取,快遞小哥和...


是不是平常聽到說消息隊(duì)列啊,JMS啊,MQ啊 、kafka啊巴啦啦的一堆術(shù)語,聽不懂?關(guān)系混亂?今天就讓我們來一起來看看他們都是什么吧。

1消息隊(duì)列介紹

首先舉個(gè)收快遞的栗子,傳統(tǒng)的收快遞,快遞小哥把我們的快遞送到我們的手里。他需要什么條件嗯?

  • 快遞小哥有時(shí)間送,

  • 我們有時(shí)間取,

  • 快遞小哥和我們約定一個(gè)時(shí)間地點(diǎn)。

但是嗯。快遞小哥有那么多的快遞需要送,可能送我快遞的時(shí)候,我不在家,可能我在家的時(shí)候,快遞小哥送其他的地方的快遞。所以嗯,這個(gè)時(shí)候,要么就是坐在家里等快遞,要么就只能從新約個(gè)時(shí)間點(diǎn)在送。那怎么辦去避免這個(gè)情況嗯?

于是嗯快遞柜出現(xiàn)了。快遞小哥不用關(guān)心我什么時(shí)候在家,因?yàn)榭爝f小哥有時(shí)間了,就把快遞放快遞柜,而我有時(shí)間了,我就去快遞柜取我的快遞。

那么快遞柜所起到的作用就是我們今天要收的消息隊(duì)列。我們可以把消息隊(duì)列比作是一個(gè)存放快遞的的快遞柜,當(dāng)我們需要獲取我們快遞的時(shí)候就可以從快遞柜里面拿到屬于我們的快遞。

1.1什么是消息隊(duì)列

我們可以把消息隊(duì)列比作是一個(gè)存放消息的容器,當(dāng)我們需要使用消息的時(shí)候可以取出消息供自己使用。我們看看維基百科上的描述:在計(jì)算機(jī)科學(xué)中,消息隊(duì)列(Message queue)是一種進(jìn)程間通信或同一進(jìn)程的不同線程間的通信方式,軟件的貯列用來處理一系列的輸入,通常是來自用戶。

是不是很難理解,我們換個(gè)說法來理解

我們可以把消息隊(duì)列比作是一個(gè)存放消息的容器,當(dāng)我們需要使用消息的時(shí)候可以取出消息供自己使用。

1.2消息隊(duì)列(Message queue)有什么用?

消息隊(duì)列是分布式系統(tǒng)中重要的組件,使用消息隊(duì)列主要是為了通過異步處理提高系統(tǒng)性能和削峰、降低系統(tǒng)耦合性。

通過異步處理提高系統(tǒng)性能(削峰、減少響應(yīng)所需時(shí)間)

舉個(gè)例子:我們?cè)谀硞€(gè)網(wǎng)站進(jìn)行注冊(cè)賬號(hào),我們需要做如下四件事:

  • 填寫我們的注冊(cè)信息;

  • 提交我們的注冊(cè)信息;

  • 我們的郵箱收到注冊(cè)信息;

  • 我們的短信收到注冊(cè)信息。

如果采用同步串行,所需要的時(shí)間是:a b c d

梳理消息隊(duì)列?MQ/JMS/Kafka
如果采用同步并行,所需要的時(shí)間是:a b max(c,d)

梳理消息隊(duì)列?MQ/JMS/Kafka
如果采用消息隊(duì)列,所需要的時(shí)間是:a b 消息隊(duì)列

梳理消息隊(duì)列?MQ/JMS/Kafka

降低系統(tǒng)耦合性

舉個(gè)例子,A公司做了某個(gè)系統(tǒng),B公司覺得A公司的某個(gè)功能很好,于是B公司和A公司的系統(tǒng)進(jìn)行了集成。這時(shí)C公司也覺得A公司的這個(gè)功能很好,于是,C公司也和A公司的系統(tǒng)進(jìn)行了集成。以后還有D公司…。

介于這種情況,A公司的系統(tǒng)和其他公司的耦合度都很高,每集成一個(gè)公司的系統(tǒng),A公司都需要修改自己的系統(tǒng)。如果采用消息隊(duì)列,則變成了如下:


梳理消息隊(duì)列?MQ/JMS/Kafka

不管以后還有多少公司的應(yīng)用程序想要用A公司的程序,都不需要和A公司進(jìn)行集成,誰需要這個(gè)功能,誰就去消息隊(duì)列里面獲取。

1.3消息隊(duì)列的兩種模式

點(diǎn)對(duì)點(diǎn)模式

應(yīng)用程序由:消息隊(duì)列,發(fā)送方,接收方組成。

每個(gè)消息都被發(fā)送到一個(gè)特定的隊(duì)列,接收者從隊(duì)列中獲取消息。隊(duì)列保留著消息,直到他們被消費(fèi)或超時(shí)。


梳理消息隊(duì)列?MQ/JMS/Kafka

發(fā)布訂閱模式

用用程序有由:角色主題(Topic)、發(fā)布者(Publisher)、訂閱者(Subscriber)構(gòu)成。

發(fā)布者發(fā)布一個(gè)消息,該消息通過topic傳遞給所有的客戶端。該模式下,發(fā)布者與訂閱者都是匿名的,即發(fā)布者與訂閱者都不知道對(duì)方是誰。并且可以動(dòng)態(tài)的發(fā)布與訂閱Topic。Topic主要用于保存和傳遞消息,且會(huì)一直保存消息直到消息被傳遞給客戶端。


梳理消息隊(duì)列?MQ/JMS/Kafka

介紹完了消息隊(duì)列,接著我們介紹JMS

2JMS介紹

JMS即Java消息服務(wù)(Java Message Service)應(yīng)用程序接口,是一個(gè)Java平臺(tái)中關(guān)于面向消息中間件(MOM)的API,類似于JDBC。用于在兩個(gè)應(yīng)用程序之間,或分布式系統(tǒng)中發(fā)送消息,進(jìn)行異步通信。它提供創(chuàng)建、發(fā)送、接收、讀取消息的服務(wù)。由Sun公司和它的合作伙伴設(shè)計(jì)的應(yīng)用程序接口和相應(yīng)語法,使得Java程序能夠和其他消息組件進(jìn)行通信。

JMS是一個(gè)消息服務(wù)的標(biāo)準(zhǔn)或者說是規(guī)范,允許應(yīng)用程序組件基于JavaEE平臺(tái)創(chuàng)建、發(fā)送、接收和讀取消息。它使分布式通信耦合度更低,消息服務(wù)更加可靠以及異步性。

介紹到這里,應(yīng)該明白了消息隊(duì)列和JMS的區(qū)別了吧?

  • 消息隊(duì)列:計(jì)算機(jī)科學(xué)中,A和B進(jìn)行通信的一種方式。

  • JMS:java平臺(tái)之間分布式通信的一種標(biāo)準(zhǔn)或者規(guī)范。

換句話說,JMS就是java對(duì)于消息隊(duì)列的一種實(shí)現(xiàn)方式。

2.1JSM消息模型

點(diǎn)對(duì)點(diǎn),發(fā)布訂閱,消息隊(duì)列中已經(jīng)說的很清楚了,這里就不重復(fù)說了。

2.2JMS消費(fèi)

  • 同步(Synchronous)

訂閱者/接收方通過調(diào)用 receive()來接收消息。在receive()方法中,線程會(huì)阻塞直到消息到達(dá)或者到指定時(shí)間后消息仍未到達(dá)。

  • 異步(Asynchronous)

消息訂閱者需注冊(cè)一個(gè)消息監(jiān)聽者,類似于事件監(jiān)聽器,只要消息到達(dá),JMS服務(wù)提供者會(huì)通過調(diào)用監(jiān)聽器的onMessage()遞送消息。

2.3JMS編程模型

JMS編程模型非常類似于JDBC?;貞浺幌拢覀冎爸v到的MyBatis。

  • SqlSessionFactoryBuilder去構(gòu)造SqlSessionFactory會(huì)話工廠;

  • SqlSessionFactory會(huì)話工廠給我們打開SqlSession會(huì)話;

  • SqlSession幫我們?nèi)ミB接數(shù)據(jù)庫(kù),接著我們就可以執(zhí)行增刪查改。

sqlSessionFactory?=?new?SqlSessionFactoryBuilder().build(inputStream);
SqlSession?openSession?=?sqlSessionFactory.openSession(true);
ProjectMapper?mapper?=?openSession.getMapper(ProjectMapper.class);
mapper.queryAllTaskByInit("init");

JMS模型如下

  • Connection Factory給我創(chuàng)建Connection連接;

  • Connection連接給我們創(chuàng)建了Session會(huì)話;

  • Session會(huì)話給我們創(chuàng)建消費(fèi)者和生產(chǎn)者;

  • 生產(chǎn)者生成消息;

  • 消費(fèi)者消費(fèi)消息;


梳理消息隊(duì)列?MQ/JMS/Kafka

3MQ介紹

上文中,我們說到了,JMS他并不是一種真正意義的技術(shù),而是一種接口,一種規(guī)范。就想JDBC一樣,無論是mybatis、hibernate,還是springJPA,不管你是那種技術(shù)實(shí)現(xiàn),反正你得遵守JDBC的規(guī)范。

在Java中,目前基于JMS實(shí)現(xiàn)的消息隊(duì)列常見技術(shù)有ActiveMQ、RabbitMQ、RocketMQ。值得注意的是,RocketMQ并沒有完全遵守JMS規(guī)范,并且Kafka不是JMS的實(shí)現(xiàn)。

3.1AMQP協(xié)議

這里我們以RabbitMQ為例介紹MQ,首先介紹下AMQP

AMQP協(xié)議(Advanced Message Queuing Protocol,高級(jí)消息隊(duì)列協(xié)議)是一個(gè)進(jìn)程間傳遞異步消息的網(wǎng)絡(luò)協(xié)議。

AMQP模型

梳理消息隊(duì)列?MQ/JMS/Kafka

AMQP工作過程

發(fā)布者(Publisher)發(fā)布消息(Message),經(jīng)由交換機(jī)(Exchange)。

交換機(jī)根據(jù)路由規(guī)則將收到的消息分發(fā)給與該交換機(jī)綁定的隊(duì)列、(Queue)。

最后 AMQP 代理會(huì)將消息投遞給訂閱了此隊(duì)列的消費(fèi)者,或者消費(fèi)者按照需求自行獲取。

RabbitMQ是MQ產(chǎn)品的典型代表,是一款基于AMQP協(xié)議可復(fù)用的企業(yè)消息系統(tǒng)

3.2RabbitMQ模型

RabbitMQ由兩部分組成,分別是服務(wù)端和應(yīng)用端;

  • 服務(wù)端包括:隊(duì)列和交換機(jī)。

  • 客戶端包括:生產(chǎn)者和消費(fèi)者。

在rabbitmq server上可以創(chuàng)建多個(gè)虛擬的message broker。每一個(gè)broker本質(zhì)上是一個(gè)mini-rabbitmq server,分別管理各自的exchange,和bindings。

broker相當(dāng)于物理的server,可以為不同app提供邊界隔離,使得應(yīng)用安全的運(yùn)行在不同的broker實(shí)例上,相互之間不會(huì)干擾。producer和consumer連接rabbit server需要指定一個(gè)broker。

梳理消息隊(duì)列?MQ/JMS/Kafka
梳理消息隊(duì)列?MQ/JMS/Kafka
Exchange有4種類型:direct(默認(rèn)),fanout, topic, 和headers

  • Direct:直接交換器,工作方式類似于單播,Exchange會(huì)將消息發(fā)送完全匹配ROUTING_KEY的Queue。

  • Fanout:廣播是式交換器,不管消息的ROUTING_KEY設(shè)置為什么,Exchange都會(huì)將消息轉(zhuǎn)發(fā)給所有綁定的Queue(所謂綁定就是將一個(gè)特定的 Exchange 和一個(gè)特定的 Queue 綁定起來。Exchange 和Queue的綁定可以是多對(duì)多的關(guān)系)。

  • Topic:主題交換器,工作方式類似于組播,Exchange會(huì)將消息轉(zhuǎn)發(fā)和ROUTING_KEY匹配模式相同的所有隊(duì)列,比如,ROUTING_KEY為user.stock的Message會(huì)轉(zhuǎn)發(fā)給綁定匹配模式為 * .stock,user.stock, * . * 和#.user.stock.#的隊(duì)列。( * 表是匹配一個(gè)任意詞組,#表示匹配0個(gè)或多個(gè)詞組)。

至于如何在代碼中使用RabbitMQ,這里我們先不擼代碼,本文目前只介紹理論梳理知識(shí)點(diǎn)。

4Kafka

上完中我們提到過,kafka不是JMS的實(shí)現(xiàn),因此在MQ章節(jié)中,我們沒有提及到它?,F(xiàn)在我們開始學(xué)習(xí)kafka吧。

先來放張kafka的原理圖,相信你看到這個(gè)圖片時(shí),內(nèi)心是奔潰的。我草,啥玩意。接下來我們就一點(diǎn)一點(diǎn)的消化吧。

4.1kafka原理圖

梳理消息隊(duì)列?MQ/JMS/Kafka
先介紹上圖中的術(shù)語。

  • Producer :消息生產(chǎn)者,就是向kafka broker發(fā)消息的客戶端。

  • Consumer :消息消費(fèi)者,向kafka broker取消息的客戶端。

  • Topic :kafka給消息提供的分類方式。broker用來存儲(chǔ)不同topic的消息數(shù)據(jù)。一個(gè)Topic可以認(rèn)為是一類消息,每個(gè)topic將被分成多個(gè)partition(區(qū)),每個(gè)partition在存儲(chǔ)層面是append log文件。任何發(fā)布到此partition的消息都會(huì)被直接追加到log文件的尾部,每條消息在文件中的位置稱為offset(偏移量),offset為一個(gè)long型數(shù)字,它是唯一標(biāo)記一條消息。它唯一的標(biāo)記一條消息。kafka并沒有提供其他額外的索引機(jī)制來存儲(chǔ)offset,因?yàn)樵趉afka中幾乎不允許對(duì)消息進(jìn)行“隨機(jī)讀寫”。

  • broker:中間件的kafka cluster,存儲(chǔ)消息,是由多個(gè)server組成的集群。

  • Partition:為了實(shí)現(xiàn)擴(kuò)展性,一個(gè)非常大的topic可以分布到多個(gè)broker(即服務(wù)器)上,一個(gè)topic可以分為多個(gè)partition,每個(gè)partition是一個(gè)有序的隊(duì)列。partition中的每條消息都會(huì)被分配一個(gè)有序的id(offset)。kafka只保證按一個(gè)partition中的順序?qū)⑾l(fā)給consumer,不保證一個(gè)topic的整體(多個(gè)partition間)的順序。

  • Offset:kafka的存儲(chǔ)文件都是按照offset.kafka來命名,例如你想找位于2049的位置,只要找到2048.kafka的文件即可。當(dāng)然the first offset就是00000000000.kafka。

類似于JMS的特性,但不是JMS規(guī)范的實(shí)現(xiàn)。kafka對(duì)消息保存時(shí)根據(jù)Topic進(jìn)行歸類,發(fā)送消息者成為Producer,消息接受者成為Consumer,此外kafka集群有多個(gè)kafka實(shí)例組成,每個(gè)實(shí)例(server)成為broker。無論是kafka集群,還是producer和consumer都依賴于zookeeper來保證系統(tǒng)可用性集群保存信息。

kafka基于文件存儲(chǔ)。通過分區(qū),可以將日志內(nèi)容分散到多個(gè)server上,來避免文件尺寸達(dá)到單機(jī)磁盤的上限,每個(gè)partiton都會(huì)被當(dāng)前server(kafka實(shí)例)保存;可以將一個(gè)topic切分多任意多個(gè)partitions,來消息保存/消費(fèi)的效率.此外越多的partitions意味著可以容納更多的consumer,有效提升并發(fā)消費(fèi)的能力。

kafka和JMS不同的是:即使消息被消費(fèi),消息仍然不會(huì)被立即刪除。日志文件將會(huì)根據(jù)broker中的配置要求,保留一定的時(shí)間之后刪除。

Kafka高可用機(jī)制

  • 多個(gè)broker組成,每個(gè)broker是一個(gè)節(jié)點(diǎn);

  • 你創(chuàng)建一個(gè)topic,這個(gè)topic可以劃分為多個(gè)partition,每個(gè)partition可以存在于不同的broker上,每個(gè)partition就放一部分?jǐn)?shù)據(jù)。

  • 采用replica副本機(jī)制,每個(gè)partition的數(shù)據(jù)都會(huì)同步到其他機(jī)器上,形成多個(gè)replica副本。

  • 所有replica會(huì)選舉一個(gè)leader出來,那么生產(chǎn)和消費(fèi)都跟這個(gè)leader打交道,然后其他replica就是follower。

  • 讀數(shù)據(jù)時(shí),從leader讀取,寫數(shù)據(jù)時(shí),leader把數(shù)據(jù)同步到所有follower上去。如果某個(gè)broker宕機(jī)了,這個(gè)broker在其他的broker還保留副本,假設(shè)這個(gè)broker上面存在leader,那么就重新選一個(gè)leader。

內(nèi)容有點(diǎn)多,需要結(jié)合圖片一點(diǎn)一點(diǎn)消化

4.2生產(chǎn)者結(jié)構(gòu)圖

梳理消息隊(duì)列?MQ/JMS/Kafka
至此,雖然看的云里霧里,不過相信你們還是能區(qū)分了吧?

整理一下:

  • 消息隊(duì)列:指計(jì)算機(jī)領(lǐng)域中,A和B通信的一種通信方式;

  • JMS:Java中對(duì)于消息隊(duì)列的接口規(guī)范;

  • ActiveMQ/RabbitMQ:JMS接口規(guī)范具體實(shí)現(xiàn)的一種技術(shù);

  • RocketMQ:不完全是JMS接口規(guī)范具體實(shí)現(xiàn)的一種技術(shù);

  • Kafka:非JMS接口規(guī)范具體實(shí)現(xiàn)的一種技術(shù);

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉