再談訊息佇列技術-轉

giserinchina發表於2018-09-25

再談訊息佇列技術

上週,我們舉辦了第二屆技術沙龍,我這邊主要演講了訊息佇列技術的議題,現分享給大家:

在我們團隊內部,隨著訊息應用中心(任務中心)的廣泛應用,有時候我們感覺不到訊息佇列的存在,但這不影響訊息佇列在高可用、分散式、高併發架構下的核心地位。

訊息佇列都應用到了哪些實際的應用場景中?

一、再談訊息佇列的應用場景

  1. 非同步處理:例如簡訊通知、終端狀態推送、App推送、使用者註冊等
  2. 資料同步:業務資料推送同步
  3. 重試補償:記賬失敗重試
  4. 系統解耦:通訊上下行、終端異常監控、分散式事件中心
  5. 流量消峰:秒殺場景下的下單處理
  6. 釋出訂閱:HSF的服務狀態變化通知、分散式事件中心
  7. 高併發緩衝:日誌服務、監控上報

但是,我們對訊息佇列的底層技術和原理還是不瞭解,那麼我們馬上開始吧…

二、訊息佇列的一些基本概念和簡單原理

1. Broker

Broker的概念來自與Apache ActiveMQ,通俗的講就是MQ的伺服器。

2. 訊息的生產者、消費者

訊息生產者Producer:傳送訊息到訊息佇列。

訊息消費者Consumer:從訊息佇列接收訊息。

3. 點對點訊息佇列模型

訊息生產者向一個特定的佇列傳送訊息,訊息消費者從該佇列中接收訊息;

訊息的生產者和消費者可以不同時處於執行狀態。

每一個成功處理的訊息都由訊息消費者簽收確認(Acknowledge)。如圖:

4. 釋出訂閱訊息模型-Topic

釋出訂閱訊息模型中,支援向一個特定的主題Topic釋出訊息,0個或多個訂閱者接收來自這個訊息主題的訊息。在這種模型下,釋出者和訂閱者彼此不知道對方。實際操作過程中,

釋出訂閱訊息模型中,支援向一個特定的主題Topic釋出訊息,0個或多個訂閱者接收來自這個訊息主題的訊息。在這種模型下,釋出者和訂閱者彼此不知道對方。實際操作過程中,

必須先訂閱,再傳送訊息,而後接收訂閱的訊息,這個順序必須保證。

5. 訊息的順序性保證

基於Queue訊息模型,利用FIFO先進先出的特性,可以保證訊息的順序性。

6. 訊息的ACK確認機制

即訊息的Ackownledge確認機制,

為了保證訊息不丟失,訊息佇列提供了訊息Acknowledge機制,即ACK機制,當Consumer確認訊息已經被消費處理,傳送一個ACK給訊息佇列,此時訊息佇列便可以刪除這個訊息了。如果Consumer當機/關閉,沒有傳送ACK,訊息佇列將認為這個訊息沒有被處理,會將這個訊息重新傳送給其他的Consumer重新消費處理。

7. 訊息的持久化

訊息的持久化,對於一些關鍵的核心業務來說是非常重要的,啟用訊息持久化後,訊息佇列當機重啟後,訊息可以從持久化儲存恢復,訊息不丟失,可以繼續消費處理。

8. 訊息的同步和非同步收發

同步:訊息的收發支援同步收發的方式。

同時還有另一種同步方式:同步收發場景下,訊息生產者和消費者雙向應答模式,例如:張三寫封信送到郵局中轉站,然後李四從中轉站獲得信,然後在寫一份回執信,放到中轉站,然後張三去取,當然張三寫信的時候就得寫明回信地址

訊息的接收如果以同步的方式(Pull)進行接收,如果佇列中為空,此時接收將處於同步阻塞狀態,會一直等待,直到訊息的到達。

非同步:訊息的收發同樣支援非同步方式:非同步傳送訊息,不需要等待訊息佇列的接收確認;非同步接收訊息,以Push的方式觸發訊息消費者接收訊息。

9. 訊息的事務支援

訊息的收發處理支援事務,例如:在任務中心場景中,一次處理可能涉及多個訊息的接收、處理,這處於同一個事務範圍內,如果一個訊息處理失敗,事務回滾,訊息重新回到佇列中。

三、我們對訊息佇列的實際使用

我們使用了兩種訊息佇列元件:

RabbitMQ:高可用、高可靠訊息應用場景,例如記賬失敗重試、通知服務,訊息不允許丟

Kafka:高效能訊息應用場景,例如日誌、監控,訊息允許丟失。

在此之上,我們封裝了訊息應用中心、日誌服務等核心元件和服務。那麼,訊息應用中心和日誌都用到了訊息佇列什麼技術? 乾貨來了…

1.     訊息應用中心

訊息應用中心(任務中心)使用了訊息佇列的非同步處理、資料同步、重試補償、系統解耦、流量消峰等特性。其中:

訊息應用中心(任務中心),支援RabbitMQ和Kafka兩種訊息通道,支援在任務後設資料層面設定

任務:就是一個包含了任務執行上下文的訊息,同時代表了非同步處理

任務傳送者(ITaskSender)傳送任務:訊息的生產者將任務訊息傳送的訊息佇列

任務型別:訊息佇列名稱,例如:HaKeepAcco***Queue,充電補償記賬佇列

訊息佇列:任務的臨時儲存

任務中心:任務集中處理,訊息消費者

任務處理完成:訊息Ack確認

任務的多級重試:多個重試訊息佇列,HaSysTaskStore2Queue

2.     日誌元件

日誌元件,使用了訊息佇列的高併發緩衝和釋出訂閱特性。其中:

日誌元件使用Kafka作為訊息通道,因為Kafka的效能好,吞吐量大, 可以容忍偶爾的訊息資料丟失

日誌元件使用釋出訂閱的訊息模型

日誌元件包含日誌服務SDK和日誌HSF服務,二者都是訊息的生產者Producer

日誌型別:訊息的Topic主題

日誌處理器:訊息的消費者、Topic的訂閱、日誌資料處理(Hbase\ES\其他)

3.     RPC服務狀態變化通知

RPC服務狀態變化通知,使用了訊息佇列的釋出訂閱特性。其中:

RPC服務狀態變化通知,使用了RabbitMQ訊息佇列技術

使用釋出訂閱的訊息模型

Topic:RPCServiceState

RPCService.Proxy:RPC服務狀態變化訊息的訂閱者

RPC服務註冊、釋出:訊息的生產者,傳送RPC服務狀態變化訊息。

四、訊息佇列使用的最佳實踐

1.  RabbitMQ的連線,底層都是Socket連線,長連線 or 短連線?

RabbitMQ每個在建立每個連線的同時,會自動建立一個監視執行緒來定時(預設60s)偵測連線的狀態,如果連線斷開,觸發ConnectionShutdown事件。

    用長連線,還是用短連線??

    傳送端:建議使用短連線,用完即釋放,避免長連線帶來的埠占用,因為傳送端無處不在,傳送操作短而急促。

接收端:建議使用長連線,時刻接收處理訊息,因為訊息的接收消費比較集中,接收操作久而彌堅。

2. 網路是有抖動的,連線的斷開是正常的,如何應對?

    傳送端:傳送失敗重試

接收端:註冊ConnectionShutdown事件同時捕獲訊息接收異常,重新建立連線,接收消費訊息

3. RabbitMQ Exchange(Topic)模式下帶來的訊息佇列數量激增

    只是建立了一個Exchange(Topic),為什麼會增加這麼多Queue。

   因為,每個Topic的訂閱都是繫結一個Queue用作訊息的消費。

4. 需求的演變,訊息結構的變更,如何平滑過度?

    訊息是byte[]陣列,我們將複雜物件訊息二進位制序列化。

    接收到訊息後,我們將二進位制陣列反序列化為實體類。

    當我們的實體類訊息體的結構發生變化後,因為受二進位制序列化處理的

影響,導致無法反序列化。

    解決方案:

    訊息體預留一些string型別的擴充套件欄位

   訊息佇列版本化,支援多個版本的訊息體。

5. Kafka Consumer Group

   同一Topic的一條訊息只能被同一個Group內的一個Consumer消費

   多個Consumer Group可同時消費同一條訊息

   

6. 訊息的積壓

訊息的積壓產生的原因:訊息接收消費的速率低,傳送的速度>接收的速度。

訊息積壓後的影響:

訊息大量積壓後,當新的消費者連線上MQ並開始接收訊息時,傳送速率會大幅降低。

訊息佇列叢集的壓力增加,大量的訊息要持久化儲存和同步。

如何減少訊息積壓:快速消費訊息,同時保持訊息體的不要過大

https://www.cnblogs.com/tianqing/p/7110468.html

相關文章