梳理消息隊列 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 的區別了吧?

換句話說,JMS 就是 java 對於消息隊列的一種實現方式。

2.1JSM 消息模型

點對點,發佈訂閱,消息隊列中已經說的很清楚了,這裏就不重複說了。

2.2JMS 消費

訂閱者 / 接收方通過調用 receive() 來接收消息。在 receive()方法中,線程會阻塞直到消息到達或者到指定時間後消息仍未到達。

消息訂閱者需註冊一個消息監聽者,類似於事件監聽器,只要消息到達,JMS 服務提供者會通過調用監聽器的 onMessage() 遞送消息。

2.3JMS 編程模型

JMS 編程模型非常類似於 JDBC。回憶一下,我們之前講到的 MyBatis。

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

JMS 模型如下

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

至於如何在代碼中使用 RabbitMQ,這裏我們先不擼代碼,本文目前只介紹理論梳理知識點。

4Kafka

上完中我們提到過,kafka 不是 JMS 的實現,因此在 MQ 章節中,我們沒有提及到它。現在我們開始學習 kafka 吧。

先來放張 kafka 的原理圖,相信你看到這個圖片時,內心是奔潰的。我草,啥玩意。接下來我們就一點一點的消化吧。

4.1kafka 原理圖

先介紹上圖中的術語。

類似於 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 高可用機制

內容有點多,需要結合圖片一點一點消化

4.2 生產者結構圖

至此,雖然看的雲裏霧裏,不過相信你們還是能區分了吧?

整理一下:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/cw4RhENUaEZcWT5Cvjwmgg