歡迎光臨
每天分享高質量文章

訊息中間件選型分析 —— 從 Kafka 與 RabbitMQ 的對比來看全域性

點擊上方“芋道原始碼”,選擇“置頂公眾號”

技術文章第一時間送達!

原始碼精品專欄

 

來源:https://www.jianshu.com/p/8f7ebbcbeee5


  • 一、前言

  • 二、各類訊息佇列簡述

  • 三、選型要點概述

  • 四、訊息中間件選型誤區探討


一、前言

訊息佇列中間件(簡稱訊息中間件)是指利用高效可靠的訊息傳遞機制進行與平臺無關的資料交流,並基於資料通信來進行分佈式系統的集成。通過提供訊息傳遞和訊息排隊模型,它可以在分佈式環境下提供應用解耦、彈性伸縮、冗餘儲存、流量削峰、異步通信、資料同步等等功能,其作為分佈式系統架構中的一個重要組件,有著舉足輕重的地位。

目前開源的訊息中間件可謂是琳琅滿目,能讓大家耳熟能詳的就有很多,比如ActiveMQ、RabbitMQ、Kafka、RocketMQ、ZeroMQ等。不管選擇其中的哪一款,都會有用的不趁手的地方,畢竟不是為你量身定製的。有些大廠在長期的使用過程中積累了一定的經驗,其訊息佇列的使用場景也相對穩定固化,或者目前市面上的訊息中間件無法滿足自身需求,並且也具備足夠的精力和人力而選擇自研來為自己量身打造一款訊息中間件。但是絕大多數公司還是不會選擇重覆造輪子,那麼選擇一款合適自己的訊息中間件顯得尤為重要。就算是前者,那麼在自研出穩定且可靠的相關產品之前還是會經歷這樣一個選型過程。

在整體架構中引入訊息中間件,勢必要考慮很多因素,比如成本及收益問題,怎麼樣才能達到最優的性價比?雖然訊息中間件種類繁多,但是各自都有各自的側重點,選擇合適自己、揚長避短無疑是最好的方式。如果你對此感到無所適從,本文或許可以參考一二。


二、各類訊息佇列簡述

ActiveMQ是Apache出品的、採用Java語言編寫的完全基於JMS1.1規範的面向訊息的中間件,為應用程式提供高效的、可擴展的、穩定的和安全的企業級訊息通信。不過由於歷史原因包袱太重,目前市場份額沒有後面三種訊息中間件多,其最新架構被命名為Apollo,號稱下一代ActiveMQ,有興趣的同學可行瞭解。

RabbitMQ是採用Erlang語言實現的AMQP協議的訊息中間件,最初起源於金融系統,用於在分佈式系統中儲存轉發訊息。RabbitMQ發展到今天,被越來越多的人認可,這和它在可靠性、可用性、擴展性、功能豐富等方面的卓越表現是分不開的。

Kafka起初是由LinkedIn公司採用Scala語言開發的一個分佈式、多分割槽、多副本且基於zookeeper協調的分佈式訊息系統,現已捐獻給Apache基金會。它是一種高吞吐量的分佈式發佈訂閱訊息系統,以可水平擴展和高吞吐率而被廣泛使用。目前越來越多的開源分佈式處理系統如Cloudera、Apache Storm、Spark、Flink等都支持與Kafka集成。

RocketMQ是阿裡開源的訊息中間件,目前已經捐獻個Apache基金會,它是由Java語言開發的,具備高吞吐量、高可用性、適合大規模分佈式系統應用等特點,經歷過雙11的洗禮,實力不容小覷。

ZeroMQ號稱史上最快的訊息佇列,基於C語言開發。ZeroMQ是一個訊息處理佇列庫,可在多執行緒、多內核和主機之間彈性伸縮,雖然大多數時候我們習慣將其歸入訊息佇列家族之中,但是其和前面的幾款有著本質的區別,ZeroMQ本身就不是一個訊息佇列服務器,更像是一組底層網絡通訊庫,對原有的Socket API上加上一層封裝而已。

目前市面上的訊息中間件還有很多,比如騰訊系的PhxQueue、CMQ、CKafka,又比如基於Go語言的NSQ,有時人們也把類似Redis的產品也看做訊息中間件的一種,當然它們都很優秀,但是本文篇幅限制無法窮極所有,下麵會針對性的挑選RabbitMQ和Kafka兩款典型的訊息中間件來做分析,力求站在一個公平公正的立場來闡述訊息中間件選型中的各個要點。


三、選型要點概述

衡量一款訊息中間件是否符合需求需要從多個維度進行考察,首要的就是功能維度,這個直接決定了你能否最大程度上的實現開箱即用,進而縮短專案周期、降低成本等。如果一款訊息中間件的功能達不到想要的功能,那麼就需要進行二次開發,這樣會增加專案的技術難度、複雜度以及增大專案周期等。

1. 功能維度

功能維度又可以劃分個多個子維度,大致可以分為以下這些:

  • 優先級佇列

優先級佇列不同於先進先出佇列,優先級高的訊息具備優先被消費的特權,這樣可以為下游提供不同訊息級別的保證。不過這個優先級也是需要有一個前提的:如果消費者的消費速度大於生產者的速度,並且訊息中間件服務器(一般簡單的稱之為Broker)中沒有訊息堆積,那麼對於發送的訊息設置優先級也就沒有什麼實質性的意義了,因為生產者剛發送完一條訊息就被消費者消費了,那麼就相當於Broker中至多只有一條訊息,對於單條訊息來說優先級是沒有什麼意義的。

  • 延遲佇列

當你在網上購物的時候是否會遇到這樣的提示:“三十分鐘之內未付款,訂單自動取消”?這個是延遲佇列的一種典型應用場景。延遲佇列儲存的是對應的延遲訊息,所謂“延遲訊息”是指當訊息被髮送以後,並不想讓消費者立刻拿到訊息,而是等待特定時間後,消費者才能拿到這個訊息進行消費。延遲佇列一般分為兩種:基於訊息的延遲和基於佇列的延遲。基於訊息的延遲是指為每條訊息設置不同的延遲時間,那麼每當佇列中有新訊息進入的時候就會重新根據延遲時間排序,當然這也會對性能造成極大的影響。實際應用中大多採用基於佇列的延遲,設置不同延遲級別的佇列,比如5s、10s、30s、1min、5mins、10mins等,每個佇列中訊息的延遲時間都是相同的,這樣免去了延遲排序所要承受的性能之苦,通過一定的掃描策略(比如定時)即可投遞超時的訊息。

  • 死信佇列

由於某些原因訊息無法被正確的投遞,為了確保訊息不會被無故的丟棄,一般將其置於一個特殊角色的佇列,這個佇列一般稱之為死信佇列。與此對應的還有一個“回退佇列”的概念,試想如果消費者在消費時發生了異常,那麼就不會對這一次消費進行確認(Ack),進而發生回滾訊息的操作之後訊息始終會放在佇列的頂部,然後不斷被處理和回滾,導致佇列陷入死迴圈。為瞭解決這個問題,可以為每個佇列設置一個回退佇列,它和死信佇列都是為異常的處理提供的一種機制保障。實際情況下,回退佇列的角色可以由死信佇列和重試佇列來扮演。

  • 重試佇列

重試佇列其實可以看成是一種回退佇列,具體指消費端消費訊息失敗時,為防止訊息無故丟失而重新將訊息回滾到Broker中。與回退佇列不同的是重試佇列一般分成多個重試等級,每個重試等級一般也會設置重新投遞延時,重試次數越多投遞延時就越大。舉個例子:訊息第一次消費失敗入重試佇列Q1,Q1的重新投遞延遲為5s,在5s過後重新投遞該訊息;如果訊息再次消費失敗則入重試佇列Q2,Q2的重新投遞延遲為10s,在10s過後再次投遞該訊息。以此類推,重試越多次重新投遞的時間就越久,為此需要設置一個上限,超過投遞次數就入死信佇列。重試佇列與延遲佇列有相同的地方,都是需要設置延遲級別,它們彼此的區別是:延遲佇列動作由內部觸發,重試佇列動作由外部消費端觸發;延遲佇列作用一次,而重試佇列的作用範圍會向後傳遞。

  • 消費樣式

消費樣式分為推(push)樣式和拉(pull)樣式。推樣式是指由Broker主動推送訊息至消費端,實時性較好,不過需要一定的流制機制來確保服務端推送過來的訊息不會壓垮消費端。而拉樣式是指消費端主動向Broker端請求拉取(一般是定時或者定量)訊息,實時性較推樣式差,但是可以根據自身的處理能力而控制拉取的訊息量。

  • 廣播消費

訊息一般有兩種傳遞樣式:點對點(P2P,Point-to-Point)樣式和發佈/訂閱(Pub/Sub)樣式。對於點對點的樣式而言,訊息被消費以後,佇列中不會再儲存,所以訊息消費者不可能消費到已經被消費的訊息。雖然佇列可以支持多個消費者,但是一條訊息只會被一個消費者消費。發佈訂閱樣式定義瞭如何向一個內容節點發佈和訂閱訊息,這個內容節點稱為主題(topic),主題可以認為是訊息傳遞的中介,訊息發佈者將訊息發佈到某個主題,而訊息訂閱者則從主題中訂閱訊息。主題使得訊息的訂閱者與訊息的發佈者互相保持獨立,不需要進行接觸即可保證訊息的傳遞,發佈/訂閱樣式在訊息的一對多廣播時採用。RabbitMQ是一種典型的點對點樣式,而Kafka是一種典型的發佈訂閱樣式。但是RabbitMQ中可以通過設置交換器型別來實現發佈訂閱樣式而達到廣播消費的效果,Kafka中也能以點對點的形式消費,你完全可以把其消費組(consumer group)的概念看成是佇列的概念。不過對比來說,Kafka中因為有了訊息回溯功能的存在,對於廣播消費的力度支持比RabbitMQ的要強。

  • 訊息回溯

一般訊息在消費完成之後就被處理了,之後再也不能消費到該條訊息。訊息回溯正好相反,是指訊息在消費完成之後,還能消費到之前被消費掉的訊息。對於訊息而言,經常面臨的問題是“訊息丟失”,至於是真正由於訊息中間件的缺陷丟失還是由於使用方的誤用而丟失一般很難追查,如果訊息中間件本身具備訊息回溯功能的話,可以通過回溯消費復現“丟失的”訊息進而查出問題的源頭之所在。訊息回溯的作用遠不止與此,比如還有索引恢復、本地快取重建,有些業務補償方案也可以採用回溯的方式來實現。

  • 訊息堆積+持久化

流量削峰是訊息中間件的一個非常重要的功能,而這個功能其實得益於其訊息堆積能力。從某種意義上來講,如果一個訊息中間件不具備訊息堆積的能力,那麼就不能把它看做是一個合格的訊息中間件。訊息堆積分記憶體式堆積和磁盤式堆積。RabbitMQ是典型的記憶體式堆積,但這並非絕對,在某些條件觸發後會有換頁動作來將記憶體中的訊息換頁到磁盤(換頁動作會影響吞吐),或者直接使用惰性佇列來將訊息直接持久化至磁盤中。Kafka是一種典型的磁盤式堆積,所有的訊息都儲存在磁盤中。一般來說,磁盤的容量會比記憶體的容量要大得多,對於磁盤式的堆積其堆積能力就是整個磁盤的大小。從另外一個角度講,訊息堆積也為訊息中間件提供了冗餘儲存的功能。援引紐約時報的案例,其直接將Kafka用作儲存系統。

  • 訊息追蹤

對於分佈式架構系統中的鏈路追蹤(trace)而言,大家一定不會陌生。對於訊息中間件而言,訊息的鏈路追蹤(以下簡稱訊息追蹤)同樣重要。對於訊息追蹤最通俗的理解就是要知道訊息從哪來,存在哪裡以及發往哪裡去。基於此功能下,我們可以對發送或者消費完的訊息進行鏈路追蹤服務,進而可以進行問題的快速定位與排查。

  • 訊息過濾

訊息過濾是指按照既定的過濾規則為下游用戶提供指定類別的訊息。就以kafka而言,完全可以將不同類別的訊息發送至不同的topic中,由此可以實現某種意義的訊息過濾,或者Kafka還可以根據分割槽對同一個topic中的訊息進行分類。不過更加嚴格意義上的訊息過濾應該是對既定的訊息採取一定的方式按照一定的過濾規則進行過濾。同樣以Kafka為例,可以通過客戶端提供的ConsumerInterceptor接口或者Kafka Stream的filter功能進行訊息過濾。

  • 多租戶

也可以稱為多重租賃技術,是一種軟體架構技術,主要用來實現多用戶的環境下公用相同的系統或程式組件,並且仍可以確保各用戶間資料的隔離性。RabbitMQ就能夠支持多租戶技術,每一個租戶表示為一個vhost,其本質上是一個獨立的小型RabbitMQ服務器,又有自己獨立的佇列、交換器及系結關係等,並且它擁有自己獨立的權限。vhost就像是物理機中的虛擬機一樣,它們在各個實體間提供邏輯上的分離,為不同程式安全保密地允許資料,它既能將同一個RabbitMQ中的眾多客戶區分開,又可以避免佇列和交換器等命名衝突。

  • 多協議支持

訊息是信息的載體,為了讓生產者和消費者都能理解所承載的信息(生產者需要知道如何構造訊息,消費者需要知道如何解析訊息),它們就需要按照一種統一的格式描述訊息,這種統一的格式稱之為訊息協議。有效的訊息一定具有某種格式,而沒有格式的訊息是沒有意義的。一般訊息層面的協議有AMQP、MQTT、STOMP、XMPP等(訊息領域中的JMS更多的是一個規範而不是一個協議),支持的協議越多其應用範圍就會越廣,通用性越強,比如RabbitMQ能夠支持MQTT協議就讓其在物聯網應用中獲得一席之地。還有的訊息中間件是基於其本身的私有協議運轉的,典型的如Kafka。

  • 跨語言支持

對很多公司而言,其技術棧體系中會有多種編程語言,如C/C++、JAVA、Go、PHP等,訊息中間件本身具備應用解耦的特性,如果能夠進一步的支持多客戶端語言,那麼就可以將此特性的效能擴大。跨語言的支持力度也可以從側面反映出一個訊息中間件的流行程度。

  • 流量控制

流量控制(flow control)針對的是發送方和接收方速度不匹配的問題,提供一種速度匹配服務抑制發送速率使接收方應用程式的讀取速率與之相適應。通常的流控方法有Stop-and-wait、滑動視窗以及令牌桶等。

  • 訊息順序性

顧名思義,訊息順序性是指保證訊息有序。這個功能有個很常見的應用場景就是CDC(Change Data Chapture),以MySQL為例,如果其傳輸的binlog的順序出錯,比如原本是先對一條資料加1,然後再乘以2,發送錯序之後就變成了先乘以2後加1了,造成了資料不一致。

  • 安全機制

在Kafka 0.9版本之後就開始增加了身份認證和權限控制兩種安全機制。身份認證是指客戶端與服務端連接進行身份認證,包括客戶端與Broker之間、Broker與Broker之間、Broker與ZooKeeper之間的連接認證,目前支持SSL、SASL等認證機制。權限控制是指對客戶端的讀寫操作進行權限控制,包括對訊息或Kafka集群操作權限控制。權限控制是可插拔的,並支持與外部的授權服務進行集成。對於RabbitMQ而言,其同樣提供身份認證(TLS/SSL、SASL)和權限控制(讀寫操作)的安全機制。

  • 訊息冪等性

對於確保訊息在生產者和消費者之間進行傳輸而言一般有三種傳輸保障(delivery guarantee):At most once,至多一次,訊息可能丟失,但絕不會重覆傳輸;At least once,至少一次,訊息絕不會丟,但是可能會重覆;Exactly once,精確一次,每條訊息肯定會被傳輸一次且僅一次。對於大多數訊息中間件而言,一般只提供At most once和At least once兩種傳輸保障,對於第三種一般很難做到,由此訊息冪等性也很難保證。

Kafka自0.11版本開始引入了冪等性和事務,Kafka的冪等性是指單個生產者對於單分割槽單會話的冪等,而事務可以保證原子性地寫入到多個分割槽,即寫入到多個分割槽的訊息要麼全部成功,要麼全部回滾,這兩個功能加起來可以讓Kafka具備EOS(Exactly Once Semantic)的能力。

不過如果要考慮全域性的冪等,還需要與從上下游方面綜合考慮,即關聯業務層面,冪等處理本身也是業務層面所需要考慮的重要議題。以下游消費者層面為例,有可能消費者消費完一條訊息之後沒有來得及確認訊息就發生異常,等到恢復之後又得重新消費原來消費過的那條訊息,那麼這種型別的訊息冪等是無法有訊息中間件層面來保證的。如果要保證全域性的冪等,需要引入更多的外部資源來保證,比如以訂單號作為唯一性標識,並且在下游設置一個去重表。

  • 事務性訊息

事務本身是一個並不陌生的詞彙,事務是由事務開始(Begin Transaction)和事務結束(End Transaction)之間執行的全體操作組成。支持事務的訊息中間件並不在少數,Kafka和RabbitMQ都支持,不過此兩者的事務是指生產者發生訊息的事務,要麼發送成功,要麼發送失敗。訊息中間件可以作為用來實現分佈式事務的一種手段,但其本身並不提供全域性分佈式事務的功能。

下表是對Kafka與RabbitMQ功能的總結性對比及補充說明。

功能項 Kafka(1.1.0版本) RabbitMQ(3.6.10版本)
優先級佇列 不支持 支持。建議優先級大小設置在0-10之間。
延遲佇列 不支持 支持
死信佇列 不支持 支持
重試佇列 不支持 不支持。RabbitMQ中可以參考延遲佇列實現一個重試佇列,二次封裝比較簡單。如果要在Kafka中實現重試佇列,首先得實現延遲佇列的功能,相對比較複雜。
消費樣式 拉樣式 推樣式+拉樣式
廣播消費 支持。Kafka對於廣播消費的支持相對而言更加正統。 支持,但力度較Kafka弱。
訊息回溯 支持。Kafka支持按照offset和timestamp兩種維度進行訊息回溯。 不支持。RabbitMQ中訊息一旦被確認消費就會被標記刪除。
訊息堆積 支持 支持。一般情況下,記憶體堆積達到特定閾值時會影響其性能,但這不是絕對的。如果考慮到吞吐這因素,Kafka的堆積效率比RabbitMQ總體上要高很多。
持久化 支持 支持
訊息追蹤 不支持。訊息追蹤可以通過外部系統來支持,但是支持粒度沒有內置的細膩。 支持。RabbitMQ中可以採用Firehose或者rabbitmq_tracing插件實現。不過開啟rabbitmq_tracing插件件會大幅影響性能,不建議生產環境開啟,反倒是可以使用Firehose與外部鏈路系統結合提供高細膩度的訊息追蹤支持。
訊息過濾 客戶端級別的支持 不支持。但是二次封裝一下也非常簡單。
多租戶 不支持 支持
多協議支持 只支持定義協議,目前幾個主流版本間存在兼容性問題。 RabbitMQ本身就是AMQP協議的實現,同時支持MQTT、STOMP等協議。
跨語言支持 採用Scala和Java編寫,支持多種語言的客戶端。 採用Erlang編寫,支持多種語言的客戶端。
流量控制 支持client和user級別,通過主動設置可將流控作用於生產者或消費者。 RabbitMQ的流控基於Credit-Based演算法,是內部被動觸發的保護機制,作用於生產者層面。
訊息順序性 支持單分割槽(partition)級別的順序性。 順序性的條件比較苛刻,需要單執行緒發送、單執行緒消費並且不採用延遲佇列、優先級佇列等一些高級功能,從某種意義上來說不算支持順序性。
安全機制 (TLS/SSL、SASL)身份認證和(讀寫)權限控制 與Kafka相似
冪等性 支持單個生產者單分割槽單會話的冪等性。 不支持
事務性訊息 支持 支持

2. 性能

功能維度是訊息中間件選型中的一個重要的參考維度,但這並不是唯一的維度。有時候性能比功能還要重要,況且性能和功能很多時候是相悖的,魚和熊掌不可兼得,Kafka在開啟冪等、事務功能的時候會使其性能降低,RabbitMQ在開啟rabbitmq_tracing插件的時候也會極大的影響其性能。訊息中間件的性能一般是指其吞吐量,雖然從功能維度上來說,RabbitMQ的優勢要大於Kafka,但是Kafka的吞吐量要比RabbitMQ高出1至2個數量級,一般RabbitMQ的單機QPS在萬級別之內,而Kafka的單機QPS可以維持在十萬級別,甚至可以達到百萬級。

訊息中間件的吞吐量始終會受到硬體層面的限制。就以網卡帶寬為例,如果單機單網卡的帶寬為1Gbps,如果要達到百萬級的吞吐,那麼訊息體大小不得超過(1Gb/8)/100W,即約等於134B,換句話說如果訊息體大小超過134B,那麼就不可能達到百萬級別的吞吐。這種計算方式同樣可以適用於記憶體和磁盤。

時延作為性能維度的一個重要指標,卻往往在訊息中間件領域所被忽視,因為一般使用訊息中間件的場景對時效性的要求並不是很高,如果要求時效性完全可以採用RPC的方式實現。訊息中間件具備訊息堆積的能力,訊息堆積越大也就意味著端到端的時延也就越長,與此同時延時佇列也是某些訊息中間件的一大特色。那麼為什麼還要關註訊息中間件的時延問題呢?訊息中間件能夠解耦系統,對於一個時延較低的訊息中間件而言,它可以讓上游生產者發送訊息之後可以迅速的傳回,也可以讓消費者更加快速的獲取到訊息,在沒有堆積的情況下可以讓整體上下游的應用之間的級聯動作更加高效,雖然不建議在時效性很高的場景下使用訊息中間件,但是如果所使用的訊息中間件的時延方面比較優秀,那麼對於整體系統的性能將會是一個不小的提升。

3. 可靠性+可用性

訊息丟失是使用訊息中間件時所不得不面對的一個同點,其背後訊息可靠性也是衡量訊息中間件好壞的一個關鍵因素。尤其是在金融支付領域,訊息可靠性尤為重要。然而說到可靠性必然要說到可用性,註意這兩者之間的區別,訊息中間件的可靠性是指對訊息不丟失的保障程度;而訊息中間件的可用性是指無故障運行的時間百分比,通常用幾個9來衡量。

從狹義的角度來說,分佈式系統架構是一致性協議理論的應用實現,對於訊息可靠性和可用性而言也可以追溯到訊息中間件背後的一致性協議。對於Kafka而言,其採用的是類似PacificA的一致性協議,通過ISR(In-Sync-Replica)來保證多副本之間的同步,並且支持強一致性語意(通過acks實現)。對應的RabbitMQ是通過鏡像環形佇列實現多副本及強一致性語意的。多副本可以保證在master節點宕機異常之後可以提升slave作為新的master而繼續提供服務來保障可用性。Kafka設計之初是為日誌處理而生,給人們留下了資料可靠性要求不要的不良印象,但是隨著版本的升級優化,其可靠性得到極大的增強,詳細可以參考KIP101。就目前而言,在金融支付領域使用RabbitMQ居多,而在日誌處理、大資料等方面Kafka使用居多,隨著RabbitMQ性能的不斷提升和Kafka可靠性的進一步增強,相信彼此都能在以前不擅長的領域分得一杯羹。

同步刷盤是增強一個組件可靠性的有效方式,訊息中間件也不例外,Kafka和RabbitMQ都可以支持同步刷盤,但是筆者對同步刷盤有一定的疑問:絕大多數情景下,一個組件的可靠性不應該由同步刷盤這種極其損耗性能的操作來保障,而是採用多副本的機制來保證。

這裡還要提及的一個方面是擴展能力,這裡我狹隘地將此歸納到可用性這一維度,訊息中間件的擴展能力能夠增強其用可用能力及範圍,比如前面提到的RabbitMQ支持多種訊息協議,這個就是基於其插件化的擴展實現。還有從集群部署上來講,歸功於Kafka的水平擴展能力,其基本上可以達到線性容量提升的水平,在LinkedIn實踐介紹中就提及了有部署超過千台設備的Kafka集群。

5. 運維管理

在訊息中間件的使用過程中難免會出現各式各樣的異常情況,有客戶端的,也有服務端的,那麼怎樣及時有效的進行監測及修複。業務線流量有峰值又低谷,尤其是電商領域,那麼怎樣前進行有效的容量評估,尤其是大促期間?腳踢電源、網線被挖等事件層出不窮,如何有效的做好異地多活?這些都離不開訊息中間件的衍生產品——運維管理。

運維管理也可以進行進一步的細分,比如:申請、審核、監控、告警、管理、容災、部署等。

申請、審核很好理解,在源頭對資源進行管控,既可以進行有效校正應用方的使用規範,配和監控也可以做好流量統計與流量評估工作,一般申請、審核與公司內部系統交融性較大,不適合使用開源類的產品。

監控、告警也比較好理解,對訊息中間件的使用進行全方位的監控,即可以為系統提供基準資料,也可以在檢測到異常的情況配合告警,以便運維、開發人員的迅速介入。除了一般的監控項(比如硬體、GC等)之外,對於訊息中間件還需要關註端到端時延、訊息審計、訊息堆積等方面。對於RabbitMQ而言,最正統的監控管理工具莫過於rabbitmq_management插件了,但是社區內還有AppDynamics, Collectd, DataDog, Ganglia, Munin, Nagios, New Relic, Prometheus, Zenoss等多種優秀的產品。Kafka在此方面也毫不遜色,比如:Kafka Manager, Kafka Monitor, Kafka Offset Monitor, Burrow, Chaperone, Confluent Control Center等產品,尤其是Cruise還可以提供自動化運維的功能。

不管是擴容、降級、版本升級、集群節點部署、還是故障處理都離不開管理工具的應用,一個配套完備的管理工具集可以在遇到變更時做到事半功倍。故障可大可小,一般是一些應用異常,也可以是機器掉電、網絡異常、磁盤損壞等單機故障,這些故障單機房內的多副本足以應付。如果是機房故障就要涉及異地容災了,關鍵點在於如何有效的進行資料複製,對於Kafka而言,可以參考MirrorMarker、uReplicator等產品,而RabbitMQ可以參考Federation和Shovel。

6. 社區力度及生態發展

對於目前流行的編程語言而言,如Java、Python,如果你在使用過程中遇到了一些異常,基本上可以通過搜索引擎的幫助來得到解決,因為一個產品用的人越多,踩過的坑也就越多,對應的解決方案也就越多。對於訊息中間件也同樣適用,如果你選擇了一種“生僻”的訊息中間件,可能在某些方面運用的得心應手,但是版本更新緩慢、遇到棘手問題也難以得到社區的支持而越陷越深;相反如果你選擇了一種“流行”的訊息中間件,其更新力度大,不僅可以迅速的彌補之前的不足,而且也能順應技術的快速發展來變更一些新的功能,這樣可以讓你以“站在巨人的肩膀上”。在運維管理維度我們提及了Kafka和RabbitMQ都有一系列開源的監控管理產品,這些正是得益於其社區及生態的迅猛發展。


四、訊息中間件選型誤區探討

在進行訊息中間件選型之前可以先問自己一個問題:是否真的需要一個訊息中間件?在搞清楚這個問題之後,還可以繼續問自己一個問題:是否需要自己維護一套訊息中間件?很多初創型公司為了節省成本會選擇直接購買訊息中間件有關的雲服務,自己只需要關註收發訊息即可,其餘的都可以外包出去。

很多人面對訊息中間件時會有一種自研的衝動,你完全可以對Java中的ArrayBlockingQueue做一個簡單的封裝,你也可以基於檔案、資料庫、Redis等底層儲存封裝而形成一個訊息中間件。訊息中間件做為一個基礎組件並沒有想象中的那麼簡單,其背後還需要配套的管理運維整個生態的產品集。自研還有會交接問題,如果文件不齊全、運作不規範將會帶給新人噩夢般的體驗。是否真的有自研的必要?如果不是KPI的壓迫可以先考慮下這2個問題:1. 目前市面上的訊息中間件是否都真的無法滿足目前業務需求? 2. 團隊是否有足夠的能力、人力、財力、精力來支持自研?

很多人在做訊息中間件選型時會參考網絡上的很多對比類的文章,但是其專業性、嚴謹性、以及其政治立場問題都有待考證,需要帶著懷疑的態度去審視這些文章。比如有些文章會在沒有任何限定條件及場景的情況下直接定義某款訊息中間件最好,還有些文章沒有指明訊息中間件版本及測試環境就來做功能和性能對比分析,諸如此類的文章都可以唾棄之。

訊息中間件猶如小馬過河,選擇合適的才最重要,這需要貼合自身的業務需求,技術服務於業務,大體上可以根據上一節所提及的功能、性能等6個維度來一一進行篩選。更深層次的抉擇在於你能否掌握其魂,筆者鄙見:RabbitMQ在於routing,而Kafka在於streaming,瞭解其根本對於自己能夠對症下藥選擇到合適的訊息中間件尤為重要。

訊息中間件選型切忌一味的追求性能或者功能,性能可以優化,功能可以二次開發。如果要在功能和性能方面做一個抉擇的話,那麼首選性能,因為總體上來說性能優化的空間沒有功能擴展的空間大。然而對於長期發展而言,生態又比性能以及功能都要重要。

很多時候,對於可靠性方面也容易存在一個誤區:想要找到一個產品來保證訊息的絕對可靠,很不幸的是這世界上沒有絕對的東西,只能說儘量趨於完美。想要盡可能的保障訊息的可靠性也並非單單隻靠訊息中間件本身,還要依賴於上下游,需要從生產端、服務端和消費端這3個維度去努力保證,《RabbitMQ訊息可靠性分析》這篇文章就從這3個維度去分析了RabbitMQ的可靠性。

訊息中間件選型還有一個考量標準就是儘量貼合團隊自身的技術棧體系,雖然說沒有蹩腳的訊息中間件只有蹩腳的程式員,但是讓一個C棧的團隊去深挖PhxQueue總比去深挖Scala編寫的Kafka要容易的多。

訊息中間件大道至簡:一發一存一消費,沒有最好的訊息中間件,只有最合適的訊息中間件。



如果你對 Dubbo / Netty 等等原始碼與原理感興趣,歡迎加入我的知識星球一起交流。長按下方二維碼噢

目前在知識星球更新了《Dubbo 原始碼解析》目錄如下:

01. 除錯環境搭建
02. 專案結構一覽
03. 配置 Configuration
04. 核心流程一覽

05. 拓展機制 SPI

06. 執行緒池

07. 服務暴露 Export

08. 服務取用 Refer

09. 註冊中心 Registry

10. 動態編譯 Compile

11. 動態代理 Proxy

12. 服務呼叫 Invoke

13. 呼叫特性 

14. 過濾器 Filter

15. NIO 服務器

16. P2P 服務器

17. HTTP 服務器

18. 序列化 Serialization

19. 集群容錯 Cluster

20. 優雅停機

21. 日誌適配

22. 狀態檢查

23. 監控中心 Monitor

24. 管理中心 Admin

25. 運維命令 QOS

26. 鏈路追蹤 Tracing

… 一共 69+ 篇

目前在知識星球更新了《Netty 原始碼解析》目錄如下:

01. 除錯環境搭建
02. NIO 基礎
03. Netty 簡介
04. 啟動 Bootstrap

05. 事件輪詢 EventLoop

06. 通道管道 ChannelPipeline

07. 通道 Channel

08. 位元組緩衝區 ByteBuf

09. 通道處理器 ChannelHandler

10. 編解碼 Codec

11. 工具類 Util

… 一共 61+ 篇

目前在知識星球更新了《資料庫物體設計》目錄如下:


01. 商品模塊
02. 交易模塊
03. 營銷模塊
04. 公用模塊

… 一共 17+ 篇


目前在知識星球更新了《Spring 原始碼解析》目錄如下:


01. 除錯環境搭建
02. IoC Resource 定位
03. IoC BeanDefinition 載入

04. IoC BeanDefinition 註冊

05. IoC Bean 獲取

06. IoC Bean 生命周期

… 一共 35+ 篇

赞(0)

分享創造快樂