1. 程式人生 > >「訊息佇列」訊息佇列概述與AMQP協議

「訊息佇列」訊息佇列概述與AMQP協議

轉載請註明出處:https://blog.csdn.net/jinixin/article/details/83552185

 

 

前面幾篇文章中談了rpc服務, rpc可用於程序間通訊, 使應用得以解耦, 而程序間通訊還可使用訊息佇列來完成.

本篇文章就簡單談談訊息佇列, 以及其所遵守的AMQP協議.

 

 

訊息佇列的定義

 

訊息佇列, 從字面上看其必和佇列有一定關係. 而佇列想必大家也都有所瞭解, 其是一種基本的資料結構, 先入先出, 可以起到暫存資料, 共享資料的作用. 訊息佇列和前面的佇列類似, 只是其額外還支援資料持久化, 處理確認, 流量控制, 跨伺服器投遞等功能.

官方定義訊息佇列(Message Queue)是一種程序間通訊或同一程序不同執行緒間通訊的方式. 訊息佇列提供了非同步的通訊協議, 資料傳遞是單向的, 傳送者向訊息佇列中不斷寫入訊息, 消費者不斷從訊息佇列中讀取訊息. 釋出者與消費者不用同時與佇列互動, 佇列可以持久的儲存訊息.

 

 

訊息佇列的組成

 

訊息佇列大體可分成三部分: 訊息生產者(Producer) --> 訊息代理(Broker) --> 訊息消費者(Consumer), 其中的"-->"表示訊息的流動方向, 訊息在訊息佇列中只可以單向流動. 其中的訊息代理是由交換機, 繫結和佇列所組成的, 具體可見下圖.

訊息佇列大致組成

 

 

訊息佇列的作用

 

1. 降低耦合, 減少服務間的依賴, 連線不同平臺或語言

2. 將同步變為非同步, 增加系統吞吐量, 縮短響應時間

3. 削弱峰值, 抗住壓力, 防止奔潰

4. 便於服務實現分散式與橫向擴充套件

 

談到訊息佇列就不得不提AMQP協議, 許多市面上流行的訊息佇列都是圍繞該協議來構建的, 該協議為非同步訊息處理提供了一種標準.

 

 

AMQP協議

 

AMQP即高階訊息佇列協議(Advanced Message Queuing Protocol), 其是一種開源的, 基於TCP的應用層協議

. 該協議的設計目的是為擺脫商業訊息佇列高昂的授權費用, 併為不同訊息佇列產品提供統一的介面標準.

AMQP指出訊息佇列主要由訊息生產者, 訊息代理(交換機, 繫結, 佇列), 訊息消費者所構成. 訊息由訊息生產者建立, 經訊息代理流向訊息消費者. 下面將介紹訊息的構成, 訊息生產者與消費者, 訊息代理, 訊息持久化與訊息確認機制.

 

1. 訊息的構成

訊息由訊息屬性與有效載荷(Payload)兩部分組成.

1) 有效載荷

有效載荷也就是要傳輸的資料, 訊息代理(下面介紹)不會對其進行檢查或修改.

2) 訊息屬性

訊息屬性類似於HTTP協議的頭部, 其包含交換機名字(用於決定訊息被髮送到的交換機), 內容型別, 內容編碼, 路由鍵, 投遞模式(是否持久化), 訊息優先權(優先佇列), 訊息時間戳, 訊息有效期等欄位.

3) 訊息持久化

訊息持久化即斷電後訊息是否丟失. 某條訊息是否持久化是通過訊息屬性中的"投遞模式"欄位來決定的. 如果不設定該欄位, 而只是將訊息傳送給持久化交換機或是路由到持久化佇列是不會使該訊息具有持久化特質的.

 

2. 訊息生產者

根據有效載荷建立訊息(設定訊息屬性), 並將訊息交給訊息代理.

 

3. 訊息消費者

從訊息代理那兒接收訊息中的有效載荷, 注意其只關心有效載荷而不接收訊息屬性.

AMQP支援主動推送訊息給應用(push), 以及應用主動獲取訊息(pull). 採用push時, 應用需顯示的表明其對哪個佇列的訊息感興趣, 我們稱之為應用訂閱了某佇列, 或註冊了某消費者.

 

4. 訊息代理

訊息代理(Broker)一般由交換機, 繫結和佇列所構成. 利用虛擬化技術, 還可以產生虛擬主機這一層級.

1) 連線與通道

訊息代理一般可與釋出者和消費者保持長連線, 該連線基於TCP, 支援TLS(SSL)加密.

為解決生產者或消費者大量併發連線訊息代理的問題, 引入了通道的概念. 通道是建立在TCP連線內的虛擬連線, 通過多路複用技術, 多個通道可共享一個TCP連線, 從而避免大量建立TCP連線時資源的消耗. 同個連線下的不同通道間傳輸資料時互不影響, 因此建議多個執行緒或程序共享一個連線, 但每個執行緒或程序獨享連線下的一個通道.

 

2) 虛擬主機

訊息佇列通過虛擬化技術, 可以在一個訊息代理上實現多個隔離的環境, 使每個環境都有獨立的使用者組, 交換機和佇列, 該環境被稱為虛擬主機(Virtual Host). 這個類似於作業系統中物理機和虛擬機器, 以及程式語言中名稱空間的概念.

訊息佇列詳細組成

 

3) 交換機

生產者實際將訊息傳送到訊息代理的交換機(Exchange)上, 交換機接收並排序這些訊息, 再按一定規則將它們分別轉發(路由)到對應佇列上. 這裡的一定規則主要取決於兩個條件, 其一是交換機型別, 其二是訊息所攜帶的路由鍵屬性, 具體例子在"交換機型別"那兒介紹.

訊息代理被建立後會自動宣告一個預設交換機, 其型別為直連交換機(下面介紹), 每個新建的佇列都會自動繫結到該交換機上, 繫結的路由鍵與佇列名是一致的.

[1] 路由鍵與繫結鍵

路由鍵存在於訊息中, 用於告知交換機將其轉發(路由)到哪條佇列上. 路由鍵形式為字串, 可被"."分隔成多個單詞, 一個訊息僅能有一個路由鍵.

繫結鍵存在於佇列中, 用於告知交換機自己接收哪種型別的訊息. 繫結鍵形式為字串, 可被"."分隔成多個單詞, 一條佇列能有多個繫結鍵.

[2] 交換機型別

訊息具體轉發規則是由交換機型別決定的, 交換機分為四種類型: 直連交換機, 主題交換機, 扇形交換機和頭交換機. 主要關注前三個, 最後一個不常用.

直連交換機 (direct, 類似網路裡的"單播"): 一個攜帶"XX"路由鍵的訊息被髮給直連交換機後, 直連交換機會將其轉發給所有具有"XX"繫結鍵的佇列.

扇形交換機 (fanout, 類似網路裡的"廣播"): 交換機將接收到的訊息轉發給繫結到該交換機上的所有佇列, 不管路由鍵與繫結鍵是否匹配.

主題交換機 (topic, 類似網路裡的"組播"): 類似於直連交換機, 但匹配規則不是"XX"路由鍵與"XX"繫結鍵完全匹配, 而是隻要符合類似正則匹配即可. 具體規則如下:  繫結鍵中的"#"可替換零個或多個單詞, "*"只替換一個單詞(注意是單詞, 不是字元). 當繫結鍵僅為"#"時, 就成了扇形交換, 而當繫結鍵中沒有使用"#"或"*"時, 就成了直連交換.

舉個例子, 佇列1的繫結鍵為"*.red.*", 佇列2的繫結鍵為"monkey.#"和"*.*.fat":
路由鍵為"monkey.red.thin"的訊息會轉發給佇列1與佇列2;
路由鍵為"monkey.blue.fat"的訊息會轉發給佇列2, 且僅會被轉發一次, 雖然匹配中了兩次佇列2的繫結鍵;
路由鍵為"red"的訊息因沒有匹配到合適佇列, 會被丟棄.

[3] 交換機狀態

分為"持久"和"暫存"兩種狀態, 區別在於"持久交換機"在訊息代理重啟後依舊存在, "暫存交換機"在代理重啟後需被重新宣告.

 

4) 佇列

佇列(Queue)用於在消費者消費訊息前儲存從交換機那兒接收到的訊息.

佇列狀態和交換機一樣, 也分為"持久"和"暫存"兩種. "持久佇列"在訊息佇列重啟後依舊存在, 而"暫存佇列"則需被重新宣告.

 

5) 繫結

將佇列掛到指定交換機下的操作被稱為繫結(binding), 交換機將訊息轉發給佇列時所參照的規則被稱為繫結規則. 繫結連線了交換機和佇列兩個實體, 其依賴於訊息中的路由鍵與佇列上的繫結鍵.

 

5. 訊息確認機制

為確保訊息不丟失, 訊息代理支援兩種確認模式: 其一是訊息轉發給消費者後立即自動確認, 即自動確認模式. 其二是等待消費者自己傳送確認, 即手動確認模式. 無論是哪種模式, 消費者都需要告訴訊息代理自己已收到該訊息, 之後訊息代理便可自由刪除該訊息.

當一名消費者die後(如通道或連線被關閉, 底層TCP丟失等), 訊息代理會將已傳送給該消費者且未收到確認的訊息重新放入佇列中, 如果有其他消費者線上, 這些訊息會立即轉發給他們處理.

注意確認訊息必須在相同的通道上傳送, 請不要使用新的或其它通道. 如果你開啟了手動訊息確認, 但在訊息處理後卻一直忘記確認, 那麼訊息會不停的重發, 這不僅在一定程度上造成訊息混亂, 而且訊息佇列還會不斷吃記憶體, 情況將變得很危險.

 

6. 訊息佇列工作流程

簡單來說工作流程就是生產者將有效載荷(真正的資料)封裝成訊息包, 然後傳送給訊息代理, 而訊息代理依據一定規則將訊息轉發(路由)給消費者.

更具體來說工作流程則是生產者將訊息傳遞給訊息代理上的交換機, 交換機根據訊息裡的路由鍵以及自己的型別, 將該訊息轉發(路由)到對應佇列上, 最後消費者會從其關心(訂閱)的佇列中取得有效載荷並處理.

為應對上面流程中出現的異常, AMQP通過訊息確認機制來保證送達, 只有當消費者向訊息代理髮送"收到確認(ACK)"後, 訊息代理才會從佇列中刪除該訊息.

 

 

總結

 

AMQP協議的核心是訊息代理, 訊息代理則可簡單認為是由交換機, 佇列, 繫結所組成的.

AMQP所指導的訊息佇列已為我們實現了三大主體(交換機, 佇列以及如何繫結), 但轉發(路由)方案需要我們自己實現, 路由演算法由交換機型別和繫結規則共同決定.

 

文中如有不當之處, 還望包容和指出, 感謝.