消息隊列(Message Queue,簡稱 MQ)作為構建分布式互聯網應用的關鍵組件,松耦合的架構設計能顯著提升系統的可用性與可擴展性。在分布式系統中扮演著至關重要的角色,主要承擔著實現異步消息傳遞、應用解耦、流量削峰以及消息通訊等關鍵功能。
一、消息隊列的應用場景
1、異步處理
以用戶注冊并需發送注冊郵件和短信為例。用戶完成注冊后,系統需要執行發送注冊郵件和注冊短信這兩項操作。傳統的處理方式有串行和并行兩種,具體如下:
1)串行方式:先將注冊信息成功寫入數據庫,接著發送注冊郵件,最后發送注冊短信。只有當這三個任務全部完成后,才會向客戶端返回結果。
2)并行方式:在將注冊信息成功寫入數據庫后,同時發送注冊郵件和注冊短信。同樣,要等這三個任務都完成,再向客戶端返回結果。與串行方式相比,并行方式能縮短處理時間。假設每個業務節點的處理時間均為 50 毫秒,不考慮網絡等其他開銷,那么串行方式的總耗時為 150 毫秒,并行方式的總耗時則可能為 100 毫秒。由于 CPU 在單位時間內處理的請求數是固定的,假設 CPU1 秒內的吞吐量是 100 次,那么串行方式 1 秒內 CPU 可處理的請求量約為 7 次(1000ms/150ms),并行方式則約為 10 次(1000ms/100ms)。
而引入消息隊列后,對于非必須的業務邏輯,可采用異步處理方式。改造后的架構下,用戶的響應時間相當于注冊信息寫入數據庫的時間,即 50 毫秒。因為注冊郵件和發送短信的請求寫入消息隊列后便直接返回,且寫入消息隊列的速度極快,耗時基本可忽略不計。如此一來,系統的吞吐量可提升至每秒 20 QPS,相比串行方式提高了 3 倍,相比并行方式提高了 2 倍。
2、應用解耦
以用戶下單購買業務為例。在傳統模式中,用戶下單后,訂單系統需要調用庫存系統的接口來通知庫存系統。這種模式存在明顯缺點:一是若庫存系統無法訪問,訂單減庫存操作就會失敗,進而導致訂單失敗;二是訂單系統與庫存系統存在緊密耦合。
引入應用消息隊列后的方案則有效解決了這些問題:
1)訂單系統:用戶下單后,訂單系統完成持久化處理,將消息寫入消息隊列,隨后向用戶返回訂單下單成功的信息。
2)庫存系統:通過訂閱下單的消息,采用拉取或推送的方式獲取下單信息,然后根據這些信息進行庫存操作。
即便在下單時庫存系統無法正常使用,也不會影響用戶正常下單,因為訂單系統在將信息寫入消息隊列后,就不再關注后續操作了。這就實現了訂單系統與庫存系統的應用解耦。
3、流量削峰
流量削峰是消息隊列的又一常用場景,在秒殺或團搶活動中應用廣泛。秒殺活動往往會因參與人數過多導致流量暴增,極易使應用崩潰。為解決這一問題,可在應用前端加入消息隊列,其作用主要有兩點:一是能夠控制參與活動的人數;二是可以緩解短時間內的高流量對應用造成的壓力。
具體實現方式如下:
1)服務器接收用戶的請求后,首先將其寫入消息隊列。若消息隊列的長度超過最大限制,就直接拋棄該用戶請求或引導用戶跳轉到錯誤頁面。
2)秒殺業務根據消息隊列中的請求信息,進行后續的處理。
4、消息通訊
消息通訊是指消息隊列通常內置了高效的通信機制,因此也可用于消息通訊。例如,可實現點對點消息隊列或聊天室等功能。這實際上對應了消息隊列的兩種消息模式,即點對點模式和發布訂閱模式。
二、常用消息隊列各項對比
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka | |
生產者消費者模式(Producer-Consumer) | 支持 | 支持 | 支持 | 支持 | |
發布訂閱模式(Publish-Subscribe) | 支持 | 支持 | 支持 | 支持 | |
請求回應模型(Request-Reply) | 支持 | 支持 | 不支持 | 不支持 | |
API 完備性 | 高 | 高 | 高 | 高 | |
多語言支持 | 支持 | 支持 | 只支持 JAVA | 支持 | |
單機吞吐量 | 萬級 | 萬級 | 萬級 | 十萬級 | |
消息延遲 | 無 | 微秒級 | 毫秒級 | 毫秒級 | |
可用性 | 高(主從) | 高(主從) | 非常高(分布式) | 非常高(分布式) | |
消息丟失 | 低 | 低 | 理論上不會丟失 | 理論上不會丟失 | |
文檔的完備性 | 高 | 高 | 高 | 高 | |
提供快速入門 | 有 | 有 | 有 | 有 | |
社區活躍度 | 高 | 高 | 中 | 高 | |
商業支持 | 無 | 無 | 阿里云 | 主流云服務廠商? |
三、ActiveMQ、RabbitMQ、RocketMQ、Kafka 特點
ActiveMQ
ActiveMQ 是一個歷史悠久的開源項目,在眾多產品中都有應用。它實現了 JMS1.1 規范,能與 spring-jms 輕松融合,還支持多種協議。不過,它不夠輕巧(源代碼比 RocketMQ 多),支持持久化到數據庫,但在隊列數量較多的情況下,表現欠佳。
RabbitMQ
相比 Kafka,RabbitMQ 更為成熟,支持 AMQP 事務處理。在可靠性方面,它超過 Kafka;在性能方面,又優于 ActiveMQ。
RocketMQ
RocketMQ 是阿里開源的消息中間件,目前正在 Apache 進行孵化。它采用純 Java 開發,具有高吞吐量、高可用性的特點,適合大規模分布式系統應用。其設計思路源于 Kafka,但并非簡單復制,而是對消息的可靠傳輸及事務性進行了優化。目前,RocketMQ 在阿里集團被廣泛應用于交易、充值、流計算、消息推送、日志流式處理、binglog 分發等場景,支撐了阿里多次雙十一活動。由于它是阿里從實踐中發展而來的產品,部分接口和 API 的通用性不是很強。但它的可靠性毋庸置疑,且在性能上與 Kafka 一脈相承甚至更優,還支持海量消息堆積。
Kafka
Kafka 的設計初衷是處理日志,不支持 AMQP 事務處理,可將其視為一個日志系統,針對性很強,因此并不具備成熟 MQ 應有的全部特性。不過,Kafka 的性能(吞吐量、tps)強于 RabbitMQ,在處理大數據量的快速處理場景中,比 RabbitMQ 更具優勢。