分布式技術原理與實戰(zhàn)45講--第26講:消息隊列有哪些應用場景
分布式系統(tǒng)不同模塊之間的通信,除了 遠程服務調(diào)用 以外,消息中間件是另外一個重要的手段,在各種互聯(lián)網(wǎng)系統(tǒng)設計中,消息隊列有著廣泛的應用。從本課時開始,專欄進入分布式消息的模塊,將討論消息隊列使用中的高頻問題,先來看一下,消息隊列的應用場景。
什么是消息隊列
消息隊列,顧名思義,就是傳遞消息的隊列,學習操作系統(tǒng)中進程通信的時候我們知道,消息隊列是進程之間的一種很重要的通信機制。隨著分布式系統(tǒng)的發(fā)展,消息隊列在系統(tǒng)設計中又有了更多的應用。
參與消息傳遞的雙方稱為生產(chǎn)者和消費者,生產(chǎn)者和消費者可以只有一個實例,也可以集群部署,典型架構(gòu)如下圖所示:

其中消息體是參與生產(chǎn)和消費兩方傳遞的數(shù)據(jù),消息格式既可以是簡單的字符串,也可以是序列化后的復雜文檔信息。隊列是消息的載體,用于傳輸和保存消息,它和數(shù)據(jù)結(jié)構(gòu)中的隊列一樣,可以支持先進先出、優(yōu)先級隊列等不同的特性。
消息隊列有哪些應用
消息隊列可以用于系統(tǒng)內(nèi)部組件之間的通信,也可以用于系統(tǒng)跟其他服務之間的交互,消息隊列的使用,增加了系統(tǒng)的可擴展性。下面把消息隊列的應用歸納為以下幾點。
系統(tǒng)解耦
設計模式中有一個開閉原則,指的是軟件實體應該對擴展開放、對修改關閉,盡量保持系統(tǒng)之間的獨立,這里面蘊含的是解耦思想。而消息隊列的使用,可以認為是在系統(tǒng)中隱含地加入了一個對外的擴展接口,能夠方便地對業(yè)務進行解耦,調(diào)用方只需要發(fā)送消息而不用關注下游邏輯如何執(zhí)行。

那你可能會有疑問,系統(tǒng)之間的解耦,使用 RPC 服務調(diào)用也可以實現(xiàn),使用消息隊列有什么好處嗎?使用遠程服務調(diào)用,需要在其中一個調(diào)用方進行顯式地編碼業(yè)務邏輯;如果使用消息隊列就不會有這個問題了,系統(tǒng)之間可以更好地實現(xiàn)依賴倒轉(zhuǎn),這也是設計模式中的一個重要原則。
異步處理
異步化是一個非常重要的機制,在處理高并發(fā)、高可用等系統(tǒng)設計時,如果不需要或者限制于系統(tǒng)承載能力,不能立即處理消息,此時就可以應用消息隊列,將請求異步化。
異步處理的一個典型場景是 流量削峰,我們用電商的秒殺場景來舉例。秒殺搶購的流量峰值是很高的,很多時候服務并不能承載這么高的瞬間流量,于是可以引入消息隊列,結(jié)合限流工具,對超過系統(tǒng)閾值的請求,在消息隊列中暫存,等待流量高峰過去以后再進行處理。
請求緩沖
在典型的生產(chǎn)者和消費者模型中,就是通過一個隊列來實現(xiàn)緩沖的。使用消息隊列,可以作為一個緩沖層,平滑各個業(yè)務系統(tǒng)之間處理性能的不同等,在早期的企業(yè)應用系統(tǒng)中,有一個企業(yè)數(shù)據(jù)總線(ESB)的概念,實現(xiàn)的就是內(nèi)部各個系統(tǒng)之間的集成。
數(shù)據(jù)分發(fā)
消息隊列有不同的訂閱模式,支持一對多的廣播機制,可以用來實現(xiàn)數(shù)據(jù)的分發(fā)。典型的比如關系型數(shù)據(jù)庫對 binlog 訂閱的處理,由于主庫的 binlog 只有一份,但是下游的消費方可能包括各種文件索引、離線數(shù)據(jù)庫等,這時候就可以應用消息隊列來實現(xiàn)數(shù)據(jù)的分發(fā)。
除了這些典型應用,消息隊列還可以用來實現(xiàn)分布式事務,在第 06 課時“分布式事務有哪些解決方案”中我們提過,利用 數(shù)據(jù)庫+本地消息表 的方式分布式一致性,是一個非常經(jīng)典的分布式事務解決方案。
幾種常見的消息隊列
主流的消息中間件有以下幾種,其中每種 MQ 又有其對應的應用場景。
Apache Kafka
大名鼎鼎的 Kafka 是高性能消息隊列的代表,Kafka 是 LinkedIn 開源的一個分布式消息系統(tǒng),主要使用 Scala 語言開發(fā),已經(jīng)加入 Apache 頂級項目。
Kafka 集群部署時依賴 ZooKeeper 環(huán)境,相比其他的消息隊列,運維成本要高很多,ZooKeeper 的引入,使得 Kafka 可以非常方便地進行水平擴展,支持海量數(shù)據(jù)的傳輸。
Kafka 的另外一個特點是高吞吐率,在消息持久化寫入磁盤的過程中,使用了多種技術來實現(xiàn)讀寫的高性能,包括磁盤的順序讀寫、零拷貝技術等。
Apache RocketMQ
RocketMQ 是阿里巴巴開源的一款消息中間件,使用Java語言開發(fā),在阿里內(nèi)部應用非常廣泛,很多高并發(fā)的業(yè)務場景下都有 RocketMQ 的應用。
RocketMQ 經(jīng)過了雙十一的檢驗,消息傳遞的穩(wěn)定性和可靠性都比較有保障。以消息持久化為例,我們知道,Linux 文件在寫入磁盤時,也就是常說的刷盤操作,因為存在緩存,可能會出現(xiàn)數(shù)據(jù)丟失的情況,RocketMQ 為了保證數(shù)據(jù)一致性,在寫入磁盤時支持同步刷盤方式,即消息存儲磁盤成功,才會返回消息發(fā)送成功的響應。
RocketMQ 在實現(xiàn)上有很多這種細節(jié)的設計,盡可能地保證了消息投遞中的順序一致性及可靠性,并且優(yōu)化了響應時間,特別適合電商等相對復雜的業(yè)務中應用。
Apache RabbitMQ
RabbitMQ 是使用 Erlang 語言編寫的一個開源消息隊列,功能比較全面,支持多種消息傳輸?shù)膮f(xié)議。
我們知道不同的消息隊列有很多,為了約束其實現(xiàn),也就有了一些對應的實現(xiàn)標準,AMQP 是一個異步消息傳輸?shù)木W(wǎng)絡協(xié)議,RabbitMQ 是典型實現(xiàn)代表,除了 AMQP,RabbitMQ 同時支持 MQTT、STOMP 等協(xié)議,對于具體的協(xié)議內(nèi)容,這里不展開,感興趣的同學可以去找相關資料了解下。Kafka 和 RocketMQ 實現(xiàn)的是自定義協(xié)議,實現(xiàn)起來靈活度更高。
除了順序傳輸,RabbitMQ 還可以支持優(yōu)先級隊列等特性,不過,它不適合處理大數(shù)據(jù)量的消息,一旦出現(xiàn)消息堆積,性能下降比較快,所以 RabbitMQ 比較適合企業(yè)級應用。
除了上面提到的三款主流消息隊列,還有 ActiveMQ、ZeroMQ 等,也都有各自適合的應用場景。思考一下,如果在一個電商系統(tǒng)的構(gòu)建中,這三款消息隊列可以怎樣組合使用呢?
Kafka 可以在各類數(shù)據(jù)埋點中使用,比如電商營銷的轉(zhuǎn)化率日志收集和計算,另外,Kafka 的高性能使得特別它適合應用在各類監(jiān)控、大數(shù)據(jù)分析等場景。
RocketMQ 對一致性的良好保證,可以應用在電商各級業(yè)務調(diào)用的拆分中,比如在訂單完成后通知用戶,物流信息更新以后對訂單狀態(tài)的更新等。
RabbitMQ 則可以在數(shù)據(jù)遷移、系統(tǒng)內(nèi)部的業(yè)務調(diào)用中應用,比如一些后臺數(shù)據(jù)的同步、各種客服和 CRM 系統(tǒng)。
總結(jié)
這一課時分享了消息隊列的知識點,包括消息隊列的結(jié)構(gòu)、消息隊列的應用場景,以及幾種常見的消息隊列的應用。
通過本課時的學習,你已經(jīng)了解了消息隊列的基本應用,你可以結(jié)合自己的工作,思考一下都在哪些地方應用了消息隊列,以及發(fā)揮了什么作用。繼續(xù)擴展一下,如果讓你來設計一個消息隊列,應該怎么設計呢?比如消息體是否需要持久化?如何存儲消息,如何保證消息的順序投遞,如果出現(xiàn)重復消費該如何解決,歡迎留言分享你的想法,關于這些問題的討論,也會在后面的課時中展開講解。