?【Alibaba中介軟體技術系列】「RocketMQ技術專題」小白專區之領略一下RocketMQ基礎之最!

浩宇天尚發表於2021-11-17

應一些小夥伴們的私信,希望可以介紹一下RocketMQ的基礎,那麼我們現在就從0開始,進入RocketMQ的基礎學習及概念介紹,為學習和使用RocketMQ打好基礎!

RocketMQ的定位

RocketMQ是一款快速地、可靠地、分散式、容易使用的訊息中介軟體,由Alibaba開發,其前身是 Metaq,Metaq 可以看成是linkedin的Kafka(scala)的java版本,並對其增加了事務的支援。

RocketMQ的定義

RocketMQ為Metaq3.0,相比於原始kafka,其擅長點出了原始的log collecting之外,還增加諸如HA、事務等特性,使得從功能上可以替代傳統大部分 MQ。

RocketMQ具有特點

  • 可靠的FIFO和嚴格的訊息順序
  • Pub/Sub 和 P2P 訊息模型
  • 單佇列容納百萬訊息的能力
  • 拉(Pull)和推(push)佇列
  • 各種訊息協議,如 JMS,MQTT 等
  • 分散式叢集,支援容錯
  • Docker images for isolated testing and cloud Isolated clusters
  • 豐富的配置和監控功能的管理

RocketMQ的基本部件

Topic(訂閱主題)

Topic 是一個主題。一個系統中,我們可以將訊息劃成 Topic ,這樣,將不同的訊息傳送到不同的 queue。

Queue(佇列)

  • 一個topic下,我們可以設定多個queue,每個queue就是我們平時所說的訊息佇列;

  • 因為queue是完全從屬於某個特定的topic的,所以當我們要傳送訊息時,總是要指定該訊息所屬的topic是什麼。

  • 通過equeue就能知道該topic下有幾個queue了,但是到底傳送到哪個queue呢?比如topic下有4個queue,那對於這個topic下的訊息,傳送時,到底該傳送到哪個queue呢?

訊息被路由的過程
  • 目前,equeue的做法是在傳送一個訊息時,需要使用者指定這個訊息對應的topic以及一個用來路由的一個object型別的引數。

  • equeue會根據topic得到所有的queue,然後根據該object引數通過hash code然後取模queue的個數最後得到要傳送的queue的編號,從而知道該傳送到哪個queue。

  • 這個路由訊息的過程是在傳送訊息的這一方做的,也就是下面要說的producer。之所以不在訊息伺服器上做是因為這樣可以讓使用者自己決定該如何路由訊息,具有更大的靈活性。

Producer(生產者)

訊息佇列的生產者。我們知道,訊息佇列的本質就是實現了publish-subscribe的模式,即生產者-消費者模式。生產者生產訊息,消費者消費訊息。所以這裡的Producer就是用來生產和傳送訊息的。

Consumer

訊息佇列的消費者,一個訊息可以有多個消費者。

Consumer Group

消費者分組,這可能對大家來說是一個新概念。之所以要搞出一個消費者分組,是為了實現下面要說的叢集消費。一個消費者分組中包含了一些消費者,如果這些消費者是要叢集消費,那這些消費者會平均消費該分組中的訊息。

Broker

  • equeue中的broker負責訊息的中轉,即接收producer傳送過來的訊息,然後持久化訊息到磁碟,然後接收consumer傳送過來的拉取訊息的請求,然後根據請求拉取相應的訊息給consumer。

  • 所以,broker可以理解為訊息佇列伺服器,提供訊息的接收、儲存、拉取服務。

  • broker對於equeue來說是核心,它絕對不能掛,一旦掛了,那producer,consumer就無法實現publish-subscribe了。

NameServer(命名服務)

客戶端尋找NameServer地址的方式
  1. 程式碼中指定NameServer地址;

  2. java啟動引數中指定NameServer地址:-Drocketmq.nameerv.addr

  3. 環境變數指定NameServer地址:NAMESRV_ADDR

  4. HTTP靜態伺服器定址,客戶端啟動後,會定時訪問一個靜態HTTP伺服器,該URL返回NameServer地址列表。推薦使用HTTP靜態伺服器定址方式,對於客戶端部署簡單,而且NameServer叢集可以熱升級。

訊息過濾的方式

  1. 簡單訊息過濾。訂閱時指定topic下面tags;

  2. 高階訊息過濾。

    • Broker所在的機器會啟動多個FilterServer過濾程式;

    • Consumer啟動後,會向FilterServer上傳一個過濾的Java類;

    • Consumer從FilterServer拉訊息,FilterServer將請求轉發給Broker,FilterServer從Broker收到訊息後,按照Consumer上傳的java過濾程式做過濾,過濾完成後返回給Consumer。

兩種方式的總結:
  • 使用CPU資源來換取網路卡流量資源;

  • FilterServer與Broker部署在同一臺機器,資料通過本地迴環通訊,不走網路卡;

  • 一臺Broker部署多個FilterServer,充分利用CPU資源,因為單個JVM難以全面利用高配的物理機CPU資源;

  • 因為過濾程式碼使用Java編寫,應用幾乎可以做任意形式的伺服器端訊息過濾,例如通過Messgae Header進行過濾,甚至可以按照Message Body進行過濾;

  • 使用Java語言進行作為過濾表示式是一個雙刃劍,方便了應用的過濾操作,但是帶來了伺服器端的安全風險。需要應用來保證過濾程式碼安全,例如在過濾程式中儘可能不做申請大記憶體,建立執行緒等操作,避免Broker伺服器發生資源洩露。

傳送訊息注意事項

  1. 應用盡可能用一個Topic,訊息子型別用tags來標識,tags可以由應用只有設定。只有傳送訊息設定了tags,消費方在訂閱訊息時,才可以利用tags在broker做訊息過濾;

  2. 每個訊息在業務層面的唯一標識碼,要設定到keys欄位,方便將來定位訊息丟失問題。伺服器會為每個訊息建立索引,應該可以通過topic、key來查詢這條訊息內容以及訊息被誰消費,由於雜湊索引,請務必保證key儘可能唯一。

  3. 訊息傳送成功或者失敗,要列印訊息日誌,務必輸出sendResult和key欄位;

  4. send訊息方法,只要不拋異常,就代表傳送成功,但是傳送成功會有多個狀態,在sendResult裡定義。

傳送資訊的結果狀態
  • SEND_OK:訊息傳送成功;

  • FLUSH_DISK_TIMEOUT:訊息傳送成功,但是伺服器刷盤超時,訊息已經進入伺服器佇列,只有此時伺服器當機,訊息才會丟失;

  • FLUSH_SLAVE_TIMEOUT:訊息傳送成功,但是伺服器同步到slave時超時,訊息已經進入伺服器佇列,只有此次伺服器當機,訊息才會丟失;

  • SLAVE_NOT_AVAILABLE:訊息傳送成功,但是此時slave不可用,訊息已經進入伺服器佇列,只有此時伺服器當機,訊息才會丟失;

消費資訊注意事項

叢集消費

叢集消費是指,一個consumer group下的consumer,平均消費topic下的queue。

  • 假如一個topic下有4個queue,然後當前有一個consumer group,該分組下有4個consumer,那每個consumer就被分配到該topic下的一個queue,這樣就達到了平均消費topic下的queue的目的。

  • 如果consumer group下只有兩個consumer,那每個consumer就消費2個queue。

  • 如果有3個consumer,則第一個消費2個queue,後面兩個每個消費一個queue,從而達到儘量平均消費。

應該儘量讓consumer group下的consumer的數目和topic的queue的數目一致或成倍數關係。這樣每個consumer消費的queue的數量總是一樣的,這樣每個consumer伺服器的壓力才會差不多。當前前提是這個topic下的每個queue裡的訊息的數量總是差不多多的。這點我們可以對訊息根據某個使用者自己定義的key來進行hash路由來保證。

廣播消費

廣播消費是指一個consumer只要訂閱了某個topic的訊息,那它就會收到該topic下的所有queue裡的訊息,而不管這個consumer的group是什麼。所以對於廣播消費來說,consumer group沒什麼實際意義。consumer可以在例項化時,我們可以指定是叢集消費還是廣播消費。

對於叢集消費和廣播消費,消費進度持久化的地方是不同的,叢集消費的消費進度是放在broker,也就是訊息佇列伺服器上的,而廣播消費的消費進度是儲存在consumer本地磁碟上的。

叢集消費目的
  • 由於一個queue的消費者可能會更換,因為consumer group下的consumer數量可能會增加或減少,然後就會重新計算每個consumer該消費的queue是哪些,所以,當出現一個queue的consumer變動的時候,新的consumer如何知道該從哪裡開始消費這個queue呢?

如果這個queue的消費進度是儲存在前一個consumer伺服器上的,那就很難拿到這個消費進度了,因為有可能那個伺服器已經掛了,或者下架了,都有可能。而因為broker對於所有的consumer總是在服務的,所以,在叢集消費的情況下,被訂閱的topic的queue的消費位置是儲存在broker上的,儲存的時候按照不同的consumer group做隔離,以確保不同的consumer group下的consumer的消費進度互補影響。

廣播消費目的

廣播消費,由於不會出現一個queue的consumer會變動的情況,所以我們沒必要讓broker來儲存消費位置,所以是儲存在consumer自己的伺服器上。

消費進度(offset)

消費進度是指,當一個consumer group裡的consumer在消費某個queue裡的訊息時,equeue是通過記錄消費位置(offset)來知道當前消費到哪裡了。以便該consumer重啟後繼續從該位置開始消費。

比如一個topic有4個queue,一個consumer group有4個consumer,則每個consumer分配到一個queue,然後每個consumer分別消費自己的queue裡的訊息。

equeue會分別記錄每個consumer對其queue的消費進度,從而保證每個consumer重啟後知道下次從哪裡開始繼續消費。

實際上,也許下次重啟後不是由該consumer消費該queue了,而是由group裡的其他consumer消費了,這樣也沒關係,因為我們已經記錄了這個queue的消費位置了。

消費位置和consumer其實無關,消費位置完全是queue的一個屬性,用來記錄當前被消費到哪裡了。另外一點很重要的是,一個topic可以被多個consumer group裡的consumer訂閱。

不同consumer group裡的consumer即便是消費同一個topic下的同一個queue,那消費進度也是分開儲存的。也就是說,不同的consumer group內的consumer的消費完全隔離,彼此不受影響。

相關文章