淺談消息隊列及常見的消息中間件

前言

消息隊列 已經逐漸成爲企業應用系統 內部通訊 的核心手段。它具備 低耦合可靠投遞廣播流量控制最終一致性 等一系列功能。前端

當前使用較多的 消息隊列RabbitMQRocketMQActiveMQKafkaZeroMQMetaMQ 等,而部分 數據庫RedisMySQL 以及 phxsql 也可實現消息隊列的功能。git

正文

1. 消息隊列概述

消息隊列 是指利用 高效可靠消息傳遞機制 進行與平臺無關的 數據交流,並基於 數據通訊 來進行分佈式系統的集成。sql

經過提供 消息傳遞消息排隊 模型,它能夠在 分佈式環境 下提供 應用解耦彈性伸縮冗餘存儲流量削峯異步通訊數據同步 等等功能,其做爲 分佈式系統架構 中的一個重要組件,有着舉足輕重的地位。數據庫

2. 消息隊列的特色

2.1. 採用異步處理模式

消息發送者 能夠發送一個消息而無須等待響應。消息發送者 將消息發送到一條 虛擬的通道主題隊列)上,消息接收者訂閱 或是 監聽 該通道。一條信息可能最終轉發給 一個或多個 消息接收者,這些接收者都無需對 消息發送者 作出 同步迴應。整個過程都是 異步的編程

2.2. 應用系統之間解耦合

主要體如今以下兩點:後端

  1. 發送者和接受者沒必要了解對方、只須要 確認消息緩存

  2. 發送者和接受者 沒必要同時在線安全

好比在線交易系統爲了保證數據的 最終一致,在 支付系統 處理完成後會把 支付結果 放到 消息中間件 裏,通知 訂單系統 修改 訂單支付狀態。兩個系統是經過消息中間件解耦的。服務器

3. 消息隊列的傳遞服務模型

消息隊列的 傳遞服務模型 以下圖所示:多線程

4. 消息隊列的的傳輸模式

4.1. 點對點模型

點對點模型 用於 消息生產者消息消費者 之間 點到點 的通訊。消息生產者將消息發送到由某個名字標識的特定消費者。這個名字實際上對於消費服務中的一個 隊列Queue),在消息傳遞給消費者以前它被 存儲 在這個隊列中。隊列消息 能夠放在 內存 中也能夠 持久化,以保證在消息服務出現故障時仍然可以傳遞消息。

傳統的點對點消息中間件一般由 消息隊列服務消息傳遞服務消息隊列消息應用程序接口 API 組成,其典型的結構以下圖所示。

特色:

  1. 每一個消息只用一個消費者;
  2. 發送者和接受者沒有時間依賴;
  3. 接受者確認消息接受和處理成功。

示意圖以下所示:

4.2. 發佈/訂閱模型(Pub/Sub)

發佈者/訂閱者 模型支持向一個特定的 消息主題 生產消息。0多個訂閱者 可能對接收來自 特定消息主題 的消息感興趣。

在這種模型下,發佈者和訂閱者彼此不知道對方,就比如是匿名公告板。這種模式被概況爲:多個消費者能夠得到消息,在 發佈者訂閱者 之間存在 時間依賴性。發佈者須要創建一個 訂閱subscription),以便可以消費者訂閱。訂閱者 必須保持 持續的活動狀態接收消息

在這種狀況下,在訂閱者 未鏈接時,發佈的消息將在訂閱者 從新鏈接從新發布,以下圖所示:

特性:

  1. 每一個消息能夠有多個訂閱者;
  2. 客戶端只有訂閱後才能接收到消息;
  3. 持久訂閱和非持久訂閱。

注意:

  1. 發佈者和訂閱者有時間依賴:接受者和發佈者只有創建訂閱關係才能收到消息;
  2. 持久訂閱:訂閱關係創建後,消息就不會消失,無論訂閱者是否都在線;
  3. 非持久訂閱:訂閱者爲了接受消息,必須一直在線。 當只有一個訂閱者時約等於點對點模式

5. 消息隊列應用場景

當你須要使用 消息隊列 時,首先須要考慮它的必要性。可使用消息隊列的場景有不少,最經常使用的幾種,是作 應用程序鬆耦合異步處理模式發佈與訂閱最終一致性錯峯流控日誌緩衝 等。反之,若是須要 強一致性,關注業務邏輯的處理結果,則使用 RPC 顯得更爲合適。

5.1. 異步處理

非核心 流程 異步化,減小系統 響應時間,提升 吞吐量。例如:短信通知終端狀態推送App 推送用戶註冊 等。

消息隊列 通常都內置了 高效的通訊機制,所以也能夠用於單純的消息通信,好比實現 點對點消息隊列 或者 聊天室 等。

應用案例

網站用戶註冊,註冊成功後會過一會發送郵件確認或者短息。

5.2. 系統解耦

  • 系統之間不是 強耦合的消息接受者 能夠隨意增長,而不須要修改 消息發送者的代碼消息發送者 的成功不依賴 消息接受者(好比:有些銀行接口不穩定,但調用方並不須要依賴這些接口)。

  • 不強依賴 於非本系統的核心流程,對於 非核心流程,能夠放到消息隊列中讓 消息消費者 去按需消費,而 不影響核心主流程

5.3. 最終一致性

最終一致性 不是 消息隊列 的必備特性,但確實能夠依靠 消息隊列 來作 最終一致性 的事情。

  • 先寫消息再操做,確保操做完成後再修改消息狀態。定時任務補償機制 實現消息 可靠發送接收、業務操做的可靠執行,要注意 消息重複冪等設計

  • 全部不保證 100% 不丟消息 的消息隊列,理論上沒法實現 最終一致性

Kafka 一類的設計,在設計層面上就有 丟消息 的可能(好比 定時刷盤,若是掉電就會丟消息)。哪怕只丟千分之一的消息,業務也必須用其餘的手段來保證結果正確。

5.4. 廣播

生產者/消費者 模式,只須要關心消息是否 送達隊列,至於誰但願訂閱和須要消費,是 下游 的事情,無疑極大地減小了開發和聯調的工做量。

5.5. 流量削峯和流控

上下游系統 處理能力存在差距的時候,利用 消息隊列 作一個通用的 「漏斗」,進行 限流控制。在下游有能力處理的時候,再進行分發。

舉個例子:用戶在支付系統成功結帳後,訂單系統會經過短信系統向用戶推送扣費通知。 短信系統 可能因爲 短板效應,速度卡在 網關 上(每秒幾百次請求),跟 前端的併發量 不是一個數量級。 因而,就形成 支付系統短信系統 的處理能力出現差別化。

然而用戶晚上個半分鐘左右收到短信,通常是不會有太大問題的。若是沒有消息隊列,兩個系統之間經過 協商滑動窗口 等複雜的方案也不是說不能實現。但 系統複雜性 指數級增加,勢必在 上游 或者 下游存儲,而且要處理 定時擁塞 等一系列問題。並且每當有 處理能力有差距 的時候,都須要 單獨 開發一套邏輯來維護這套邏輯。

因此,利用中間系統轉儲兩個系統的通訊內容,並在下游系統有能力處理這些消息的時候,再處理這些消息,是一套相對較通用的方式。

應用案例

  1. 把消息隊列當成可靠的 消息暫存地,進行必定程度的 消息堆積
  2. 定時進行消息投遞,好比模擬 用戶秒殺 訪問,進行 系統性能壓測

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.1J2EE 1.4 規範的 JMS Provider 實現。它很是快速,支持 多種語言的客戶端協議,並且能夠很是容易的嵌入到企業的應用環境中,並有許多高級功能。

(a) 主要特性

  1. 服從JMS規範JMS 規範提供了良好的標準和保證,包括:同步異步 的消息分發,一次和僅一次的消息分發,消息接收訂閱 等等。聽從 JMS 規範的好處在於,不論使用什麼 JMS 實現提供者,這些基礎特性都是可用的;

  2. 鏈接靈活性ActiveMQ 提供了普遍的 鏈接協議,支持的協議有:HTTP/SIP 多播SSLTCPUDP 等等。對衆多協議的支持讓 ActiveMQ 擁有了很好的靈活性;

  3. 支持的協議種類多OpenWireSTOMPRESTXMPPAMQP

  4. 持久化插件和安全插件ActiveMQ 提供了 多種持久化 選擇。並且,ActiveMQ 的安全性也能夠徹底依據用戶需求進行 自定義鑑權受權

  5. 支持的客戶端語言種類多:除了 Java 以外,還有:C/C++.NETPerlPHPPythonRuby

  6. 代理集羣:多個 ActiveMQ 代理 能夠組成一個 集羣 來提供服務;

  7. 異常簡單的管理ActiveMQ 是以開發者思惟被設計的。因此,它並不須要專門的管理員,由於它提供了簡單又使用的管理特性。有不少中方法能夠 監控 ActiveMQ 不一樣層面的數據,包括使用在 JConsole 或者在 ActiveMQWeb Console 中使用 JMX。經過處理 JMX 的告警消息,經過使用 命令行腳本,甚至能夠經過監控各類類型的 日誌

(b) 部署環境

ActiveMQ 能夠運行在 Java 語言所支持的平臺之上。使用 ActiveMQ 須要:

  • Java JDK
  • ActiveMQ 安裝包

(c) 優勢

  1. 跨平臺 (JAVA 編寫與平臺無關,ActiveMQ 幾乎能夠運行在任何的 JVM 上);

  2. 能夠用 JDBC:能夠將 數據持久化 到數據庫。雖然使用 JDBC 會下降 ActiveMQ 的性能,可是數據庫一直都是開發人員最熟悉的存儲介質;

  3. 支持 JMS 規範:支持 JMS 規範提供的 統一接口;

  4. 支持 自動重連錯誤重試機制

  5. 有安全機制:支持基於 shirojaas 等多種 安全配置機制,能夠對 Queue/Topic 進行 認證和受權

  6. 監控完善:擁有完善的 監控,包括 Web ConsoleJMXShell 命令行,JolokiaRESTful API

  7. 界面友善:提供的 Web Console 能夠知足大部分狀況,還有不少 第三方的組件 可使用,好比 hawtio

(d) 缺點

  1. 社區活躍度不及 RabbitMQ 高;

  2. 根據其餘用戶反饋,會出莫名其妙的問題,會 丟失消息

  3. 目前重心放到 activemq 6.0 產品 Apollo,對 5.x 的維護較少;

  4. 不適合用於 上千個隊列 的應用場景;

7.2. RabbitMQ

RabbitMQ2007 年發佈,是一個在 AMQP (高級消息隊列協議)基礎上完成的,可複用的企業消息系統,是當前最主流的消息中間件之一。

(a) 主要特性

  1. 可靠性:提供了多種技術可讓你在 性能可靠性 之間進行 權衡。這些技術包括 持久性機制投遞確認發佈者證明高可用性機制

  2. 靈活的路由:消息在到達隊列前是經過 交換機 進行 路由 的。RabbitMQ 爲典型的路由邏輯提供了 多種內置交換機 類型。若是你有更復雜的路由需求,能夠將這些交換機組合起來使用,你甚至能夠實現本身的交換機類型,而且當作 RabbitMQ插件 來使用;

  3. 消息集羣:在相同局域網中的多個 RabbitMQ 服務器能夠 聚合 在一塊兒,做爲一個獨立的邏輯代理來使用;

  4. 隊列高可用:隊列能夠在集羣中的機器上 進行鏡像,以確保在硬件問題下還保證 消息安全

  5. 支持多種協議:支持 多種消息隊列協議

  6. 支持多種語言:用 Erlang 語言編寫,支持只要是你能想到的 全部編程語言

  7. 管理界面RabbitMQ 有一個易用的 用戶界面,使得用戶能夠 監控管理 消息 Broker 的許多方面;

  8. 跟蹤機制:若是 消息異常RabbitMQ 提供消息跟蹤機制,使用者能夠找出發生了什麼;

  9. 插件機制:提供了許多 插件,來從多方面進行擴展,也能夠編寫本身的插件。

(b) 部署環境

RabbitMQ 能夠運行在 Erlang 語言所支持的平臺之上,包括 SolarisBSDLinuxMacOSXTRU64Windows 等。使用 RabbitMQ 須要:

  • ErLang 語言包
  • RabbitMQ 安裝包

(c) 優勢

  1. 因爲 Erlang 語言的特性,消息隊列性能較好,支持 高併發

  2. 健壯、穩定、易用、跨平臺、支持 多種語言、文檔齊全;

  3. 有消息 確認機制持久化機制,可靠性高;

  4. 高度可定製的 路由

  5. 管理界面 較豐富,在互聯網公司也有較大規模的應用,社區活躍度高。

(d) 缺點

  1. 儘管結合 Erlang 語言自己的併發優點,性能較好,可是不利於作 二次開發和維護

  2. 實現了 代理架構,意味着消息在發送到客戶端以前能夠在 中央節點 上排隊。此特性使得 RabbitMQ 易於使用和部署,可是使得其 運行速度較慢,由於中央節點 增長了延遲消息封裝後 也比較大;

  3. 須要學習 比較複雜接口和協議,學習和維護成本較高。

7.3. RocketMQ

RocketMQ 出自 阿里 的開源產品,用 Java 語言實現,在設計時參考了 Kafka,並作出了本身的一些改進,消息可靠性上Kafka 更好。RocketMQ 在阿里內部被普遍應用在 訂單交易充值流計算消息推送日誌流式處理binglog 分發 等場景。

(a) 主要特性

  1. 基於 隊列模型:具備 高性能高可靠高實時分佈式 等特色;

  2. ProducerConsumer隊列 都支持 分佈式

  3. Producer 向一些隊列輪流發送消息,隊列集合 稱爲 TopicConsumer 若是作 廣播消費,則一個 Consumer 實例消費這個 Topic 對應的 全部隊列;若是作 集羣消費,則 多個 Consumer 實例 平均消費 這個 Topic 對應的隊列集合;

  4. 可以保證 嚴格的消息順序

  5. 提供豐富的 消息拉取模式

  6. 高效的訂閱者 水平擴展能力;

  7. 實時消息訂閱機制

  8. 億級 消息堆積 能力;

  9. 較少的外部依賴。

(b) 部署環境

RocketMQ 能夠運行在 Java 語言所支持的平臺之上。使用 RocketMQ 須要:

  • Java JDK
  • 安裝 gitMaven
  • RocketMQ 安裝包

(c) 優勢

  1. 單機 支持 1 萬以上 持久化隊列

  2. RocketMQ 的全部消息都是 持久化的,先寫入系統 PAGECACHE,而後 刷盤,能夠保證 內存磁盤 都有一份數據,而 訪問 時,直接 從內存讀取

  3. 模型簡單,接口易用(JMS 的接口不少場合並不太實用);

  4. 性能很是好,能夠容許 大量堆積消息Broker 中;

  5. 支持 多種消費模式,包括 集羣消費廣播消費等;

  6. 各個環節 分佈式擴展設計,支持 主從高可用

  7. 開發度較活躍,版本更新很快。

(d) 缺點

  1. 支持的 客戶端語言 很少,目前是 JavaC++,其中 C++ 還不成熟;

  2. RocketMQ 社區關注度及成熟度也不及前二者;

  3. 沒有 Web 管理界面,提供了一個 CLI (命令行界面) 管理工具帶來 查詢管理診斷各類問題

  4. 沒有在 MQ 核內心實現 JMS 等接口;

7.4. Kafka

Apache Kafka 是一個 分佈式消息發佈訂閱 系統。它最初由 LinkedIn 公司基於獨特的設計實現爲一個 分佈式的日誌提交系統 (a distributed commit log),以後成爲 Apache 項目的一部分。Kafka 性能高效可擴展良好 而且 可持久化。它的 分區特性可複製可容錯 都是其不錯的特性。

(a) 主要特性

  1. 快速持久化:能夠在 O(1) 的系統開銷下進行 消息持久化

  2. 高吞吐:在一臺普通的服務器上既能夠達到 10W/s吞吐速率

  3. 徹底的分佈式系統BrokerProducerConsumer 都原生自動支持 分佈式,自動實現 負載均衡

  4. 支持 同步異步 複製兩種 高可用機制

  5. 支持 數據批量發送拉取

  6. 零拷貝技術(zero-copy):減小 IO 操做步驟,提升 系統吞吐量

  7. 數據遷移擴容 對用戶透明;

  8. 無需停機 便可擴展機器;

  9. 其餘特性:豐富的 消息拉取模型、高效 訂閱者水平擴展、實時的 消息訂閱、億級的 消息堆積能力、按期刪除機制;

(b) 部署環境

使用 Kafka 須要:

  • Java JDK
  • Kafka 安裝包

(c) 優勢

  1. 客戶端語言豐富:支持 Java.NetPHPRubyPythonGo 等多種語言;

  2. 高性能:單機寫入 TPS 約在 100 萬條/秒,消息大小 10 個字節;

  3. 提供 徹底分佈式架構,並有 replica 機制,擁有較高的 可用性可靠性,理論上支持 消息無限堆積

  4. 支持批量操做;

  5. 消費者 採用 Pull 方式獲取消息。消息有序經過控制 可以保證全部消息被消費且僅被消費 一次

  6. 有優秀的第三方 Kafka Web 管理界面 Kafka-Manager

  7. 日誌領域 比較成熟,被多家公司和多個開源項目使用。

(d) 缺點

  1. Kafka 單機超過 64隊列/分區 時,Load 時會發生明顯的飆高現象。隊列 越多,負載 越高,發送消息 響應時間變長

  2. 使用 短輪詢方式實時性 取決於 輪詢間隔時間

  3. 消費失敗 不支持重試

  4. 支持 消息順序,可是 一臺代理宕機 後,就會產生 消息亂序

  5. 社區更新較慢。

7.5. 幾種消息隊列對比

這裏列舉了上述四種消息隊列的差別對比:

Kafka 在於 分佈式架構RabbitMQ 基於 AMQP 協議 來實現,RocketMQ 的思路來源於 Kafka,改爲了 主從結構,在 事務性可靠性 方面作了優化。普遍來講,電商金融 等對 事務一致性 要求很高的,能夠考慮 RabbitMQRocketMQ,對 性能要求高 的可考慮 Kafka

小結

本文介紹了消息隊列的特色,消息隊列的 傳遞服務模型,消息的 傳輸方式,消息的 推拉模式。而後介紹了 ActiveMQRabbitMQRocketMQKafka 幾種常見的消息隊列,闡述了 各類消息隊列主要特色優缺點。經過本文,對於消息隊列及相關技術選型,相信你會有了更深刻的理解和認識。更多細節和原理性的東西,還需在實踐中見真知!


歡迎關注技術公衆號: 零壹技術棧

零壹技術棧

本賬號將持續分享後端技術乾貨,包括虛擬機基礎,多線程編程,高性能框架,異步、緩存和消息中間件,分佈式和微服務,架構學習和進階等學習資料和文章。

相關文章
相關標籤/搜索