天天看點

RocketMQ 簡介

文章首發于公衆号《程式員果果》

位址:

https://mp.weixin.qq.com/s/qSsHBNDghZAlkUVBYM6LDA

簡介

RocketMQ是由阿裡捐贈給Apache的一款低延遲、高并發、高可用、高可靠的分布式消息中間件。經曆了淘寶雙十一的洗禮。RocketMQ既可為分布式應用系統提供異步解耦和削峰填谷的能力,同時也具備網際網路應用所需的海量消息堆積、高吞吐、可靠重試等特性。

核心概念

  • Topic:消息主題,一級消息類型,生産者向其發送消息。
  • Message:生産者向Topic發送并最終傳送給消費者的資料消息的載體。
  • 消息屬性:生産者可以為消息定義的屬性,包含Message Key和Tag。
  • Message Key:消息的業務辨別,由消息生産者(Producer)設定,唯一辨別某個業務邏輯。
  • Message ID:消息的全局唯一辨別,由消息隊列RocketMQ系統自動生成,唯一辨別某條消息。
  • Tag:消息标簽,二級消息類型,用來進一步區分某個Topic下的消息分類
  • Producer:也稱為消息釋出者,負責生産并發送消息至Topic。
  • Consumer:也稱為消息訂閱者,負責從Topic接收并消費消息。
  • 分區:即Topic Partition,實體上的概念。每個Topic包含一個或多個分區。
  • 消費位點:每個Topic會有多個分區,每個分區會統計目前消息的總條數,這個稱為最大位點MaxOffset;分區的起始位置對應的位置叫做起始位點MinOffset。
  • Group:一類生産者或消費者,這類生産者或消費者通常生産或消費同一類消息,且消息釋出或訂閱的邏輯一緻。
  • Group ID:Group的辨別。
  • 隊列:個Topic下會由一到多個隊列來存儲消息。
  • Exactly-Once投遞語義:Exactly-Once投遞語義是指發送到消息系統的消息隻能被Consumer處理且僅處理一次,即使Producer重試消息發送導緻某消息重複投遞,該消息在Consumer也隻被消費一次。
  • 叢集消費:一個Group ID所辨別的所有Consumer平均分攤消費消息。例如某個Topic有9條消息,一個Group ID有3個Consumer執行個體,那麼在叢集消費模式下每個執行個體平均分攤,隻消費其中的3條消息。
  • 廣播消費:一個Group ID所辨別的所有Consumer都會各自消費某條消息一次。例如某個Topic有9條消息,一個Group ID有3個Consumer執行個體,那麼在廣播消費模式下每個執行個體都會各自消費9條消息。
  • 定時消息:Producer将消息發送到消息隊列RocketMQ服務端,但并不期望這條消息立馬投遞,而是推遲到在目前時間點之後的某一個時間投遞到Consumer進行消費,該消息即定時消息。
  • 延時消息:Producer将消息發送到消息隊列RocketMQ服務端,但并不期望這條消息立馬投遞,而是延遲一定時間後才投遞到Consumer進行消費,該消息即延時消息。
  • 事務消息:RocketMQ提供類似X/Open XA的分布事務功能,通過消息隊列RocketMQ的事務消息能達到分布式事務的最終一緻。
  • 順序消息:RocketMQ提供的一種按照順序進行釋出和消費的消息類型,分為全局順序消息和分區順序消息。
  • 全局順序消息:對于指定的一個Topic,所有消息按照嚴格的先入先出(FIFO)的順序進行釋出和消費。
  • 分區順序消息:對于指定的一個Topic,所有消息根據Sharding Key進行區塊分區。同一個分區内的消息按照嚴格的FIFO順序進行釋出和消費。Sharding Key是順序消息中用來區分不同分區的關鍵字段,和普通消息的Message Key是完全不同的概念。
  • 消息堆積:Producer已經将消息發送到消息隊列RocketMQ的服務端,但由于Consumer消費能力有限,未能在短時間内将所有消息正确消費掉,此時在消息隊列RocketMQ的服務端儲存着未被消費的消息,該狀态即消息堆積。
  • 消息過濾:Consumer可以根據消息标簽(Tag)對消息進行過濾,確定Consumer最終隻接收被過濾後的消息類型。消息過濾在消息隊列RocketMQ的服務端完成。
  • 消息軌迹:在一條消息從Producer發出到Consumer消費處理過程中,由各個相關節點的時間、地點等資料彙聚而成的完整鍊路資訊。通過消息軌迹,您能清晰定位消息從Producer發出,經由消息隊列RocketMQ服務端,投遞給Consumer的完整鍊路,友善定位排查問題。
  • 重置消費位點:以時間軸為坐标,在消息持久化存儲的時間範圍内(預設3天),重新設定Consumer對已訂閱的Topic的消費進度,設定完成後Consumer将接收設定時間點之後由Producer發送到消息隊列RocketMQ服務端的消息。
  • 死信隊列:死信隊列用于處理無法被正常消費的消息。當一條消息初次消費失敗,消息隊列RocketMQ會自動進行消息重試;達到最大重試次數後,若消費依然失敗,則表明Consumer在正常情況下無法正确地消費該消息。此時,消息隊列RocketMQ不會立刻将消息丢棄,而是将這條消息發送到該Consumer對應的特殊隊列中。

    消息隊列RocketMQ将這種正常情況下無法被消費的消息稱為死信消息(Dead-Letter Message),将存儲死信消息的特殊隊列稱為死信隊列(Dead-Letter Queue)。

消息收發模型

消息隊列RocketMQ支援釋出和訂閱模型,消息生産者應用建立Topic并将消息發送到Topic。消費者應用建立對Topic的訂閱以便從其接收消息。通信可以是一對多(扇出)、多對一(扇入)和多對多。具體通信如下圖所示。

RocketMQ 簡介
  • 生産者叢集:用來表示發送消息應用,一個生産者叢集下包含多個生産者執行個體,可以是多台機器,也可以是一台機器的多個程序,或者一個程序的多個生産者對象。

    一個生産者叢集可以發送多個Topic消息。發送分布式事務消息時,如果生産者中途意外當機,消息隊列RocketMQ服務端會主動回調生産者叢集的任意一台機器來确認事務狀态。

  • 消費者叢集:用來表示消費消息應用,一個消費者叢集下包含多個消費者執行個體,可以是多台機器,也可以是多個程序,或者是一個程序的多個消費者對象。

    一個消費者叢集下的多個消費者以均攤方式消費消息。如果設定的是廣播方式,那麼這個消費者叢集下的每個執行個體都消費全量資料。

    一個消費者叢集對應一個Group ID,一個Group ID可以訂閱多個Topic,如上圖中的Group 2所示。Group和Topic的訂閱關系可以通過直接在程式中設定即可。

應用場景

  • 削峰填谷:諸如秒殺、搶紅包、企業開門紅等大型活動時皆會帶來較高的流量脈沖,或因沒做相應的保護而導緻系統超負荷甚至崩潰,或因限制太過導緻請求大量失敗而影響使用者體驗,消息隊列RocketMQ可提供削峰填谷的服務來解決該問題。
  • 異步解耦:交易系統作為淘寶和天貓主站最核心的系統,每筆交易訂單資料的産生會引起幾百個下遊業務系統的關注,包括物流、購物車、積分、流計算分析等等,整體業務系統龐大而且複雜,消息隊列RocketMQ可實作異步通信和應用解耦,確定主站業務的連續性。
  • 順序收發:細數日常中需要保證順序的應用場景非常多,例如證券交易過程時間優先原則,交易系統中的訂單建立、支付、退款等流程,航班中的旅客登機消息處理等等。與先進先出FIFO(First In First Out)原理類似,消息隊列RocketMQ提供的順序消息即保證消息FIFO。
  • 分布式事務一緻性:交易系統、支付紅包等場景需要確定資料的最終一緻性,大量引入消息隊列RocketMQ的分布式事務,既可以實作系統之間的解耦,又可以保證最終的資料一緻性。
  • 大資料分析:資料在“流動”中産生價值,傳統資料分析大多是基于批量計算模型,而無法做到實時的資料分析,利用阿裡雲消息隊列RocketMQ與流式計算引擎相結合,可以很友善的實作業務資料的實時分析。
  • 分布式緩存同步:天貓雙11大促,各個分會場琳琅滿目的商品需要實時感覺價格變化,大量并發通路資料庫導緻會場頁面響應時間長,集中式緩存因帶寬瓶頸,限制了商品變更的通路流量,通過消息隊列RocketMQ建構分布式緩存,實時通知商品資料的變化。

下文先以使用者注冊為場景說明消息隊列RocketMQ如何實作以下功能:

  • 異步解耦
  • 分布式事務的資料一緻性
  • 消息的順序收發

最後,再以電商的秒殺場景和價格同步場景分别說明消息隊列RocketMQ所實作的削峰填谷和大規模機器的緩存同步。

傳統處理

最常見的一個場景是使用者注冊後,需要發送注冊郵件和短信通知,以告知使用者注冊成功。傳統的做法有以下兩種:

  • 串行方式
    RocketMQ 簡介
    資料流動如下所述:
    1. 您在注冊頁面填寫賬号和密碼并送出注冊資訊,這些注冊資訊首先會被寫入注冊系統。
    2. 注冊資訊寫入注冊系統成功後,再發送請求至郵件通知系統。郵件通知系統收到請求後向使用者發送郵件通知。
    3. 郵件通知系統接收注冊系統請求後再向下遊的短信通知系統發送請求。短信通知系統收到請求後向使用者發送短信通知。

    以上三個任務全部完成後,才傳回注冊結果到用戶端,使用者才能使用賬号登入。

    假設每個任務耗時分别為50 ms,則使用者需要在注冊頁面等待總共150 ms才能登入。

  • 并行方式
    RocketMQ 簡介
    1. 使用者在注冊頁面填寫賬号和密碼并送出注冊資訊,這些注冊資訊首先會被寫入注冊系統。
    2. 注冊資訊寫入注冊系統成功後,再同時發送請求至郵件和短信通知系統。郵件和短信通知系統收到請求後分别向使用者發送郵件和短信通知。

    以上兩個任務全部完成後,才傳回注冊結果到用戶端,使用者才能使用賬号登入。

    假設每個任務耗時分别為50 ms,其中,郵件和短信通知并行完成,則使用者需要在注冊頁面等待總共100 ms才能登入。

對于使用者來說,注冊功能實際隻需要注冊系統存儲使用者的賬戶資訊後,該使用者便可以登入,後續的注冊短信和郵件不是即時需要關注的步驟。

對于注冊系統而言,發送注冊成功的短信和郵件通知并不一定要綁定在一起同步完成,是以實際當資料寫入注冊系統後,注冊系統就可以把其他的操作放入對應的消息隊列RocketMQ中然後馬上傳回使用者結果,由消息隊列RocketMQ異步地進行這些操作。

RocketMQ 簡介
  1. 注冊資訊寫入注冊系統成功後,再發送消息至消息隊列RocketMQ。消息隊列RocketMQ會馬上傳回響應給注冊系統,注冊完成。使用者可立即登入。
  2. 下遊的郵件和短信通知系統訂閱消息隊列RocketMQ的此類注冊請求消息,即可向使用者發送郵件和短信通知,完成所有的注冊流程。

使用者隻需在注冊頁面等待注冊資料寫入注冊系統和消息隊列RocketMQ的時間,即等待55 ms即可登入。

異步解耦是消息隊列RocketMQ的主要特點,主要目的是減少請求響應時間和解耦。主要的适用場景就是将比較耗時而且不需要即時(同步)傳回結果的操作作為消息放入消息隊列。同時,由于使用了消息隊列RocketMQ,隻要保證消息格式不變,消息的發送方和接收方并不需要彼此聯系,也不需要受對方的影響,即解耦。

注冊系統注冊的流程中,使用者入口在網頁注冊系統,通知系統在郵件系統,兩個系統之間的資料需要保持最終一緻。

普通消息處理

如上所述,注冊系統和郵件通知系統之間通過消息隊列進行異步處理。注冊系統将注冊資訊寫入注冊系統之後,發送一條注冊成功的消息到消息隊列RocketMQ,郵件通知系統訂閱消息隊列RocketMQ的注冊消息,做相應的業務處理,發送注冊成功或者失敗的郵件。

RocketMQ 簡介

流程說明如下:

  1. 注冊系統發起注冊。
  2. 注冊系統向消息隊列RocketMQ發送注冊消息成功與否的消息。

    2.1. 消息發送成功,進入3。

    2.2. 消息發送失敗,導緻郵件通知系統未收到消息隊列RocketMQ發送的注冊成功與否的消息,而無法發送郵件,最終郵件通知系統和注冊系統之間的狀态資料不一緻。

  3. 郵件通知系統收到消息隊列RocketMQ的注冊成功消息。
  4. 郵件通知系統發送注冊成功郵件給使用者。

在這樣的情況下,雖然實作了系統間的解耦,上遊系統不需要關心下遊系統的業務處理結果;但是資料一緻性不好處理,如何保證郵件通知系統狀态與注冊系統狀态的最終一緻。

事務消息處理

此時,需要利用消息隊列RocketMQ所提供的事務消息來實作系統間的狀态資料一緻性。

RocketMQ 簡介
  1. 注冊系統向消息隊列RocketMQ發送半事務消息。

    1.1. 半事務消息發送成功,進入2。

    1.2. 半事務消息發送失敗,注冊系統不進行注冊,流程結束。(最終注冊系統與郵件通知系統資料一緻)

  2. 注冊系統開始注冊。

    2.1. 注冊成功,進入3.1。

    2.2. 注冊失敗,進入3.2。

  3. 注冊系統向消息隊列RocketMQ發送半消息狀态。

    3.1. 送出半事務消息,産生注冊成功消息,進入4。

    3.2. 復原半事務消息,未産生注冊成功消息,流程結束。

    說明 最終注冊系統與郵件通知系統資料一緻。

  4. 郵件通知系統接收消息隊列RocketMQ的注冊成功消息。
  5. 郵件通知系統發送注冊成功郵件。(最終注冊系統與郵件通知系統資料一緻)

    關于分布式事務消息的更多詳細内容,請參見事務消息。

消息隊列RocketMQ順序消息分為兩種情況:

  • 全局順序:對于指定的一個Topic,所有消息将按照嚴格的先入先出(FIFO)的順序,進行順序釋出和順序消費。
  • 分區順序:對于指定的一個Topic,所有消息根據Sharding Key進行區塊分區,同一個分區内的消息将按照嚴格的FIFO的順序,進行順序釋出和順序消費,可以保證一個消息被一個程序消費。

    在注冊場景中,可使用使用者ID作為Sharding Key來進行分區,同一個分區下的建立、更新或删除注冊資訊的消息必須按照FIFO的順序釋出和消費。

削峰填谷

流量削峰也是消息隊列RocketMQ的常用場景,一般在秒殺或團隊搶購活動中使用廣泛。

在秒殺或團隊搶購活動中,由于使用者請求量較大,導緻流量暴增,秒殺的應用在處理如此大量的通路流量後,下遊的通知系統無法承載海量的調用量,甚至會導緻系統崩潰等問題而發生漏通知的情況。為解決這些問題,可在應用和下遊通知系統之間加入消息隊列RocketMQ。

RocketMQ 簡介

秒殺處理流程如下所述:

  1. 使用者發起海量秒殺請求到秒殺業務處理系統。
  2. 秒殺處理系統按照秒殺處理邏輯将滿足秒殺條件的請求發送至消息隊列RocketMQ。
  3. 下遊的通知系統訂閱消息隊列RocketMQ的秒殺相關消息,再将秒殺成功的消息發送到相應使用者。
  4. 使用者收到秒殺成功的通知。

大規模機器的緩存同步

雙十一大促時,各個分會場會有玲琅滿目的商品,每件商品的價格都會實時變化。使用緩存技術也無法滿足對商品價格的通路需求,緩存伺服器網卡滿載。通路較多次商品價格查詢影響會場頁面的打開速度。

此時需要提供一種廣播機制,一條消息本來隻可以被叢集的一台機器消費,如果使用消息隊列RocketMQ的廣播消費模式,那麼這條消息會被所有節點消費一次,相當于把價格資訊同步到需要的每台機器上,取代緩存的作用。

系統部署架構

系統部署架構如下圖所示。

RocketMQ 簡介

圖中所涉及到的概念如下所述:

  • Name Server:是一個幾乎無狀态節點,可叢集部署,在消息隊列RocketMQ版中提供命名服務,更新和發現Broker服務。
  • Broker:消息中轉角色,負責存儲消息,轉發消息。分為Master Broker和Slave Broker,一個Master Broker可以對應多個Slave Broker,但是一個Slave Broker隻能對應一個Master Broker。Broker啟動後需要完成一次将自己注冊至Name Server的操作;随後每隔30s定期向Name Server上報Topic路由資訊。
  • 生産者:與Name Server叢集中的其中一個節點(随機)建立長連結(Keep-alive),定期從Name Server讀取Topic路由資訊,并向提供Topic服務的Master Broker建立長連結,且定時向Master Broker發送心跳。
  • 消費者:與Name Server叢集中的其中一個節點(随機)建立長連接配接,定期從Name Server拉取Topic路由資訊,并向提供Topic服務的Master Broker、Slave Broker建立長連接配接,且定時向Master Broker、Slave Broker發送心跳。Consumer既可以從Master Broker訂閱消息,也可以從Slave Broker訂閱消息,訂閱規則由Broker配置決定。

參考

本文根據阿裡雲 RocketMQ産品文檔整理

https://help.aliyun.com/document_detail/29532.html?userCode=qtldtin2