天天看點

消息中間件選型分析消息中間件選型分析

消息中間件選型分析

——從Kafka與RabbitMQ的對比來看全局
           
有很多網友留言:公司要做消息中間件選型,該如何選?你覺得哪個比較好?消息選型的确是一個大論題,實則說來話長的事情又如何長話短說。對此筆者專門撰稿一篇内功心法:《 如何看待消息中間件的選型 》,不過這篇隻表其意未表其行,為了彌補這種缺陷,筆者最近特意重新撰稿一篇,以供參考。溫馨提示:本文一萬多字,建議先馬(關注)後看。

一、前言

消息隊列中間件(簡稱消息中間件)是指利用高效可靠的消息傳遞機制進行與平台無關的資料交流,并基于資料通信來進行分布式系統的內建。通過提供消息傳遞和消息排隊模型,它可以在分布式環境下提供應用解耦、彈性伸縮、備援存儲、流量削峰、異步通信、資料同步等等功能,其作為分布式系統架構中的一個重要元件,有着舉足輕重的地位。

目前開源的消息中間件可謂是琳琅滿目,能讓大家耳熟能詳的就有很多,比如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是一種典型的磁盤式堆積,所有的消息都存儲在磁盤中。一般來說,磁盤的容量會比記憶體的容量要大得多,對于磁盤式的堆積其堆積能力就是整個磁盤的大小。從另外一個角度講,消息堆積也為消息中間件提供了備援存儲的功能。援引紐約時報的案例(

https://www.confluent.io/blog/publishing-apache-kafka-new-york-times/

),其直接将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功能的總結性對比及補充說明。

消息中間件選型分析消息中間件選型分析

image.png

消息中間件選型分析消息中間件選型分析

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要容易的多。

五、總結

消息中間件大道至簡:一發一存一消費,沒有最好的消息中間件,隻有最合适的消息中間件。人過留名,雁過留聲,路過記得點個贊。

分布式之消息隊列複習精講

https://www.jianshu.com/p/8dd2b41872b6

Java程式性能優化

https://www.jianshu.com/p/0990a18cac14