1. 程式人生 > >訊息佇列及常見訊息佇列介紹

訊息佇列及常見訊息佇列介紹

一、訊息佇列(MQ)概述

訊息佇列(Message Queue),是分散式系統中重要的元件,其通用的使用場景可以簡單地描述為:

當不需要立即獲得結果,但是併發量又需要進行控制的時候,差不多就是需要使用訊息佇列的時候。

訊息佇列主要解決了應用耦合、非同步處理、流量削鋒等問題。

當前使用較多的訊息佇列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,而部分資料庫如Redis、Mysql以及phxsql也可實現訊息佇列的功能。

二、訊息佇列使用場景

訊息佇列在實際應用中包括如下四個場景:

  • 應用耦合:多應用間通過訊息佇列對同一訊息進行處理,避免呼叫介面失敗導致整個過程失敗;
  • 非同步處理:多應用對訊息佇列中同一訊息進行處理,應用間併發處理訊息,相比序列處理,減少處理時間;
  • 限流削峰:廣泛應用於秒殺或搶購活動中,避免流量過大導致應用系統掛掉的情況;
  • 訊息驅動的系統:系統分為訊息佇列、訊息生產者、訊息消費者,生產者負責產生訊息,消費者(可能有多個)負責對訊息進行處理;

下面詳細介紹上述四個場景以及訊息佇列如何在上述四個場景中使用:

2.1 非同步處理

具體場景:使用者為了使用某個應用,進行註冊,系統需要傳送註冊郵件並驗證簡訊。對這兩個操作的處理方式有兩種:序列及並行。

(1)序列方式:新註冊資訊生成後,先發送註冊郵件,再發送驗證簡訊;

在這種方式下,需要最終傳送驗證簡訊後再返回給客戶端。

(2)並行處理:新註冊資訊寫入後,由發簡訊和發郵件並行處理;

在這種方式下,發簡訊和發郵件 需處理完成後再返回給客戶端。

假設以上三個子系統處理的時間均為50ms,且不考慮網路延遲,則總的處理時間:

序列:50+50+50=150ms 並行:50+50 = 100ms

若使用訊息佇列:

並在寫入訊息佇列後立即返回成功給客戶端,則總的響應時間依賴於寫入訊息佇列的時間,而寫入訊息佇列的時間本身是可以很快的,基本可以忽略不計,因此總的處理時間相比序列提高了2倍,相比並行提高了一倍;

2.2 應用耦合

具體場景:使用者使用QQ相簿上傳一張圖片,人臉識別系統會對該圖片進行人臉識別,一般的做法是,伺服器接收到圖片後,圖片上傳系統立即呼叫人臉識別系統,呼叫完成後再返回成功,如下圖所示:

該方法有如下缺點:

  • 人臉識別系統被調失敗,導致圖片上傳失敗;
  • 延遲高,需要人臉識別系統處理完成後,再返回給客戶端,即使使用者並不需要立即知道結果;
  • 圖片上傳系統與人臉識別系統之間互相呼叫,需要做耦合;

若使用訊息佇列:

客戶端上傳圖片後,圖片上傳系統將圖片資訊如uin、批次寫入訊息佇列,直接返回成功;而人臉識別系統則定時從訊息佇列中取資料,完成對新增圖片的識別。

此時圖片上傳系統並不需要關心人臉識別系統是否對這些圖片資訊的處理、以及何時對這些圖片資訊進行處理。事實上,由於使用者並不需要立即知道人臉識別結果,人臉識別系統可以選擇不同的排程策略,按照閒時、忙時、正常時間,對佇列中的圖片資訊進行處理。

2.3 限流削峰

具體場景:購物網站開展秒殺活動,一般由於瞬時訪問量過大,伺服器接收過大,會導致流量暴增,相關係統無法處理請求甚至崩潰。而加入訊息佇列後,系統可以從訊息佇列中取資料,相當於訊息佇列做了一次緩衝。

該方法有如下優點:

  1. 請求先入訊息佇列,而不是由業務處理系統直接處理,做了一次緩衝,極大地減少了業務處理系統的壓力;
  2. 佇列長度可以做限制,事實上,秒殺時,後入佇列的使用者無法秒殺到商品,這些請求可以直接被拋棄,返回活動已結束或商品已售完資訊;

2.4 訊息驅動的系統

具體場景:使用者新上傳了一批照片, 人臉識別系統需要對這個使用者的所有照片進行聚類,聚類完成後由對賬系統重新生成使用者的人臉索引(加快查詢)。這三個子系統間由訊息佇列連線起來,前一個階段的處理結果放入佇列中,後一個階段從佇列中獲取訊息繼續處理。

該方法有如下優點:

  • 避免了直接呼叫下一個系統導致當前系統失敗;
  • 每個子系統對於訊息的處理方式可以更為靈活,可以選擇收到訊息時就處理,可以選擇定時處理,也可以劃分時間段按不同處理速度處理;

三、訊息佇列的兩種模式

訊息佇列包括兩種模式,點對點模式(point to point, queue)和釋出/訂閱模式(publish/subscribe,topic)。

3.1 點對點模式

點對點模式下包括三個角色:

  • 訊息佇列
  • 傳送者 (生產者)
  • 接收者(消費者)

訊息傳送者生產訊息傳送到queue中,然後訊息接收者從queue中取出並且消費訊息。訊息被消費以後,queue中不再有儲存,所以訊息接收者不可能消費到已經被消費的訊息。

點對點模式特點:

  • 每個訊息只有一個接收者(Consumer)(即一旦被消費,訊息就不再在訊息佇列中);
  • 傳送者和接收者間沒有依賴性,傳送者傳送訊息之後,不管有沒有接收者在執行,都不會影響到傳送者下次傳送訊息;
  • 接收者在成功接收訊息之後需向佇列應答成功,以便訊息佇列刪除當前接收的訊息;

3.2 釋出/訂閱模式

釋出/訂閱模式下包括三個角色:

  • 角色主題(Topic)
  • 釋出者(Publisher)
  • 訂閱者(Subscriber)

釋出者將訊息傳送到Topic,系統將這些訊息傳遞給多個訂閱者。

釋出/訂閱模式特點:

  • 每個訊息可以有多個訂閱者;
  • 釋出者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須建立一個訂閱者之後,才能消費釋出者的訊息。
  • 為了消費訊息,訂閱者需要提前訂閱該角色主題,並保持線上執行;

四、常用訊息佇列介紹

本部分主要介紹四種常用的訊息佇列(RabbitMQ/ActiveMQ/RocketMQ/Kafka)的主要特性、優點、缺點。

4.1 RabbitMQ

RabbitMQ 2007年釋出,是一個在AMQP(高階訊息佇列協議)基礎上完成的,可複用的企業訊息系統,是當前最主流的訊息中介軟體之一。

主要特性:

  1. 可靠性: 提供了多種技術可以讓你在效能和可靠性之間進行權衡。這些技術包括永續性機制、投遞確認、釋出者證實和高可用性機制;
  2. 靈活的路由: 訊息在到達佇列前是通過交換機進行路由的。RabbitMQ為典型的路由邏輯提供了多種內建交換機型別。如果你有更復雜的路由需求,可以將這些交換機組合起來使用,你甚至可以實現自己的交換機型別,並且當做RabbitMQ的外掛來使用;
  3. 訊息叢集:在相同區域網中的多個RabbitMQ伺服器可以聚合在一起,作為一個獨立的邏輯代理來使用;
  4. 佇列高可用:佇列可以在叢集中的機器上進行映象,以確保在硬體問題下還保證訊息安全;
  5. 多種協議的支援:支援多種訊息佇列協議;
  6. 伺服器端用Erlang語言編寫,支援只要是你能想到的所有程式語言;
  7. 管理介面: RabbitMQ有一個易用的使用者介面,使得使用者可以監控和管理訊息Broker的許多方面;
  8. 跟蹤機制:如果訊息異常,RabbitMQ提供訊息跟蹤機制,使用者可以找出發生了什麼;
  9. 外掛機制:提供了許多外掛,來從多方面進行擴充套件,也可以編寫自己的外掛;

使用RabbitMQ需要:

  • ErLang語言包
  • RabbitMQ安裝包

RabbitMQ可以執行在Erlang語言所支援的平臺之上:

Solaris

BSD

Linux

MacOSX

TRU64

Windows NT/2000/XP/Vista/Windows 7/Windows 8

Windows Server 2003/2008/2012

Windows 95, 98

VxWorks

優點:

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

缺點:

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

   4、架構圖

幾個重要概念:

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。

exchange接收到訊息後,就根據訊息的key和已經設定的binding,進行訊息路由,將訊息投遞到一個或多個佇列裡。

4.2 ActiveMQ

ActiveMQ是由Apache出品,ActiveMQ 是一個完全支援JMS1.1和J2EE 1.4規範的 JMS Provider實現。它非常快速,支援多種語言的客戶端和協議,而且可以非常容易的嵌入到企業的應用環境中,並有許多高階功能。

主要特性:

  1. 服從 JMS 規範:JMS 規範提供了良好的標準和保證,包括:同步或非同步的訊息分發,一次和僅一次的訊息分發,訊息接收和訂閱等等。遵從 JMS 規範的好處在於,不論使用什麼 JMS 實現提供者,這些基礎特性都是可用的;
  2. 連線性:ActiveMQ 提供了廣泛的連線選項,支援的協議有:HTTP/S,IP 多播,SSL,STOMP,TCP,UDP,XMPP等等。對眾多協議的支援讓 ActiveMQ 擁有了很好的靈活性。
  3. 支援的協議種類多:OpenWire、STOMP、REST、XMPP、AMQP ;
  4. 持久化外掛和安全外掛:ActiveMQ 提供了多種持久化選擇。而且,ActiveMQ 的安全性也可以完全依據使用者需求進行自定義鑑權和授權;
  5. 支援的客戶端語言種類多:除了 Java 之外,還有:C/C++,.NET,Perl,PHP,Python,Ruby;
  6. 代理叢集:多個 ActiveMQ 代理可以組成一個叢集來提供服務;
  7. 異常簡單的管理:ActiveMQ 是以開發者思維被設計的。所以,它並不需要專門的管理員,因為它提供了簡單又使用的管理特性。有很多中方法可以監控 ActiveMQ 不同層面的資料,包括使用在 JConsole 或者 ActiveMQ 的Web Console 中使用 JMX,通過處理 JMX 的告警訊息,通過使用命令列指令碼,甚至可以通過監控各種型別的日誌。

使用ActiveMQ需要:

  • Java JDK
  • ActiveMQ安裝包

ActiveMQ可以執行在Java語言所支援的平臺之上。

優點:

  1. 跨平臺(JAVA編寫與平臺無關有,ActiveMQ幾乎可以執行在任何的JVM上)
  2. 可以用JDBC:可以將資料持久化到資料庫。雖然使用JDBC會降低ActiveMQ的效能,但是資料庫一直都是開發人員最熟悉的儲存介質。將訊息存到資料庫,看得見摸得著。而且公司有專門的DBA去對資料庫進行調優,主從分離;
  3. 支援JMS :支援JMS的統一介面;
  4. 支援自動重連;
  5. 有安全機制:支援基於shiro,jaas等多種安全配置機制,可以對Queue/Topic進行認證和授權。
  6. 監控完善:擁有完善的監控,包括Web Console,JMX,Shell命令列,Jolokia的REST API;
  7. 介面友善:提供的Web Console可以滿足大部分情況,還有很多第三方的元件可以使用,如hawtio;

缺點:

  1. 社群活躍度不及RabbitMQ高;
  2. 根據其他使用者反饋,會出莫名其妙的問題,會丟失訊息;
  3. 目前重心放到activemq6.0產品-apollo,對5.x的維護較少;
  4. 不適合用於上千個佇列的應用場景;

4.3 RocketMQ

RocketMQ出自 阿里公司的開源產品,用 Java 語言實現,在設計時參考了 Kafka,並做出了自己的一些改進,訊息可靠性上比 Kafka 更好。RocketMQ在阿里集團被廣泛應用在訂單,交易,充值,流計算,訊息推送,日誌流式處理,binglog分發等場景。

主要特性:

  1. 是一個佇列模型的訊息中介軟體,具有高效能、高可靠、高實時、分散式特點;
  2. Producer、Consumer、佇列都可以分散式;
  3. Producer向一些佇列輪流傳送訊息,佇列集合稱為Topic,Consumer如果做廣播消費,則一個consumer例項消費這個Topic對應的所有佇列,如果做叢集消費,則多個Consumer例項平均消費這個topic對應的佇列集合;
  4. 能夠保證嚴格的訊息順序;
  5. 提供豐富的訊息拉取模式;
  6. 高效的訂閱者水平擴充套件能力;
  7. 實時的訊息訂閱機制;
  8. 億級訊息堆積能力;
  9. 較少的依賴;

使用RocketMQ需要:

  • Java JDK
  • 安裝git、Maven
  • RocketMQ安裝包

RocketMQ可以執行在Java語言所支援的平臺之上。

優點:

  1. 單機支援 1 萬以上持久化佇列
  2. RocketMQ 的所有訊息都是持久化的,先寫入系統 PAGECACHE,然後刷盤,可以保證記憶體與磁碟都有一份資料,

訪問時,直接從記憶體讀取。

  1. 模型簡單,介面易用(JMS 的介面很多場合並不太實用);
  2. 效能非常好,可以大量堆積訊息在broker中;
  3. 支援多種消費,包括叢集消費、廣播消費等。
  4. 各個環節分散式擴充套件設計,主從HA;
  5. 開發度較活躍,版本更新很快。

缺點:

支援的客戶端語言不多,目前是java及c++,其中c++不成熟;

RocketMQ社群關注度及成熟度也不及前兩者;

沒有web管理介面,提供了一個CLI(命令列介面)管理工具帶來查詢、管理和診斷各種問題;

沒有在 mq 核心中去實現JMS等介面;

4.4 Kafka

Apache Kafka是一個分散式訊息釋出訂閱系統。它最初由LinkedIn公司基於獨特的設計實現為一個分散式的提交日誌系統( a distributed commit log),,之後成為Apache專案的一部分。Kafka系統快速、可擴充套件並且可持久化。它的分割槽特性,可複製和可容錯都是其不錯的特性。

主要特性:

  1. 快速持久化,可以在O(1)的系統開銷下進行訊息持久化;
  2. 高吞吐,在一臺普通的伺服器上既可以達到10W/s的吞吐速率;
  3. .完全的分散式系統,Broker、Producer、Consumer都原生自動支援分散式,自動實現負載均衡;
  4. 支援同步和非同步複製兩種HA;
  5. 支援資料批量傳送和拉取;
  6. zero-copy:減少IO操作步驟;
  7. 資料遷移、擴容對使用者透明;
  8. 無需停機即可擴充套件機器;
  9. 其他特性:嚴格的訊息順序、豐富的訊息拉取模型、高效訂閱者水平擴充套件、實時的訊息訂閱、億級的訊息堆積能力、定期刪除機制;

使用Kafka需要:

  • Java JDK
  • Kafka安裝包

優點:

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

缺點:

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

4.5 RabbitMQ/ActiveMQ/RocketMQ/Kafka對比

這裡列舉了上述四種訊息佇列的差異對比:

結論:

Kafka在於分散式架構,RabbitMQ基於AMQP協議來實現,RocketMQ/思路來源於kafka,改成了主從結構,在事務性可靠性方面做了優化。廣泛來說,電商、金融等對事務性要求很高的,可以考慮RabbitMQ和RocketMQ,對效能要求高的可考慮Kafka。

五、參考資料:

5.1 訊息佇列:

5.2 RabbitMQ

5.3 ActiveMQ

5.4 RocketMQ

5.5 Kafka

5.6 RabbitMQ/ActiveMQ/RocketMQ/Kafka對比

總結:

訊息佇列利用高效可靠的訊息傳遞機制進行平臺無關的資料交流,並基於資料通訊來進行分散式系統的整合。目前業界有很多的MQ產品,例如RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,也有直接使用資料庫redis充當訊息佇列的案例。而這些訊息佇列產品,各有側重,在實際選型時,需要結合自身需求及MQ產品特徵,綜合考慮。