Java架構之訊息佇列 (一):訊息佇列的概述
訊息佇列系列分享大綱:
一、訊息佇列的概述
二、訊息佇列之RabbitMQ的使用
三、訊息佇列之Kafka的使用
四、訊息佇列之RabbitMQ的原理詳解
五、訊息佇列之Kafka的原理詳解
六、訊息佇列之面試集錦
1.訊息佇列的概述
訊息佇列(Message Queue)中介軟體是分散式系統中重要的元件; 主要解決應用耦合,非同步訊息,流量削鋒等問題; 實現高效能,高可用,可伸縮和最終一致性架構。是大型分散式系統不可缺少的中介軟體; 目前在生產環境,使用較多的訊息佇列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ 部分資料庫如Redis、Mysql以及phxsql也可實現訊息佇列的功能; 具有 低耦合、可靠投遞、廣播、流量控制、最終一致性 等一系列功能。 |
2.訊息佇列使用場景
訊息佇列在實際應用中有四個場景:
- 應用耦合:多應用間通過訊息佇列對同一訊息進行處理,避免呼叫介面失敗導致整個過程失敗;
- 非同步處理:多應用對訊息佇列中同一訊息進行處理,應用間併發處理訊息,相比序列處理,減少處理時間;
- 限流削峰:廣泛應用於秒殺或搶購活動中,避免流量過大導致應用系統掛掉的情況;
- 訊息驅動的系統:系統分為訊息佇列、訊息生產者、訊息消費者,生產者負責產生訊息,消費者(可能有多個)負責對訊息進行處理;
2.1非同步處理
具體場景:使用者為了使用某個應用,進行註冊,系統需要傳送註冊郵件並驗證簡訊。對這兩個操作的處理方式有兩種:序列及並行
(1)序列方式:新註冊資訊生成後,先發送註冊郵件,再發送驗證簡訊;
在這種方式下,需要最終傳送驗證簡訊後再返回給客戶端。
(2)並行處理:新註冊資訊寫入後,由發簡訊和發郵件並行處理;
在這種方式下,發簡訊和發郵件 需處理完成後再返回給客戶端。
假設以上三個子系統處理的時間均為50ms,且不考慮網路延遲,則總的處理時間:
序列:50+50+50=150ms 並行:50+50 = 100ms
若使用訊息佇列:
並在寫入訊息佇列後立即返回成功給客戶端,則總的響應時間依賴於寫入訊息佇列的時間,而寫入訊息佇列的時間本身是可以很快的,基本可以忽略不計,因此總的處理時間相比序列提高了2倍,相比並行提高了一倍;
2.2 應用耦合
具體場景:使用者使用QQ相簿上傳一張圖片,人臉識別系統會對該圖片進行人臉識別,一般的做法是,伺服器接收到圖片後,圖片上傳系統立即呼叫人臉識別系統,呼叫完成後再返回成功,如下圖所示:
該方法有如下缺點:
- 人臉識別系統被調失敗,導致圖片上傳失敗;
- 延遲高,需要人臉識別系統處理完成後,再返回給客戶端,即使使用者並不需要立即知道結果;
- 圖片上傳系統與人臉識別系統之間互相呼叫,需要做耦合;
若使用訊息佇列:
客戶端上傳圖片後,圖片上傳系統將圖片資訊寫入訊息佇列,直接返回成功;而人臉識別系統則定時從訊息佇列中取資料,完成對新增圖片的識別。
人臉識別系統可以選擇不同的排程策略,按照閒時、忙時、正常時間,對佇列中的圖片資訊進行處理。
2.3 限流削峰
具體場景:購物網站開展秒殺活動,一般由於瞬時訪問量過大,伺服器接收過大,會導致流量暴增,相關係統無法處理請求甚至崩潰。而加入訊息佇列後,系統可以從訊息佇列中取資料,相當於訊息佇列做了一次緩衝。
該方法有如下優點:
- 請求先入訊息佇列,而不是由業務處理系統直接處理,做了一次緩衝,極大地減少了業務處理系統的壓力;
- 佇列長度可以做限制,事實上,秒殺時,後入佇列的使用者無法秒殺到商品,這些請求可以直接被拋棄,返回活動已結束或商品已售完資訊;
2.4 日誌處理
日誌處理是指將訊息佇列用在日誌處理中,比如Kafka的應用,解決大量日誌傳輸的問題。架構簡化如下:
訊息佇列應用於日誌處理的架構
- 日誌採集客戶端:負責日誌資料採集,定時寫受寫入Kafka佇列;
- Kafka訊息佇列:負責日誌資料的接收,儲存和轉發;
- 日誌處理應用:訂閱並消費kafka佇列中的日誌資料;
|
2.5訊息通訊
訊息通訊是指,訊息佇列一般都內建了高效的通訊機制,因此也可以用在純的訊息通訊。比如實現點對點訊息佇列,或者聊天室等。
點對點通訊:
客戶端A和客戶端B使用同一佇列,進行訊息通訊。
聊天室通訊:
客戶端A,客戶端B,客戶端N訂閱同一主題,進行訊息釋出和接收。實現類似聊天室效果。
以上實際是訊息佇列的兩種訊息模式,點對點或釋出訂閱模式,下面會介紹這兩種模式。
3.訊息佇列的兩種模式
訊息佇列包括兩種模式,點對點模式(point to point, queue)和釋出/訂閱模式(publish/subscribe,topic)。 JMS(JAVA Message Service,java訊息服務)API是一個訊息服務的標準/規範,允許應用程式元件基於JavaEE平臺建立、傳送、接收和讀取訊息。 在JMS標準中,有兩種訊息模型P2P(Point to Point),Publish/Subscribe(Pub/Sub)。 |
3.1 點對點模式
點對點模式下包括三個角色:
- 訊息佇列
- 傳送者 (生產者)
- 接收者(消費者)
訊息傳送者生產訊息傳送到queue中,然後訊息接收者從queue中取出並且消費訊息。訊息被消費以後,queue中不再有儲存,所以訊息接收者不可能消費到已經被消費的訊息。
點對點模式特點:
- 每個訊息只有一個接收者(Consumer)(即一旦被消費,訊息就不再在訊息佇列中);
- 傳送者和接收者間沒有依賴性,傳送者傳送訊息之後,不管有沒有接收者在執行,都不會影響到傳送者下次傳送訊息;
- 接收者在成功接收訊息之後需向佇列應答成功,以便訊息佇列刪除當前接收的訊息;
3.2 釋出/訂閱模式
釋出/訂閱模式下包括三個角色:
- 角色主題(Topic)
- 釋出者(Publisher)
- 訂閱者(Subscriber)
釋出者將訊息傳送到Topic,系統將這些訊息傳遞給多個訂閱者。
釋出/訂閱模式特點:
- 每個訊息可以有多個訂閱者;
- 釋出者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須建立一個訂閱者之後,才能消費釋出者的訊息。
- 為了消費訊息,訂閱者需要提前訂閱該角色主題,並保持線上執行;
4.訊息中介軟體案例
3.1電商系統
訊息佇列採用高可用,可持久化的訊息中介軟體。比如Active MQ,Rabbit MQ,Rocket Mq。
(1)應用將主幹邏輯處理完成後,寫入訊息佇列。訊息傳送是否成功可以開啟訊息的確認模式。(訊息佇列返回訊息接收成功狀態後,應用再返回,這樣保障訊息的完整性)
(2)擴充套件流程(發簡訊,配送處理)訂閱佇列訊息。採用推或拉的方式獲取訊息並處理。
(3)訊息將應用解耦的同時,帶來了資料一致性問題,可以採用最終一致性方式解決。比如主資料寫入資料庫,擴充套件應用根據訊息佇列,並結合資料庫方式實現基於訊息佇列的後續處理。
3.2日誌收集系統
分為Zookeeper註冊中心,日誌收集客戶端,Kafka叢集和Storm叢集(OtherApp)四部分組成。
- Zookeeper註冊中心,提出負載均衡和地址查詢服務;
- 日誌收集客戶端,用於採集應用系統的日誌,並將資料推送到kafka佇列;
- Kafka叢集:接收,路由,儲存,轉發等訊息處理;
Storm叢集:與OtherApp處於同一級別,採用拉的方式消費佇列中的資料;
5.常用訊息佇列介紹
5.1.ZeroMQ
ZeroMQ號稱是“史上最快的訊息佇列”,基於c語言開發的,可以在任何平臺通過任何程式碼連線,通過inproc、IPC、TCP、TIPC、多播傳送訊息,支援釋出-訂閱、推-拉、共享佇列等模式,高速非同步I/O引擎。 根據官方的說法,ZeroMQ是一個簡單好用的傳輸層,像框架一樣的可嵌入的socket類庫,使Socket程式設計更加簡單、簡潔、效能更高,是專門為高吞吐量/低延遲的場景開發的。ZeroMQ與其他MQ有著本質的區別,它根本不是訊息佇列伺服器,更類似與一個底層網路通訊庫,對原有Socket API進行封裝,在使用的使用引入對應的jar包即可,可謂是相當靈活。 同時,因為它的簡單靈活,如果我們想作為訊息佇列使用的話,需要開發大量程式碼。而且,ZeroMQ不支援訊息持久化,其定位並不是安全可靠的訊息傳輸,所以還需要自己編碼保證可靠性。簡而言之一句話,ZeroMQ很強大,但是想用好需要自己實現。 特點是:
ZeroMQ高效能設計要點: 1、無鎖的佇列模型 對於跨執行緒間的互動(使用者端和session)之間的資料交換通道pipe,採用無鎖的佇列演算法CAS;在pipe兩端註冊有非同步事件,在讀或者寫訊息到pipe的時,會自動觸發讀寫事件。 2、批量處理的演算法 對於傳統的訊息處理,每個訊息在傳送和接收的時候,都需要系統的呼叫,這樣對於大量的訊息,系統的開銷比較大,zeroMQ對於批量的訊息,進行了適應性的優化,可以批量的接收和傳送訊息。 3、多核下的執行緒繫結,無須CPU切換 區別於傳統的多執行緒併發模式,訊號量或者臨界區, zeroMQ充分利用多核的優勢,每個核繫結執行一個工作者執行緒,避免多執行緒之間的CPU切換開銷。 |
5.2 ActiveMQ
ActiveMQ是由Apache出品,ActiveMQ 是一個完全支援JMS1.1和J2EE 1.4規範的 JMS Provider實現。它非常快速,支援多種語言的客戶端和協議,而且可以非常容易的嵌入到企業的應用環境中,並有許多高階功能。 主要特性:
使用ActiveMQ需要:
ActiveMQ可以執行在Java語言所支援的平臺之上。 優點:
缺點:
|
5.3.RabbitMQ
概述: RabbitMQ是流行的開源訊息佇列系統,用erlang語言開發。 RabbitMQ是AMQP(高階訊息佇列協議)的標準實現。 支援多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支援AJAX,持久化。 用於在分散式系統中儲存轉發訊息,在易用性、擴充套件性、高可用性等方面表現不俗。 主要特性:
優點:
缺點:
|
重要概念:
訊息佇列的使用過程,如下:
|
5.4.RocketMQ
RocketMQ出自 阿里公司的開源產品,用 Java 語言實現,在設計時參考了 Kafka,並做出了自己的一些改進,訊息可靠性上比 Kafka 更好。RocketMQ在阿里集團被廣泛應用在訂單,交易,充值,流計算,訊息推送,日誌流式處理,binglog分發等場景。 主要特性:
使用RocketMQ需要:
RocketMQ可以執行在Java語言所支援的平臺之上。 優點:
缺點:
|
5.5 Kafka
Apache Kafka是一個分散式訊息釋出訂閱系統。它最初由LinkedIn公司基於獨特的設計實現為一個分散式的提交日誌系統( a distributed commit log),,之後成為Apache專案的一部分。Kafka系統快速、可擴充套件並且可持久化。它的分割槽特性,可複製和可容錯都是其不錯的特性。 主要特性:
使用Kafka需要:
優點:
缺點:
|
5.6 Apollo
Apache稱Apollo為最快、最強健的STOMP伺服器。支援STOMP、AMQP、MQTT、OpenWire協議,支援Topic、Queue、持久訂閱等消費形式,支援對訊息的多種處理,支援安全性處理,支援REST管理API。。。功能列表很長,最大的弊病就是目前市場接收度不夠,所以使用的並不廣泛。 |
6. RabbitMQ/ActiveMQ/RocketMQ/Kafka對比
結論:
Kafka在於分散式架構,RabbitMQ基於AMQP協議來實現,RocketMQ/思路來源於kafka,改成了主從結構,在事務性可靠性方面做了優化。廣泛來說,電商、金融等對事務性要求很高的,可以考慮RabbitMQ和RocketMQ,對效能要求高的可考慮Kafka。
7.訊息佇列MQ選型
綜合上面的材料得出以下兩點: (1)中小型軟體公司: 建議選RabbitMQ erlang語言天生具備高併發的特性,而且他的管理介面用起來十分方便。正所謂,成也蕭何,敗也蕭何!他的弊端也在這裡,雖然RabbitMQ是開源的,然而國內有幾個能定製化開發erlang的程式設計師呢?所幸,RabbitMQ的社群十分活躍,可以解決開發過程中遇到的bug,這點對於中小型公司來說十分重要。 不考慮rocketmq和kafka的原因是,一方面中小型軟體公司不如網際網路公司,資料量沒那麼大,選訊息中介軟體,應首選功能比較完備的,所以kafka排除。不考慮rocketmq的原因是,rocketmq是阿里出品,如果阿里放棄維護rocketmq,中小型公司一般抽不出人來進行rocketmq的定製化開發,因此不推薦。 (2)大型軟體公司: 根據具體使用在rocketMq和kafka之間二選一。 大型軟體公司,具備足夠的資金搭建分散式環境,也具備足夠大的資料量。針對rocketMQ,大型軟體公司也可以抽出人手對rocketMQ進行定製化開發,畢竟國內有能力改JAVA原始碼的人,還是相當多的。 至於kafka,根據業務場景選擇,如果有日誌採集功能,肯定是首選kafka了。具體該選哪個,看使用場景。 |