梳理消息隊列 MQ-JMS-Kafka
架構師(JiaGouX)
是不是平常聽到說消息隊列啊,JMS 啊,MQ 啊 、kafka 啊巴啦啦的一堆術語,聽不懂?關係混亂?今天就讓我們來一起來看看他們都是什麼吧。
1 消息隊列介紹
首先舉個收快遞的栗子,傳統的收快遞,快遞小哥把我們的快遞送到我們的手裏。他需要什麼條件嗯?
-
快遞小哥有時間送,
-
我們有時間取,
-
快遞小哥和我們約定一個時間地點。
但是嗯。快遞小哥有那麼多的快遞需要送,可能送我快遞的時候,我不在家,可能我在家的時候,快遞小哥送其他的地方的快遞。所以嗯,這個時候,要麼就是坐在家裏等快遞,要麼就只能從新約個時間點在送。那怎麼辦去避免這個情況嗯?
於是嗯快遞櫃出現了。快遞小哥不用關心我什麼時候在家,因爲快遞小哥有時間了,就把快遞放快遞櫃,而我有時間了,我就去快遞櫃取我的快遞。
那麼快遞櫃所起到的作用就是我們今天要收的消息隊列。我們可以把消息隊列比作是一個存放快遞的的快遞櫃,當我們需要獲取我們快遞的時候就可以從快遞櫃裏面拿到屬於我們的快遞。
1.1 什麼是消息隊列
我們可以把消息隊列比作是一個存放消息的容器,當我們需要使用消息的時候可以取出消息供自己使用。我們看看維基百科上的描述:在計算機科學中,消息隊列(Message queue)是一種進程間通信或同一進程的不同線程間的通信方式,軟件的貯列用來處理一系列的輸入,通常是來自用戶。
是不是很難理解,我們換個說法來理解
我們可以把消息隊列比作是一個存放消息的容器,當我們需要使用消息的時候可以取出消息供自己使用。
1.2 消息隊列(Message queue)有什麼用?
消息隊列是分佈式系統中重要的組件,使用消息隊列主要是爲了通過異步處理提高系統性能和削峯、降低系統耦合性。
通過異步處理提高系統性能(削峯、減少響應所需時間)
舉個例子:我們在某個網站進行註冊賬號,我們需要做如下四件事:
-
填寫我們的註冊信息;
-
提交我們的註冊信息;
-
我們的郵箱收到註冊信息;
-
我們的短信收到註冊信息。
如果採用同步串行,所需要的時間是:a+b+c+d
如果採用同步並行,所需要的時間是:a+b+max(c,d)
如果採用消息隊列,所需要的時間是:a+b + 消息隊列
降低系統耦合性
舉個例子,A 公司做了某個系統,B 公司覺得 A 公司的某個功能很好,於是 B 公司和 A 公司的系統進行了集成。這時 C 公司也覺得 A 公司的這個功能很好,於是,C 公司也和 A 公司的系統進行了集成。以後還有 D 公司…。
介於這種情況,A 公司的系統和其他公司的耦合度都很高,每集成一個公司的系統,A 公司都需要修改自己的系統。如果採用消息隊列,則變成了如下:
不管以後還有多少公司的應用程序想要用 A 公司的程序,都不需要和 A 公司進行集成,誰需要這個功能,誰就去消息隊列裏面獲取。
1.3 消息隊列的兩種模式
點對點模式
應用程序由:消息隊列,發送方,接收方組成。
每個消息都被髮送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留着消息,直到他們被消費或超時。
發佈訂閱模式
用用程序有由:角色主題(Topic)、發佈者 (Publisher)、訂閱者(Subscriber) 構成。
發佈者發佈一個消息,該消息通過 topic 傳遞給所有的客戶端。該模式下,發佈者與訂閱者都是匿名的,即發佈者與訂閱者都不知道對方是誰。並且可以動態的發佈與訂閱 Topic。Topic 主要用於保存和傳遞消息,且會一直保存消息直到消息被傳遞給客戶端。
介紹完了消息隊列,接着我們介紹 JMS
2JMS 介紹
JMS 即 Java 消息服務(Java Message Service)應用程序接口,是一個 Java 平臺中關於面向消息中間件(MOM)的 API,類似於 JDBC。用於在兩個應用程序之間,或分佈式系統中發送消息,進行異步通信。它提供創建、發送、接收、讀取消息的服務。由 Sun 公司和它的合作伙伴設計的應用程序接口和相應語法,使得 Java 程序能夠和其他消息組件進行通信。
JMS 是一個消息服務的標準或者說是規範,允許應用程序組件基於 JavaEE 平臺創建、發送、接收和讀取消息。它使分佈式通信耦合度更低,消息服務更加可靠以及異步性。
介紹到這裏,應該明白了消息隊列和 JMS 的區別了吧?
-
消息隊列:計算機科學中,A 和 B 進行通信的一種方式。
-
JMS:java 平臺之間分佈式通信的一種標準或者規範。
換句話說,JMS 就是 java 對於消息隊列的一種實現方式。
2.1JSM 消息模型
點對點,發佈訂閱,消息隊列中已經說的很清楚了,這裏就不重複說了。
2.2JMS 消費
- 同步(Synchronous)
訂閱者 / 接收方通過調用 receive() 來接收消息。在 receive()方法中,線程會阻塞直到消息到達或者到指定時間後消息仍未到達。
- 異步(Asynchronous)
消息訂閱者需註冊一個消息監聽者,類似於事件監聽器,只要消息到達,JMS 服務提供者會通過調用監聽器的 onMessage() 遞送消息。
2.3JMS 編程模型
JMS 編程模型非常類似於 JDBC。回憶一下,我們之前講到的 MyBatis。
-
SqlSessionFactoryBuilder 去構造 SqlSessionFactory 會話工廠;
-
SqlSessionFactory 會話工廠給我們打開 SqlSession 會話;
-
SqlSession 幫我們去連接數據庫,接着我們就可以執行增刪查改。
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession = sqlSessionFactory.openSession(true);
ProjectMapper mapper = openSession.getMapper(ProjectMapper.class);
mapper.queryAllTaskByInit("init");
JMS 模型如下
-
Connection Factory 給我創建 Connection 連接;
-
Connection 連接給我們創建了 Session 會話;
-
Session 會話給我們創建消費者和生產者;
-
生產者生成消息;
-
消費者消費消息;
3MQ 介紹
上文中,我們說到了,JMS 他並不是一種真正意義的技術,而是一種接口,一種規範。就想 JDBC 一樣,無論是 mybatis、hibernate,還是 springJPA,不管你是那種技術實現,反正你得遵守 JDBC 的規範。
在 Java 中,目前基於 JMS 實現的消息隊列常見技術有 ActiveMQ、RabbitMQ、RocketMQ。值得注意的是,RocketMQ 並沒有完全遵守 JMS 規範,並且 Kafka 不是 JMS 的實現。
3.1AMQP 協議
這裏我們以 RabbitMQ 爲例介紹 MQ,首先介紹下 AMQP
AMQP 協議(Advanced Message Queuing Protocol,高級消息隊列協議)是一個進程間傳遞異步消息的網絡協議。
AMQP 模型
AMQP 工作過程
發佈者(Publisher)發佈消息(Message),經由交換機(Exchange)。
交換機根據路由規則將收到的消息分發給與該交換機綁定的隊列、(Queue)。
最後 AMQP 代理會將消息投遞給訂閱了此隊列的消費者,或者消費者按照需求自行獲取。
RabbitMQ 是 MQ 產品的典型代表,是一款基於 AMQP 協議可複用的企業消息系統
3.2RabbitMQ 模型
RabbitMQ 由兩部分組成,分別是服務端和應用端;
-
服務端包括:隊列和交換機。
-
客戶端包括:生產者和消費者。
在 rabbitmq server 上可以創建多個虛擬的 message broker。每一個 broker 本質上是一個 mini-rabbitmq server,分別管理各自的 exchange,和 bindings。
broker 相當於物理的 server,可以爲不同 app 提供邊界隔離,使得應用安全的運行在不同的 broker 實例上,相互之間不會干擾。producer 和 consumer 連接 rabbit server 需要指定一個 broker。
Exchange 有 4 種類型:direct(默認),fanout, topic, 和 headers
-
Direct:直接交換器,工作方式類似於單播,Exchange 會將消息發送完全匹配 ROUTING_KEY 的 Queue。
-
Fanout:廣播是式交換器,不管消息的 ROUTING_KEY 設置爲什麼,Exchange 都會將消息轉發給所有綁定的 Queue(所謂綁定就是將一個特定的 Exchange 和一個特定的 Queue 綁定起來。Exchange 和 Queue 的綁定可以是多對多的關係)。
-
Topic: 主題交換器,工作方式類似於組播,Exchange 會將消息轉發和 ROUTING_KEY 匹配模式相同的所有隊列,比如,ROUTING_KEY 爲 user.stock 的 Message 會轉發給綁定匹配模式爲 * .stock,user.stock, * . * 和 #.user.stock.# 的隊列。( * 表是匹配一個任意詞組,# 表示匹配 0 個或多個詞組)。
至於如何在代碼中使用 RabbitMQ,這裏我們先不擼代碼,本文目前只介紹理論梳理知識點。
4Kafka
上完中我們提到過,kafka 不是 JMS 的實現,因此在 MQ 章節中,我們沒有提及到它。現在我們開始學習 kafka 吧。
先來放張 kafka 的原理圖,相信你看到這個圖片時,內心是奔潰的。我草,啥玩意。接下來我們就一點一點的消化吧。
4.1kafka 原理圖
先介紹上圖中的術語。
-
Producer :消息生產者,就是向 kafka broker 發消息的客戶端。
-
Consumer :消息消費者,向 kafka broker 取消息的客戶端。
-
Topic :kafka 給消息提供的分類方式。broker 用來存儲不同 topic 的消息數據。一個 Topic 可以認爲是一類消息,每個 topic 將被分成多個 partition(區), 每個 partition 在存儲層面是 append log 文件。任何發佈到此 partition 的消息都會被直接追加到 log 文件的尾部,每條消息在文件中的位置稱爲 offset(偏移量),offset 爲一個 long 型數字,它是唯一標記一條消息。它唯一的標記一條消息。kafka 並沒有提供其他額外的索引機制來存儲 offset,因爲在 kafka 中幾乎不允許對消息進行 “隨機讀寫”。
-
broker:中間件的 kafka cluster,存儲消息,是由多個 server 組成的集羣。
-
Partition:爲了實現擴展性,一個非常大的 topic 可以分佈到多個 broker(即服務器)上,一個 topic 可以分爲多個 partition,每個 partition 是一個有序的隊列。partition 中的每條消息都會被分配一個有序的 id(offset)。kafka 只保證按一個 partition 中的順序將消息發給 consumer,不保證一個 topic 的整體(多個 partition 間)的順序。
-
Offset:kafka 的存儲文件都是按照 offset.kafka 來命名,例如你想找位於 2049 的位置,只要找到 2048.kafka 的文件即可。當然 the first offset 就是 00000000000.kafka。
類似於 JMS 的特性,但不是 JMS 規範的實現。kafka 對消息保存時根據 Topic 進行歸類,發送消息者成爲 Producer,消息接受者成爲 Consumer, 此外 kafka 集羣有多個 kafka 實例組成,每個實例 (server) 成爲 broker。無論是 kafka 集羣,還是 producer 和 consumer 都依賴於 zookeeper 來保證系統可用性集羣保存信息。
kafka 基於文件存儲。通過分區, 可以將日誌內容分散到多個 server 上,來避免文件尺寸達到單機磁盤的上限,每個 partiton 都會被當前 server(kafka 實例) 保存;可以將一個 topic 切分多任意多個 partitions,來消息保存 / 消費的效率. 此外越多的 partitions 意味着可以容納更多的 consumer,有效提升併發消費的能力。
kafka 和 JMS 不同的是: 即使消息被消費, 消息仍然不會被立即刪除。日誌文件將會根據 broker 中的配置要求,保留一定的時間之後刪除。
Kafka 高可用機制
-
多個 broker 組成,每個 broker 是一個節點;
-
你創建一個 topic,這個 topic 可以劃分爲多個 partition,每個 partition 可以存在於不同的 broker 上,每個 partition 就放一部分數據。
-
採用 replica 副本機制,每個 partition 的數據都會同步到其他機器上,形成多個 replica 副本。
-
所有 replica 會選舉一個 leader 出來,那麼生產和消費都跟這個 leader 打交道,然後其他 replica 就是 follower。
-
讀數據時,從 leader 讀取,寫數據時,leader 把數據同步到所有 follower 上去。如果某個 broker 宕機了,這個 broker 在其他的 broker 還保留副本,假設這個 broker 上面存在 leader, 那麼就重新選一個 leader。
內容有點多,需要結合圖片一點一點消化
4.2 生產者結構圖
至此,雖然看的雲裏霧裏,不過相信你們還是能區分了吧?
整理一下:
-
消息隊列:指計算機領域中,A 和 B 通信的一種通信方式;
-
JMS:Java 中對於消息隊列的接口規範;
-
ActiveMQ/RabbitMQ:JMS 接口規範具體實現的一種技術;
-
RocketMQ:不完全是 JMS 接口規範具體實現的一種技術;
-
Kafka:非 JMS 接口規範具體實現的一種技術;
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/cw4RhENUaEZcWT5Cvjwmgg