消息中間件部署及比較:rabbitMQ、activeMQ、zeroMQ、rocketMQ、Kafka、redis

一發一存一消費,沒有最好的消息隊列中間件(簡稱消息中間件),只有最合適的消息中間件。
消息隊列經常使用的使用場景:php

  • 非實時性:當不須要當即得到結果,可是併發量又須要進行控制的時候,差很少就是須要使用消息隊列的時候。主要解決了應用耦合、異步處理、流量削鋒等問題。
  • 應用耦合:多應用間經過消息隊列對同一消息進行處理,避免調用接口失敗致使整個過程失敗;(如:訂單->庫存)
  • 異步處理:多應用對消息隊列中同一消息進行處理,應用間併發處理消息,相比串行處理,減小處理時間;(點對多場景,廣播場景(註冊發短信,發郵件)等等)
  • 限流削峯:應用於秒殺或搶購活動中,避免流量過大致使應用系統掛掉的狀況;(根據服務承受度設置隊列大小,超過了就返回活動結束了,我們常常各大商城秒殺,內心尚未點B數嗎)減小壓力,避免服務掛掉。
  • 消息驅動的系統:系統分爲消息隊列、消息生產者、消息消費者,生產者負責產生消息,消費者(可能有多個)負責對消息進行處理;(分工處理(各自對應相應的隊列),靈活應用(收到就處理/定時處理))

消息隊列是異步RPC的主要手段之一java

兩種模式:python

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

實際開發中消息中間件選型基於幾個方面:c++

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

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

消息中間件

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

中間件功能比較1
中間件功能比較2
中間件功能比較3

應用方面:web

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

架構模型方面:ajax

  • 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數據;無消息確認機制。

吞吐量:redis

  • rabbitMQ在吞吐量方面稍遜於kafka,他們的出發點不同,rabbitMQ支持對消息的可靠的傳遞,支持事務,不支持批量的操做;基於存儲的可靠性的要求存儲能夠採用內存或者硬盤。
  • kafka具備高的吞吐量,內部採用消息的批量處理,zero-copy機制,數據的存儲和獲取是本地磁盤順序批量操做,具備O(1)的複雜度,消息處理的效率很高。

可用性方面:shell

  • 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等公共庫被牆了
解決辦法

結語

未完待續......。
我的博客~
簡書~

相關文章
相關標籤/搜索