在高並行、高訊息吞吐的網際網路場景中,我們經常會使用訊息佇列(Message Queue)作為基礎設施,在伺服器端架構中擔當訊息中轉、訊息削峰、事務非同步處理 等職能。
對於那些不需要實時響應的的業務,我們都可以放在訊息佇列中進行傳輸。下面是使用者在進行系統註冊的時候場景,充分體現MQ的作用
可以看到使用者註冊的過程步驟1+步驟2,從請求到響應總共耗時 55 ms。訊息消費+簡訊傳送的時間比較長,從上面看花了5s多,一般讓訊息佇列服務去處理,使用者靜靜等待簡訊送達即可。
訊息佇列中介軟體(簡稱訊息中介軟體)是指利用高效可靠的訊息傳遞機制進行與平臺無關的資料交流,並基於資料通訊來進行分散式系統的整合。通過提供訊息傳遞和訊息排隊模型,它可以在分散式環境下提供應用解耦、
彈性伸縮、冗餘儲存、流量削峰、非同步通訊、資料同步等等功能,其作為分散式系統架構中的一個重要元件,有著舉足輕重的地位。
Broker:訊息伺服器,以服務的形式執行在server端,給各個業務系統提供核心訊息資料的中轉服務。
Producer:訊息生產者,業務的發起方,負責生產訊息傳輸給broker。
Consumer:訊息消費者,業務的處理方,負責從broker獲取訊息並進行業務邏輯處理
Topic:主題模組,釋出/訂閱模式下的訊息統一彙集地,不同生產者向topic傳送訊息,由MQ伺服器分發到不同的訂閱者,實現訊息的廣播
Queue:佇列,PTP模式下,特定生產者向特定queue傳送訊息,消費者訂閱特定的queue完成指定訊息的接收。
Message:訊息體,根據不同通訊協定定義的固定格式進行編碼的封包,來封裝業務資料,實現訊息的傳輸。
這邊以kafka為例子,這是典型的叢集模式,Kafka通過Zookeeper管理叢集設定,選舉leader,以及在Consumer Group發生變化時進行rebalance。Producer使用push模式將訊息釋出到broker,Consumer使用pull模式從broker訂閱並消費訊息。
PTP對等:使用queue作為通訊載體
訊息生產者生產訊息傳送到queue中,然後訊息消費者從queue中取出並且消費訊息。
不可重複消費,訊息被消費以後,queue中不再儲存,所以訊息消費者不可能消費到已經被消費的訊息。 Queue支援存在多個消費者,但是對一個訊息而言,只會有一個消費者可以消費。
Pub/Sub釋出訂閱(廣播):使用topic作為通訊載體
訊息生產者(釋出)將訊息釋出到topic中,同時有多個訊息消費者(訂閱)消費該訊息。和對等方式不同,釋出到topic的訊息會被所有訂閱者消費,所以從1到N個訂閱者都能得到這個訊息的拷貝。
系統解耦:互動系統之間沒有直接的呼叫關係,只是通過訊息傳輸,故系統侵入性不強,耦合度低。
削峰、提高系統響應時間:例如原來的一套邏輯,可將緊急重要(需要立刻響應)的業務放到該呼叫方法中,響應要求不高的使用訊息佇列,放到MQ佇列中,供消費者處理。
業務的有序性處理:先來先處理,比如一個系統處理某件事需要很長一段時間,但是在處理這件事情時候,有其他人也發出了請求,可以把請求放在訊息隊裡,一個一個來處理
為巨量資料處理架構提供服務:通過訊息作為整合,巨量資料的背景下,訊息佇列還與實時處理架構整合,為資料處理提供效能支援。
目前開源的訊息中間還是很豐富的,大家用的比較多的比如 ActiveMQ、RabbitMQ、Kafka、RocketMQ、ZeroMQ 等。
但是每個人的業務場景不一樣,受限於系統的規模,業務的取捨(如延遲容忍度,死信、重試的需求,可持久化需求),並不是每一款訊息中介軟體都能滿足你的需求。
除了個別大廠會進行自研(如 阿里的Rocket MQ、滴滴的DD MQ)之外,大部分同學還是要對選型有一些思考的。各自都有各自的側重點,選擇合適自己、揚長避短無疑是最好的方式。
下面基於受眾程度,對三款主流的MQ做介紹,通過各項指標上的對比,給出我們在實際應用場景中的建議。
RabbitMQ:
採用 Erlang 語言實現的 AMQP 協定的訊息中介軟體,起源於金融系統,廣泛應用在分散式系統中,承擔訊息轉發的職責。RabbitMQ 發展歷史比較久遠,影響範圍比較大,被很多開發者認可,在可靠性、可用性、可延伸性、功能性方面有著非凡表現。
RocketMQ:
阿里開源的訊息中介軟體,目前已經捐獻給 Apache 基金會,它是由 Java 語言開發的,具備高吞吐量、高可用性、適合大規模分散式系統應用等特點。並且在阿里的雙11、618等重要活動中經受住了考驗。
Kafka:
起初是由 LinkedIn 公司採用 Scala 語言開發的一個分散式、多分割區、多副本且基於 zookeeper 協調的分散式訊息系統,現已捐獻給 Apache 基金會。它是一種高吞吐量的分散式釋出訂閱訊息系統,以可水平擴充套件和高吞吐率而被廣泛使用。
目前越來越多的開源分散式處理系統如 Cloudera、Apache Storm、Spark、Flink 等都支援與 Kafka 整合。
特性
|
RabbitMQ
|
RocketMQ
|
kafka
|
開發語言
|
erlang
|
java
|
scala
|
支援協定
|
AMQP
|
自定義
|
基於TCP 自定義
|
訊息儲存能力
|
記憶體、磁碟。支援少量堆積。
|
磁碟。支援大量堆積。
|
記憶體、磁碟、資料庫。支援大量堆積。
|
訊息事務性
|
支援(通道設定事務模式,效能有影響)
|
支援
|
支援
|
單機吞吐量
|
萬級
|
10萬級+
|
10萬級+
|
時效性
|
us級
|
ms級
|
ms級以內
|
訊息重複
|
支援at least once、at most once |
支援at least once
|
支援at least once、at most once |
訊息回溯
|
不支援
|
支援指定時間點的回溯
|
支援指定分割區offset位置的回溯
|
訊息重試
|
不支援,但可以設定autoACK=false,未收到確認的會重入佇列
|
支援
|
不支援,但可以通過訊息回溯的方式來實現
|
可用性
|
高(主從架構)
|
非常高(分散式架構)
|
非常高(分散式架構)
|
功能特性說明
|
基於erlang開發,所以並行能力很強,效能極其好,延時很低;
管理介面較豐富
|
MQ功能比較完備,擴充套件性佳
|
只支援主要的MQ功能,像一些訊息查詢,訊息回溯等功能支援的不是很強,在巨量資料領域應用廣。
|
中小型系統建議選用RabbitMQ,資料量相對較小,選型應首選功能比較完備的,所以kafka排除。RocketMQ是阿里出品,如果阿里放棄維護,中小型公司一般很難投入人力進行RocketMQ的客製化化開發,因此不推薦。
功能項 | Kafka(1.1.0+) | RabbitMQ(3.6.10+) |
優先順序佇列 | 不支援 | 支援:具有優先被消費的特權,建議優先順序大小設定在10以內,否則價值不大 |
延遲佇列 | 不支援 | 支援 |
死信佇列 | 不支援 | 支援:儲存無法被正確投遞的訊息,避免訊息被無端丟棄。 |
重試模式 | 不支援 |
不支援:RabbitMQ中可以參考延遲佇列實現一個重試佇列,需要再封裝一下,也不是太難。 如果要在kafka中實現重試佇列,首先要實現延遲佇列的功能,相對比較複雜。 |
消費模式 | 拉 模式 | 推+拉 模式 |
廣播消費(pub/sub) | 支援:kafka對廣播消費的支援比較強大 | 支援:能力相比較kafka 弱一些 |
訊息回溯 | 支援:kafka可以按照 offset(偏移量)和 timestamp(時間戳) 兩種維度進行訊息回溯。 | 不支援:RabbitMQ訊息一旦被確認消費便丟棄 |
訊息堆積 | 支援 |
支援:記憶體堆積過大會影響效能,如果僅考慮吞吐量因素,kafka的堆積效率比RabbitMQ總體高很多。 |
持久化 | 支援 | 支援 |
訊息追蹤 | 不支援:訊息追蹤可以通過外部系統來支援,但是支援粒度肯定沒有內建的細膩 |
支援:RabbitMQ中可以採用Firehose 或者 rabbitmq_tracing外掛實現。
|
訊息過濾 | 使用者端級別的支援 | 不支援,可以客製化化封裝 |
多租戶 | 不支援 | 支援 |
多協定支援 | 只支援自定義協定,目前幾個主流版本中存在相容性問題。 | RabbitMQ本身就是AMQP協定的實現,同時支援MQTT、STOMP等協定 |
跨語言支援 | 採用Scala和Java編寫,支援多種語言的使用者端 | 採用Erlang編寫,支援多種語言的使用者端 |
流量控制 | 支援client和user級別,可將流控設定在生產者和消費者層面 | RabbitMQ的流控基於 Credit-Based 演演算法,是內部被動觸發的保護機制,僅用於生產者層面。 |
訊息順序性 | 支援單分割區(partition)級別的順序性,在各自的分割區中排序 |
順序性消費的條件比較苛刻,需要單執行緒傳送、單執行緒消費,這樣吞吐量就下來了。 而且無法使用延遲佇列、優先佇列等一些高階功能,所以一般不使用。 |
安全機制 |
(TLS/SSL、SASL)身份認證和(讀/寫)許可權控制 |
與kafka相似 |
冪等性 | 單個生產者+單partition + 單對談 場景下,支援冪等性 | 不支援 |
事務性訊息 | 支援 | 支援 |
功能維度是訊息中介軟體選型中的一個重要的參考維度,但效能也是考慮的一個重要環節。
吞吐量角度:Kafka 在開啟冪等、事務功能的時候會使其效能降低,RabbitMQ 在開啟 rabbitmq_tracing 外掛的時候也會極大的影響其效能。訊息中介軟體的效能一般是指其吞吐量,雖然從功能維度上來說,RabbitMQ 的優勢要大於 Kafka,但是 Kafka 的吞吐量要比 RabbitMQ 高出 1 至 2 個數量級,一般 RabbitMQ 的單機 QPS 在萬級別之內,而 Kafka 的單機 QPS 可以維持在十萬級別,甚至可以達到百萬級。
時延角度:另外一個是時延,作為效能維度的一個重要指標,卻往往在訊息中介軟體領域所被忽視,因為一般使用訊息中介軟體的場景對時效性的要求並不是很高,如果要求時效性完全可以採用 RPC 的方式實現。訊息中介軟體具備訊息堆積的能力。Kafka是ms以內,RabbitMQ是us級別的。
高可用角度是指系統的出錯概率和無故障執行時長。
如訊息丟失,是使用訊息中介軟體時所不得不面對的一個同點,其背後訊息可靠性也是衡量訊息中介軟體好壞的一個關鍵因素。尤其是在金融支付領域,訊息可靠性尤為重要。然而說到可靠性必然要說到可用性,注意這兩者之間的區別,訊息中介軟體的可靠性是指對訊息不丟失的保障程度;
而訊息中介軟體的可用性是指無故障執行的時間百分比,通常用幾個 9 來衡量,如 99.99% 就是一個不錯的指標。
對應的 RabbitMQ 是通過映象環形佇列實現多副本及強一致性語意的。多副本可以保證在 master 節點宕機異常之後可以提升 slave 作為新的 master 而繼續提供服務來保障可用性。
訊息中介軟體一個很重要的考慮層面是運維管理,比如:申請、稽核、監控、告警、管理、容災、部署等。
對訊息中介軟體的使用 從使用、接入規範、全方位的監控、流量統計和分析等方面,提供有效的基準資料,也可以在檢測到異常的情況配合告警,以便運維、開發人員的迅速介入。除了一般的監控項(比如硬體、GC 等)之外,對於訊息中介軟體還需要關注端到端時延、訊息審計、訊息堆積等方面。
對於 RabbitMQ 而言,最正統的監控管理工具莫過於 rabbitmq_management 外掛了,另外還有 AppDynamics, Collectd, DataDog, Ganglia 等多種優秀的產品。
Kafka 豐富的管理工具,比如:Kafka Manager, Kafka Monitor, Kafka Offset Monitor 等產品,其中 Cruise 還可以提供自動化運維的功能。
Kafka 和 RabbitMQ 都有一系列開源的監控管理產品,社群活躍,產品生態都很不錯。