訊息中介軟體部署及比較:rabbitMQ、activeMQ、zeroMQ、rocketMQ、Kafka、redis

ohcomeyes發表於2019-03-03

一發一存一消費,沒有最好的訊息佇列中介軟體(簡稱訊息中介軟體),只有最合適的訊息中介軟體。
訊息佇列常用的使用場景:

  • 非實時性:當不需要立即獲得結果,但是併發量又需要進行控制的時候,差不多就是需要使用訊息佇列的時候。主要解決了應用耦合、非同步處理、流量削鋒等問題。
  • 應用耦合:多應用間通過訊息佇列對同一訊息進行處理,避免呼叫介面失敗導致整個過程失敗;(如:訂單->庫存)
  • 非同步處理:多應用對訊息佇列中同一訊息進行處理,應用間併發處理訊息,相比序列處理,減少處理時間;(點對多場景,廣播場景(註冊發簡訊,發郵件)等等)
  • 限流削峰:應用於秒殺或搶購活動中,避免流量過大導致應用系統掛掉的情況;(根據服務承受度設定佇列大小,超過了就返回活動結束了,我們們經常各大商城秒殺,心裡還沒有點B數嗎)減少壓力,避免服務掛掉。
  • 訊息驅動的系統:系統分為訊息佇列、訊息生產者、訊息消費者,生產者負責產生訊息,消費者(可能有多個)負責對訊息進行處理;(分工處理(各自對應相應的佇列),靈活應用(收到就處理/定時處理))

訊息佇列是非同步RPC的主要手段之一

兩種模式:

  1. 點對點:每個訊息只有一個消費者(Consumer),不可重複消費(一旦被消費,訊息就不再在訊息佇列中)
  2. 釋出/訂閱:微信公眾號(Topic),大夥(訂閱者)訂閱關注之後,微信公眾號運營平臺(釋出者)釋出資訊後,大夥微信就都收到資訊了,這裡其實還分pull/push的。一個是主動推送,一個是被動拉取
    基於釋出/訂閱模式做擴充套件就是橫向擴充套件,多個佇列及消費分組訂閱(提高消費能力)
  • pull:主動權在於消費方,優點是按需消費(吃自助餐,能吃多少拿多少),而且服務端佇列堆積的訊息處理也相對簡單(不用記錄狀態啊,狀態都消費端);缺點就是訊息延遲(不知道啥時候去拉取更新),這時候有小夥伴會問,那為啥不叫服務端通知一下呢(有句話叫不在其位不謀其政,服務端通知必然要記錄通知狀態和增加之間的通訊頻寬;當然也可以根據實際情況來選擇和push組合起來用(男女搭配幹活不累嘛)來提高訊息的實時性)
  • push:主動權就在服務方了,優點是實時性高,服務端可以統一管理來進行負載,不過也容易導致慢消費(就得考慮消費方受不受得了,畢竟你說你瞭解,但也只有對方才清楚你有多瞭解);缺點就是傳送訊息的狀態是集中式管理,壓力大啊(要分發訊息還要記錄狀態還要做備份,又當爹來又當媽,你說累不累)
    對於順序訊息,這種場景有限且成本太高的方式就得慎重考慮了,對那種全域性有序但允許出現小誤差的場景(日誌推送),pull模式就非常適合了(所以說kafka為啥常用於日誌處理、大資料等方面),要問為什麼?自己去領悟

實際開發中訊息中介軟體選型基於幾個方面:

  1. 功能:這個就多了,優先順序佇列、延遲佇列(劃分不同的延遲佇列來避免重新排序消耗效能,缺點嘛自己悟)、死信佇列(放沒有推送成功的)、消費模式(pull/push)、廣播消費、訊息回溯(可追溯嘛,不然被賣了都不知道是誰)、訊息堆積+持久化、訊息追蹤(鏈路條,方便定位)、訊息過濾(根據規則過濾啊,不同類別訊息傳送到不同topic)、多協議支援(通用性)、跨語言支援(流行程度)、流量控制(嘿嘿嘿,上面有)、訊息順序性(還要再說一遍?)、安全機制(身份認證,許可權認證(讀寫))、訊息冪等性(承諾知道不,答應人家的事就一定要做到)、事務性訊息(不想說)等
  2. 效能:一般是指其吞吐量(統一大小的訊息體和不同大小的訊息體生產和消耗能力),效能和功能很多時候是相悖的,魚和熊掌不可兼得。
  3. 高可靠、高可用:先說可靠,主要在於訊息的持久化這一塊(訊息只要寫入就一定會被消費,不會因為故障導致資料丟失(這個就很好測試出來了吧))。如果是從系統的角度來看就得從整體的維度去衡量了(不能單單隻靠訊息中介軟體本身,要從生產端、服務端、消費端三個維度去保障)。
    再說可用,主要在於一個是對外部服務的依賴性(像kafka依賴zookeeper),依賴也分強依賴和弱依賴,一個在於本身的備份機制所帶來的保障性(像主從複製這種備份啊,增加多個slave來加強保障同時也會存在資源浪費,大部分時候Slave可能是空閒的)。
  4. 運維:通常有稽核評估啊、監控啊、報警提醒啊、容災啊、擴容啊、升級部署等等,一方面看中介軟體支撐的維度,一方面就看結合自動化運維的難易度
  5. 社群力度及生態發展:這個好理解吧,使用開源框架最開始基本上愉快的奔跑,但時不時的總會掉坑裡,能不能爬出來一方面看自身的實力,一方面就看社群的力度了
  6. 成本 儘量貼合團隊自身的技術棧體系,讓一個C棧的團隊去深挖zeroMQ總比scala編寫kafka要容易的多

先貼一個圖(網上Q來的),一些功能支不支援主要取決於它使用的模式,看完上面詳細說明應該就比較清楚

訊息中介軟體

先從比較有代表性的兩個MQ(rabbitMQ,kafka),功能對比(圖還是Q來的)

中介軟體功能比較1
中介軟體功能比較2
中介軟體功能比較3

應用方面:

  • RabbitMQ,遵循AMQP協議,由內在高併發的erlanng語言開發,用在實時的對可靠性要求比較高的訊息傳遞上。
  • kafka它主要用於處理活躍的流式資料,大資料量的資料處理上。

架構模型方面:

  • RabbitMQ遵循AMQP協議,RabbitMQ的broker由Exchange,Binding,queue組成,其中exchange和binding組成了訊息的路由鍵;客戶端Producer通過連線channel和server進行通訊,Consumer從queue獲取訊息進行消費(長連線,queue有訊息會推送到consumer端,consumer迴圈從輸入流讀取資料)。rabbitMQ以broker為中心;有訊息的確認機制。
  • kafka遵從一般的MQ結構,producer,broker,consumer,以consumer為中心,訊息的消費資訊儲存的客戶端consumer上,consumer根據消費的點,從broker上批量pull資料;無訊息確認機制。

吞吐量:

  • rabbitMQ在吞吐量方面稍遜於kafka,他們的出發點不一樣,rabbitMQ支援對訊息的可靠的傳遞,支援事務,不支援批量的操作;基於儲存的可靠性的要求儲存可以採用記憶體或者硬碟。
  • kafka具有高的吞吐量,內部採用訊息的批量處理,zero-copy機制,資料的儲存和獲取是本地磁碟順序批量操作,具有O(1)的複雜度,訊息處理的效率很高。

可用性方面:

  • rabbitMQ支援miror(映象)的queue,主queue失效,miror queue接管。
  • kafka的broker支援主備模式。

叢集負載均衡方面:

  • rabbitMQ的負載均衡需要單獨的loadbalancer進行支援。
  • kafka採用zookeeper對叢集中的broker、consumer進行管理,可以註冊topic到zookeeper上;通過zookeeper的協調機制,producer儲存對應topic的broker資訊,可以隨機或者輪詢傳送到broker上;並且producer可以基於語義指定分片,訊息傳送到broker的某分片上。

rabbitMQ

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

  • 由於erlang語言的特性,mq效能較好,高併發;
  • 健壯、穩定、易用、跨平臺、支援多種語言、文件齊全;
  • 有訊息確認機制和持久化機制,可靠性高;
  • 高度可定製的路由;
  • 管理介面較豐富,在網際網路公司也有較大規模的應用;
  • 社群活躍度高;

缺點:

  • 儘管結合erlang語言本身的併發優勢,效能較好,但是不利於做二次開發和維護;
  • 實現了代理架構,意味著訊息在傳送到客戶端之前可以在中央節點上排隊。此特性使得RabbitMQ易於使用和部署,但是使得其執行速度較慢,因為中央節點增加了延遲,訊息封裝後也比較大;
  • 需要學習比較複雜的介面和協議,學習和維護成本較高;

activeMQ

基於java開發
是Apache出品的、採用Java語言編寫的完全基於JMS1.1規範的面向訊息的中介軟體,為應用程式提供高效的、可擴充套件的、穩定的和安全的企業級訊息通訊。不過由於歷史原因包袱太重,目前市場份額沒有後面三種訊息中介軟體多,其最新架構被命名為Apollo,(京東的訊息中介軟體就是基於activeMQ開發的)
優點:

  • 跨平臺(JAVA編寫與平臺無關有,ActiveMQ幾乎可以執行在任何的JVM上)
  • 可以用JDBC:可以將資料持久化到資料庫
  • 支援JMS :支援JMS的統一介面;
  • 支援自動重連;
  • 有安全機制:支援基於shiro,jaas等多種安全配置機制,可以對Queue/Topic進行認證和授權
  • 監控完善:擁有完善的監控,包括Web Console,JMX,Shell命令列,Jolokia的REST API;
  • 介面友善:提供的Web Console可以滿足大部分情況,還有很多第三方的元件可以使用,如hawtio;

缺點:

  • 社群活躍度不及RabbitMQ高;
  • 會出莫名其妙的問題,會丟失訊息;
  • 不適合用於上千個佇列的應用場景;

zeroMQ

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

  • 號稱最快的訊息佇列系統,尤其針對大吞吐量的需求場景
  • 單獨部署或整合到應用中使用,不需要安裝和執行一個訊息伺服器或中介軟體,因為你的應用程式將扮演了這個服務角色
  • 能夠實現高階/複雜的佇列,但是開發人員需要自己組合多種技術框架
  • 跨平臺,多語言支援
  • 可作為Socket通訊庫使用

缺點:

  • 僅提供非永續性的佇列,也就是說如果down機,資料將會丟失

rocketMQ

基於java開發(阿里訊息中介軟體)
是阿里開源的訊息中介軟體,目前已經捐獻個Apache基金會,它是由Java語言開發的,具備高吞吐量、高可用性、適合大規模分散式系統應用等特點,經歷過雙11的洗禮,實力不容小覷。
優點:

  • 單機支援 1 萬以上持久化佇列
  • RocketMQ 的所有訊息都是持久化的,先寫入系統 pagecache(頁高速緩衝儲存器),然後刷盤,可以保證記憶體與磁碟都有一份資料,訪問時,直接從記憶體讀取。
  • 模型簡單,介面易用(JMS 的介面很多場合並不太實用)
  • 效能非常好,可以大量堆積訊息在broker(叢集中包含一個或多個伺服器,這些伺服器被稱為broker)中;
  • 支援多種消費,包括叢集消費、廣播消費等。
  • 各個環節分散式擴充套件設計,主從HA(高可用性叢集);
  • 開發度較活躍,版本更新很快。

缺點:

  • 支援的客戶端語言不多,目前是java及c++,其中c++不成熟;
  • RocketMQ社群關注度及成熟度也不及前兩者;
  • 沒有web管理介面,提供了一個CLI(命令列介面)管理工具帶來查詢、管理和診斷各種問題;
  • 沒有在 mq 核心中去實現JMS等介面;

kafka

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

  • 客戶端語言豐富,支援java、.net、php、ruby、python、go等多種語言;
  • 效能卓越,單機寫入TPS約在百萬條/秒,訊息大小10個位元組;
  • 提供完全分散式架構, 並有replica機制, 擁有較高的可用性和可靠性, 理論上支援訊息無限堆積;
  • 支援批量操作;
  • 消費者採用Pull方式獲取訊息, 訊息有序, 通過控制能夠保證所有訊息被消費且僅被消費一次;
  • 有優秀的第三方Kafka Web管理介面Kafka-Manager;
  • 在日誌領域比較成熟,被多家公司和多個開源專案使用;

缺點:

  • Kafka單機超過64個佇列/分割槽,Load會發生明顯的飆高現象,佇列越多,load越高,傳送訊息響應時間變長
  • 使用短輪詢方式,實時性取決於輪詢間隔時間;
  • 消費失敗不支援重試;
  • 支援訊息順序,但是一臺代理當機後,就會產生訊息亂序;
  • 社群更新較慢;

redis

Redis的PUB/SUB機制,即釋出-訂閱模式。利用的Redis的列表(lists)資料結構。比較好的使用模式是,生產者lpush訊息,消費者brpop訊息,並設定超時時間,可以減少redis的壓力。只有在Redis當機且資料沒有持久化的情況下丟失資料,可以根據業務通過AOF和縮短持久化間隔來保證很高的可靠性,而且也可以通過多個client來提高消費速度。但相對於專業的訊息佇列來說,該方案訊息的狀態過於簡單(沒有狀態),且沒有ack機制,訊息取出後消費失敗依賴於client記錄日誌或者重新push到佇列裡面。

redis不支援分組(這點很重要,在做負載均衡的時候劣勢就體現出來),不過可以完全當做一個輕量級的佇列使用,但redis他爹做了disque,可以去試一試。

部署安裝

rabbitMQ

幾個重要概念:

  • Broker:簡單來說就是訊息佇列伺服器實體。
  • Exchange:訊息交換機,它指定訊息按什麼規則,路由到哪個佇列。
  • Queue:訊息佇列載體,每個訊息都會被投入到一個或多個佇列。
  • Binding:繫結,它的作用就是把exchange和queue按照路由規則繫結起來。
  • Routing Key:路由關鍵字,exchange根據這個關鍵字進行訊息投遞。
  • vhost:虛擬主機,一個broker裡可以開設多個vhost,用作不同使用者的許可權分離。
  • producer:訊息生產者,就是投遞訊息的程式。
  • consumer:訊息消費者,就是接受訊息的程式。
  • channel:訊息通道,在客戶端的每個連線裡,可建立多個channel,每個channel代表一個會話任務。

使用過程:

  1. 客戶端連線到訊息佇列伺服器,開啟一個channel。
  2. 客戶端宣告一個exchange,並設定相關屬性。
  3. 客戶端宣告一個queue,並設定相關屬性。
  4. 客戶端使用routing key,在exchange和queue之間建立好繫結關係。
  5. 客戶端投遞訊息到exchange。
  6. exchange接收到訊息後,就根據訊息的key和已經設定的binding,進行訊息路由,將訊息投遞到一個或多個佇列裡。

單機
RabbitMQ 安裝需要依賴 Erlang 環境
所以先安裝erlang,再安裝rabbitMQ,中間肯定會遇到很多問題,不同的環境問題不一樣,大多數是依賴包的問題,自行補齊就行了。

rabbitmq預設建立的使用者guest,密碼也是guest,這個使用者預設只能是本機訪問,從外部訪問需要新增上面的配置。建議刪除guest使用者

配置外部訪問

# rabbitmq.config檔案預設是沒有的,這裡是直接新建
vi rabbitmq.config
# 新增下面內容
[{rabbit, [{loopback_users, []}]}].
複製程式碼

刪除guest使用者

rabbitmqctl  delete_user guest
複製程式碼

新增使用者

rabbitmqctl add_user <username> <newpassword>
複製程式碼

給新增使用者賦予超級管理員許可權

rabbitmqctl set_user_tags <username> administrator
複製程式碼

啟動服務(建議後臺模式執行)

service rabbitmq-server start &
複製程式碼

開啟管理UI(建議後臺模式執行)

rabbitmq-plugins enable rabbitmq_management &
複製程式碼

訪問:ip:15672,用新新增的使用者登陸

rabbitmq

kafka

幾個重要概念:

  • Broker:Kafka叢集包含一個或多個伺服器,這種伺服器被稱為broker
  • Topic:每條釋出到Kafka叢集的訊息都有一個類別,這個類別被稱為Topic。
  • Partition:Parition是物理上的概念,每個Topic包含一個或多個Partition.
  • Producer:負責釋出訊息到Kafka broker
  • Consumer:訊息消費者,向Kafka broker讀取訊息的客戶端。
  • Consumer Group:每個Consumer屬於一個特定的Consumer Group(可為每個Consumer指定group name,若不指定group name則屬於預設的group)。

單機
Kafka使用Zookeeper來維護叢集資訊,所以需要先安裝zookeeper,而zookeeper是由java編寫的,所以需要先安裝jdk

  • jdk:1.8版本及以上(後面需要用到Kafka監控工具KafkaOffsetMonitor目前所依賴的jdk版本較高)
  • zookeeper:新版本的kafka自帶有zookeeper

下載地址:kafka.apache.org/downloads

# 下載解壓
mkdir kafka && cd kafka
wget http://mirrors.shuosc.org/apache/kafka/1.0.0/kafka_2.11-1.0.0.tgz
tar -xzf kafka_2.11-1.0.0.tgz
cd kafka_2.11-1.0.1
# 啟動zookeeper
bin/zookeeper-server-start.sh config/zookeeper.properties
# 啟動kafka
bin/kafka-server-start.sh config/server.properties
# 建立Topic test
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
# 引數描述:
# create: 建立Topic
# zookeeper:zookeeper叢集資訊,多個用,分開
# replication-factor:複製因子
# partitions:分割槽資訊
# topic:主題名

# 向topic傳送訊息
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
> 隨便輸入

# 向topic獲取訊息
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
# 就能看到前面輸入的訊息了
複製程式碼

Kafka監控工具
kafka沒有自帶的web ui,這裡使用KafkaOffsetMonitor, 程式一個jar包的形式執行,部署較為方便。只有監控功能,使用起來也較為安全。

KafkaOffsetMonitor託管在Github上,可以通過Github下載。 下載地址:github.com/Morningstar…

# 下載好之後cd到KafkaOffsetMonitor所在目錄,可以直接啟動,也可以編寫shell指令碼來啟動
java -cp KafkaOffsetMonitor-assembly-0.4.1-SNAPSHOT.jar com.quantifind.kafka.offsetapp.OffsetGetterWeb
--port 8089
--zk 127.0.0.1:2181 
--refresh 5.minutes 
--retain 1.day
複製程式碼

編寫指令碼啟動

mkdir kafka-monitor.sh
chmod  +x kafka-monitor.sh
vi kafka-monitor.sh
# 把之前啟動的命令複製進來,如:
#! /bin/bash
java -Xms512M -Xmx512M -Xss1024K \
     -cp KafkaOffsetMonitor-assembly-0.4.1-SNAPSHOT.jar \
     com.quantifind.kafka.offsetapp.OffsetGetterWeb \
     --zk localhost:2181 \
     --port 8089 \
     --refresh 10.seconds \
     --retain 5.days
# 儲存,然後就可以啟動指令碼了
複製程式碼

zk :zookeeper主機地址,如果有多個,用逗號隔開
port :應用程式埠(沒設定的話,日誌裡面會輸出隨機的埠號)
refresh :應用程式在資料庫中重新整理和儲存點的頻率
retain :在db中保留多長時間
dbName :儲存的資料庫檔名,預設為offsetapp

github上詳細引數說明:

KafkaOffsetMonitor
訪問:ip:埠

ui

    Topic:訂閱的主題
    Partition:分割槽編號
    Offest:表示該parition已經消費了多少條message
    logSize:表示該partition已經寫了多少條message
    Lag:表示有多少條message沒有被消費。
    Owner:表示消費者
    Created:該partition建立時間
    Last Seen:消費狀態重新整理最新時間。
複製程式碼

注意
本機能訪問,但其它機器不能訪問應該就是防火牆的問題,開放對應埠,或者關閉防火牆
如果能訪問,但是沒有資訊顯示出來,只顯示了黑色的屏,是因為ui頁面所依賴的ajax.googleapis.com等公共庫被牆了
解決辦法

結語

未完待續......。
個人部落格~
簡書~

相關文章