在這種情況下,在訂閱者 未連接時,發佈的消息將在訂閱者 重新連接 時 重新發布,如下圖所示:
特性:
每個消息可以有多個訂閱者;客戶端只有訂閱後才能接收到消息;持久訂閱和非持久訂閱。注意:
發佈者和訂閱者有時間依賴:接受者和發佈者只有建立訂閱關係才能收到消息;持久訂閱:訂閱關係建立後,消息就不會消失,不管訂閱者是否都在線;非持久訂閱:訂閱者為了接受消息,必須一直在線。 當只有一個訂閱者時約等於點對點模式5. 消息隊列應用場景
當你需要使用 消息隊列 時,首先需要考慮它的必要性。可以使用消息隊列的場景有很多,最常用的幾種,是做
5.1. 異步處理
非核心 流程 異步化,減少系統 響應時間,提高 吞吐量。例如:短信通知、終端狀態推送、App 推送、用戶註冊 等。
消息隊列 一般都內置了
應用案例
網站用戶註冊,註冊成功後會過一會發送郵件確認或者短息。
5.2. 系統解耦
系統之間不是 強耦合的,消息接受者 可以隨意增加,而不需要修改 消息發送者的代碼。消息發送者 的成功不依賴 消息接受者(比如:有些銀行接口不穩定,但調用方並不需要依賴這些接口)。不強依賴 於非本系統的核心流程,對於 非核心流程,可以放到消息隊列中讓 消息消費者5.3. 最終一致性
最終一致性 不是 消息隊列 的必備特性,但確實可以依靠 消息隊列 來做 最終一致性 的事情。
先寫消息再操作,確保操作完成後再修改消息狀態。定時任務補償機制 實現消息 可靠發送接收、業務操作的可靠執行,要注意 消息重複 與 冪等設計。所有不保證 100% 不丟消息 的消息隊列,理論上無法實現 最終一致性。像 Kafka 一類的設計,在設計層面上就有 丟消息 的可能(比如 定時刷盤
5.4. 廣播
生產者/消費者 模式,只需要關心消息是否 送達隊列,至於誰希望訂閱和需要消費,是 下游 的事情,無疑極大地減少了開發和聯調的工作量。
5.5. 流量削峰和流控
當 上下游系統 處理能力存在差距的時候,利用 消息隊列 做一個通用的 “漏斗”,進行 限流控制。在下游有能力處理的時候,再進行分發。
舉個例子:用戶在支付系統成功結賬後,訂單系統會通過短信系統向用戶推送扣費通知。 短信系統 可能由於 短板效應,速度卡在 網關 上(每秒幾百次請求),跟 前端的併發量 不是一個數量級。 於是,就造成 支付系統 和 短信系統 的處理能力出現差異化。
然而用戶晚上個半分鐘左右收到短信,一般是不會有太大問題的。如果沒有消息隊列,兩個系統之間通過
所以,利用中間系統轉儲兩個系統的通信內容,並在下游系統有能力處理這些消息的時候,再處理這些消息,是一套相對較通用的方式。
應用案例
把消息隊列當成可靠的 消息暫存地,進行一定程度的 消息堆積;定時進行消息投遞,比如模擬 用戶秒殺5.6. 日誌處理
將消息隊列用在 日誌處理 中,比如 Kafka 的應用,解決 海量日誌 傳輸和緩衝的問題。
應用案例
把日誌進行集中收集,用於計算 PV、
5.7. 消息通訊
消息隊列一般都內置了 高效的通信機制,因此也可以用於單純的 消息通訊,比如實現 點對點消息隊列 或者 聊天室 等。
6. 消息隊列的推拉模型
6.1. Push推消息模型
消息生產者 將消息發送給 消息隊列,消息隊列 又將消息推給 消息消費者。
6.2. Pull拉消息模型
消費者 請求 消息隊列 接受消息,消息生產者 從 消息隊列 中拉該消息。
6.3. 兩種類型的區別
7. 消息隊列技術對比
本部分主要介紹四種常用的消息隊列(ActiveMQ / RabbitMQ / RocketMQ / Kafka)的主要特性、優點、缺點。
7.1. ActiveMQ
ActiveMQ 是由 Apache 出品,ActiveMQ 是一個完全支持JMS1.1 和 J2EE 1.4 規範的 JMS Provider 實現。它非常快速,支持 多種語言的客戶端 和 協議,而且可以非常容易的嵌入到企業的應用環境中,並有許多高級功能。
(a) 主要特性
服從JMS規範:JMS 規範提供了良好的標準和保證,包括:同步 或 異步 的消息分發,一次和僅一次的消息分發,消息接收 和 訂閱 等等。遵從 JMS 規範的好處在於,不論使用什麼 JMS 實現提供者,這些基礎特性都是可用的;連接靈活性:ActiveMQ 提供了廣泛的 連接協議,支持的協議有:HTTP/S,IP 多播,SSL,TCP,UDP 等等。對眾多協議的支持讓 ActiveMQ 擁有了很好的靈活性;支持的協議種類多:OpenWire、STOMP、REST、XMPP、AMQP;持久化插件和安全插件:ActiveMQ 提供了 多種持久化 選擇。而且,ActiveMQ 的安全性也可以完全依據用戶需求進行 自定義鑑權 和 授權(b) 部署環境
ActiveMQ 可以運行在 Java 語言所支持的平臺之上。使用 ActiveMQ 需要:
Java JDKActiveMQ 安裝包(c) 優點
跨平臺 (JAVA 編寫與平臺無關,ActiveMQ 幾乎可以運行在任何的 JVM 上);可以用 JDBC:可以將 數據持久化 到數據庫。雖然使用 JDBC 會降低 ActiveMQ 的性能,但是數據庫一直都是開發人員最熟悉的存儲介質;支持 JMS 規範:支持 JMS 規範提供的(d) 缺點
社區活躍度不及 RabbitMQ 高;根據其他用戶反饋,會出莫名其妙的問題,會 丟失消息;目前重心放到 activemq 6.0 產品 Apollo,對 5.x 的維護較少;不適合用於 上千個隊列 的應用場景;7.2. RabbitMQ
RabbitMQ 於 2007 年發佈,是一個在 AMQP (高級消息隊列協議)基礎上完成的,可複用的企業消息系統,是當前最主流的消息中間件之一。
(a) 主要特性
可靠性:提供了多種技術可以讓你在 性能 和 可靠性 之間進行 權衡。這些技術包括 持久性機制、投遞確認、發佈者證實 和 高可用性機制;靈活的路由:消息在到達隊列前是通過 交換機 進行 路由 的。RabbitMQ 為典型的路由邏輯提供了 多種內置交換機 類型。如果你有更復雜的路由需求,可以將這些交換機組合起來使用,你甚至可以實現自己的交換機類型,並且當做 RabbitMQ 的 插件 來使用;消息集群:在相同局域網中的多個 RabbitMQ 服務器可以(b) 部署環境
RabbitMQ 可以運行在 Erlang 語言所支持的平臺之上,包括 Solaris,BSD,Linux,MacOSX,TRU64,Windows 等。使用 RabbitMQ 需要:
ErLang 語言包RabbitMQ 安裝包(c) 優點
由於 Erlang 語言的特性,消息隊列性能較好,支持 高併發;健壯、穩定、易用、跨平臺、支持 多種語言、文檔齊全;有消息 確認機制 和 持久化機制,可靠性高;高度可定製的 路由;管理界面 較豐富,在互聯網公司也有較大規模的應用,社區活躍度高。(d) 缺點
儘管結合 Erlang 語言本身的併發優勢,性能較好,但是不利於做 二次開發和維護;實現了 代理架構,意味著消息在發送到客戶端之前可以在7.3. RocketMQ
RocketMQ 出自 阿里 的開源產品,用 Java 語言實現,在設計時參考了 Kafka,並做出了自己的一些改進,消息可靠性上 比 Kafka 更好。RocketMQ 在阿里內部被廣泛應用在 訂單,交易,充值,流計算,消息推送,日誌流式處理,binglog 分發 等場景。
(a) 主要特性
(b) 部署環境
RocketMQ 可以運行在 Java 語言所支持的平臺之上。使用 RocketMQ 需要:
Java JDK安裝 git、MavenRocketMQ 安裝包(c) 優點
單機 支持 1 萬以上 持久化隊列;RocketMQ 的所有消息都是(d) 缺點
支持的 客戶端語言 不多,目前是 Java 及 C++,其中 C++ 還不成熟;RocketMQ 社區關注度及成熟度也不及前兩者;沒有 Web 管理界面,提供了一個 CLI (命令行界面) 管理工具帶來7.4. Kafka
Apache Kafka 是一個 分佈式消息發佈訂閱 系統。它最初由 LinkedIn 公司基於獨特的設計實現為一個 分佈式的日誌提交系統 (a distributed commit log),之後成為 Apache 項目的一部分。Kafka 性能高效、可擴展良好 並且 可持久化。它的 分區特性,可複製 和 可容錯 都是其不錯的特性。
(a) 主要特性
快速持久化:可以在 O(1) 的系統開銷下進行 消息持久化;高吞吐:在一臺普通的服務器上既可以達到 10W/s 的 吞吐速率;完全的分佈式系統:Broker、Producer 和 Consumer 都原生自動支持 分佈式,自動實現 負載均衡;支持 同步 和 異步 複製兩種 高可用機制;支持 數據批量發送 和 拉取;零拷貝技術(zero-copy):減少 IO 操作步驟,提高 系統吞吐量;數據遷移、擴容(b) 部署環境
使用 Kafka 需要:
Java JDKKafka 安裝包(c) 優點
客戶端語言豐富:支持 Java、.Net、PHP、Ruby、Python、Go 等多種語言;高性能:單機寫入 TPS 約在 100 萬條/秒,消息大小 10 個字節;提供 完全分佈式架構,並有 replica 機制,擁有較高的 可用性 和 可靠性,理論上支持 消息無限堆積;支持批量操作;消費者 採用 Pull 方式獲取消息。(d) 缺點
Kafka 單機超過 64 個 隊列/分區 時,Load 時會發生明顯的飆高現象。隊列 越多,負載 越高,發送消息 響應時間變長;使用 短輪詢方式,實時性 取決於 輪詢間隔時間;消費失敗 不支持重試;支持 消息順序,但是 一臺代理宕機 後,就會產生 消息亂序;社區更新較慢。7.5. 幾種消息隊列對比
這裡列舉了上述四種消息隊列的差異對比:
Kafka 在於 分佈式架構,RabbitMQ 基於 AMQP 協議 來實現,RocketMQ 的思路來源於 Kafka,改成了 主從結構,在 事務性 和 可靠性 方面做了優化。廣泛來說,
小結
本文介紹了消息隊列的特點,消息隊列的 傳遞服務模型,消息的 傳輸方式,消息的 推拉模式。然後介紹了 ActiveMQ,RabbitMQ,RocketMQ 和 Kafka 幾種常見的消息隊列,闡述了 各種消息隊列 的 主要特點 和 優缺點。通過本文,對於消息隊列及相關技術選型,相信你會有了更深入的理解和認識。更多細節和原理性的東西,還需在實踐中見真知!