科普 — 關于Rabbit MQ與AMQP協(xié)議概念,你想了解的都在這里...


導語
本文從AMQP協(xié)議(Advanced Message Queuing Protocol,高級消息隊列協(xié)議)、消息功能、消費模型、金融級用法及其他功能點對比等概念介紹對RabbitMQ做了科普, 希望對各位深入理解RabbitMQ有幫助。

AMQP協(xié)議概念
AMQP協(xié)議自身定義了很多概念,下面先對這些概念進行剖析,會更側重從每個概念實體的作用域、職責范圍、從屬關系等維度進行介紹。

AMQP協(xié)議概念實體圖
Connection

對應底層一個AMQP-Client到RabbitMQ-Broker的一個TCP連接。
這邊要考慮兩個端點問題,在TCP連接建立完成后,如下圖所示,連接的目標Broker就已經(jīng)確定是集群中的一臺了,由于是長連接,除非斷連重建,否則對端節(jié)點不可變。
所以從這里可以看出RabbitMQ相比Pulsar、RocketMQ不一樣的地方在于,其是一種服務端尋址模型,以Client的視角來看,想要連接任意Exchange、Queue,只要連上任意一臺Broker就行。
Channel
信道,可以理解為一種邏輯連接,體現(xiàn)了多路復用的設計思路。
支持串行執(zhí)行,包括收和發(fā)的指令,可以理解為一種半雙工模式的“虛擬網(wǎng)絡通道”。
所有Exchange、Queue、Binding的操作都是在Channel之上進行的。
Vhost
等價于一種租戶隔離概念,不同Vhost下可以創(chuàng)建同名Exchange、Queue,這樣可以進行業(yè)務隔離。
?RabbitMQ的權限隔離和權限控制的機制是在Vhost級別的。
Rabbit官方原生的全局Policy控制在Vhost級別。
Exchange
一個虛擬實體,聲明不同消息的路由策略,自身不存儲消息。
一個路由器,基于消息頭部的RoutingKey和Header將消息路由到符合條件的具體的Queue。
支持單播和廣播。
Queue
消息存儲實體,是消息底層存儲的容器,類似Pulsar的Topic。
單訂閱模式,其下的Consumer分別消費到一部分消息。
和存儲關聯(lián),因此有容量上限、ttl等存儲層的特性。
支持多消費和獨占消費,取決于你訂閱時設置的參數(shù)。由于它是存儲消息系統(tǒng)的消息,所以內(nèi)部基于一個消費位點控制持久化消費進度,記錄最后被消費并Ack的位置。
面向Consumer。
Binding
銜接Exchange和Queue的橋梁,本質(zhì)是一個規(guī)則的聲明。
?一個Exchange下可以有多個Binding。
一個Queue也可以被多個Binding關聯(lián)。
一個Exchange到一個Queue也可以聲明多個Binding。

消息功能
下面介紹RabbitMQ官方所提供的的開源原生功能,我們知道,AMQP協(xié)議可以看做成一種可編程式的消息隊列協(xié)議,可以基于其提供的基礎模型,通過自己的巧妙搭配組合,構造出多種多樣的業(yè)務模型。
消息結構

每個消息分為三個部分,在網(wǎng)絡層面即三個獨立數(shù)據(jù)幀:
PublishInfo: 消息路由聲明信息,可以聯(lián)想成寫電子郵件時填寫的目標郵箱、是否接收回執(zhí)等前置聲明。
HeaderBody: 消息頭部,用于存儲RabbitMQ自身事先定義的聲明,可以聯(lián)想層HTTP協(xié)議的Header一樣,此處可以放置一些對業(yè)務透明的上下文信息用于提供某種功能,比如分布式鏈路追蹤的TraceId。
ContentBody: 消息體,無差別二進制數(shù)據(jù)塊,服務端不感知其是否壓縮、是否加密等,只進行透明的存儲和讀取投遞。
work queue 工作隊列

它是一種模型簡化,發(fā)送消息時指定Exchange為空,RoutingKey為QueueName,Broker以后會直接把這個消息發(fā)送至目標Queue,這樣對用戶來說相當于沒Exchange,他認為是直接用Queue來消費,就比較簡單。
工作隊列只適用于單訂閱的場景,因為Queue只適用于單訂閱。
官方講解:https://www.rabbitmq.com/tutorials/tutorial-two-python.html
Publish/Subscribe 發(fā)布訂閱模式


Queue不支持多訂閱,通過轉換思路實現(xiàn):
一個Fanout類型的Exchange:相當于多訂閱場景的Topic。
多個不同的Queue:綁定到該Exchange,相當于多訂閱場景下的Subscription。
多個Consumer消費同一個Queue:常規(guī)場景多訂閱。
每個Consumer各自消費一個Queue:實例級別廣播。
官方講解:
https://www.rabbitmq.com/tutorials/tutorial-three-python.html
Routing 路由模式

路由模式是用Rabbit最常用的一種模式。
Producer發(fā)布了一個Exchange,這個Exchange的類型是Direct,在Message中指定RoutingKey,并設置一個非空的值,接下來聲明一些Queue,這些 Queue在聲明和綁定Exchange的時候,需要指定Binding,消息在路由的時候判斷消息里的RoutingKey和BindingKey是不是equal,如果是對等的就可以路由過來。
類似tag過濾的消息分發(fā)場景。
官方講解:https://www.rabbitmq.com/tutorials/tutorial-four-python.html
Topic 通配符模式

路由模式的升級版,支持通配符匹配。
Exchange類型為Topic。
匹配規(guī)則不是正則表達式,是AMQP自己的語法。
官方講解:https://www.rabbitmq.com/tutorials/tutorial-five-python.html
Header模式
不常用,匹配規(guī)則不基于RoutingKey,而是基于
HeaderBody.Properties.Headers中的鍵值對。
支持完全匹配所有鍵值對。
支持只匹配一個鍵值對。
RPC模式

RPC模式并不常用,基于回復隊列。
生產(chǎn)者和消費者采用一問一答的模式。
等價于RPC的Request-Response模型。
官方講解:https://www.rabbitmq.com/tutorials/tutorial-six-python.html

消費模型
消費模型也是使用一個消息系統(tǒng)所需要特別關心的一環(huán),在業(yè)務的使用過程中,更多地會關注一條消息從生產(chǎn)到投遞至消費者整個過程中都經(jīng)歷了什么,整個消息的聲明周期是如何閉環(huán)的?
下面主要從TDMQ RabbitMQ版的實現(xiàn)來剖析RabbitMQ協(xié)議的消息生命周期。
從消息的生命周期看待消費模型

已投遞未Ack:Consumer獨占,直到Consumer觸發(fā)Ack或者Consumer斷開。
Ack消息:標記已消費,位點前進。
Nack消息:底層操作等價于Ack,會根據(jù)配置轉發(fā)到死信Exchange,否則丟棄。
Requeue:消息放回隊頭,待下次投遞。
從內(nèi)部核心組件看消費模型

Queue:負責存儲原始消息數(shù)據(jù),按序存儲。
RedeliveryTracker:負責記錄Consumer端Requeue的消息,并觸發(fā)重新投遞,標識投遞次數(shù)。
Dispatcher:負責管理連接Queue的所有Consumer,負責消息的負載均衡、分發(fā)、進度管理等。
Limiter:QoS限流器,基于Unack數(shù)限流,而不是QPS,呼應上方消息生命周期。
Unack Tracker:跟蹤當前Channel中已投遞未Ack的消息。
從這張圖可以獲取那些信息?
一個Queue可以被不同Connection連接、被同一個Connection的不同channel連接。
一個Channel中可以啟動兩個Consumer連接同一個Queue。
QoS限流作用域為Channel,即一個Channel中創(chuàng)建的多個Consumer享有相同的配額。
如果BasicQoS Global設置為true,那么同一個Channel中的Consumer用盡配額,該Channel下的所有Consumer全部阻塞,無法接收新消息。
Unack追蹤器也是Channel作用域,故一個Channel關閉,被該Channel獨占的所有未Ack消息全部回收到Queue級別的跟蹤器,進行全局重投遞。
Basic指令集:?https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.qos
Consumer Prefetch:
https://www.rabbitmq.com/consumer-prefetch.html

金融級用法

消息確認:發(fā)送反饋,給予Producer發(fā)送成功的確認。
備選Exchange:發(fā)送成功的消息無法匹配任何binding的場景。
消息回退:消息無法匹配任何Binding時退回到Producer。
重投遞:網(wǎng)絡錯誤、Consumer端宕機、業(yè)務處理偶發(fā)錯誤等場景,重試消費恢復。
死信Exchange:業(yè)務多次重試、長時間無法成功,放入死信,待人工處理或者下一步的自動化修正or告警系統(tǒng)。

功能點對比
經(jīng)過上述說明,你應該能利用RabbitMQ的功能點,結合自己的業(yè)務場景組織一個相對合理的生產(chǎn)消費拓撲。除了上面提到的功能點,RabbitMQ本身還提供了很多其他功能,下面主要列舉一部分對比,可供參考和借鑒。
通道類
功能點 | 說明 | TDMQ支持情況 |
認證和授權 | 基于User/Password的登錄鑒權機制。 | 整合pulsar自身的JWT(role+token)機制進行對齊 |
連接協(xié)商機制 | 連接握手協(xié)商連接通信參數(shù)。 | 完全對齊RabbitMQ原生 |
認證和授權 | Vhost維度配置和User的權限關系。 | AMQP SDK使用層面完全對齊 |
限流協(xié)商機制(QoS) | 基于Unack數(shù)進行配額限制。 | 完全對齊RabbitMQ原生 |
注意:QoS機制RabbitMQ的實現(xiàn)是和標準AMQP協(xié)議有出入的,我們選擇對齊RabbitMQ而不是AMQP規(guī)范,我們也認為RabbitMQ的模式較合理,詳見https://www.rabbitmq.com/consumer-prefetch.html
Exchange類
功能點 | 說明 | TDMQ支持情況 |
Exchange綁定Exchange | RabbitMQ在AMQP協(xié)議上的擴展,使Exchange不局限于只綁定Queue,借此可以構建出更加復雜的拓撲邏輯基于User/Password的登錄鑒權機制。 | 暫未支持,排期中 |
死信Exchange | Queue的擴展參數(shù),用于Queue中丟棄消息時轉發(fā)至死信Exchange。 | 完全對齊RabbitMQ原生 |
備選Exchange | Exchange的擴展參數(shù),用于消息發(fā)送至Exchange時,無法匹配任何路由規(guī)則到下游Queue,轉發(fā)至備選Exchange。 | 完全對齊RabbitMQ原生 |
Queue類
功能點 | 說明 | TDMQ支持情況 |
優(yōu)先隊列 | 消息可設置優(yōu)先級,同時到達的消息可根據(jù)優(yōu)先級投遞,是一種局部性破壞先入先出機制的功能。 | 暫未支持,排期中 |
獨占隊列 | 聲明隊列只能被聲明的Connection實體所連接,通常和臨時隊列配合使用。 | 暫未支持,排期中 |
臨時隊列 | 隨機生成一個臨時隊列名,可用于當前進程專用,通常配合獨占隊列和AutoDelete一起使用。 | 暫未支持,排期中 |
回復隊列 | 用于聲明消息Producer處理完成后,向Producer進行回包的隊列,以此實現(xiàn)一問一答的通信模型。 | 暫未支持,排期中 |
TTL | 針對消息設置TTL(time to live),過期未投遞的消息將會被丟棄 or 進入死信。 | 目前支持vhost級別的TTL機制 |
鏡像隊列 | RabbitMQ為了解決單點儲存問題而引入的,為了實現(xiàn)隊列消息多副本存儲。 | TDMQ天然多副本分布式存儲,不需要該功能 |
收發(fā)機制類
功能點 | 說明 | TDMQ支持情況 |
消息確認 | 消息在Broker成功存儲后,回包Producer,進行發(fā)送成功確認。 | 完全對齊RabbitMQ原生 |
事務消息 | 消息確認功能出現(xiàn)前的發(fā)送確認機制,性能很差,不建議使用。 | 暫未支持,待定 |
延遲消息 | 消息發(fā)送成功后,延遲一定時間后才進行投遞。 | 完全對齊RabbitMQ原生 |
RPC | 基于回復隊列封裝出的一問一答模型,使用場景較少,建議用主流RPC框架。 | 暫未支持,待定 |
參考
RabbitMQ協(xié)議官方文檔:
https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf
RabbitMQ官方功能介紹:
https://www.rabbitmq.com/admin-guide.html
RabbitMQ協(xié)議指令集:
https://www.rabbitmq.com/amqp-0-9-1-reference.html
RabbitMQ官方教程:
https://www.rabbitmq.com/getstarted.html
RabbitMQ官方Demo:
https://github.com/rabbitmq/rabbitmq-tutorials

后記
通過這篇文章,希望能對RabbitMQ進行一定程度的科普,也從一個從0到1設計一個RabbitMQ Broker的開發(fā)的角度,淺析了一些RabbitMQ的一些消費模型細節(jié),補充點當前網(wǎng)絡上對這部分細節(jié)的缺漏,希望可以起到一些啟發(fā)作用。
后續(xù),我們將會著重分享,如何在apache pulsar生態(tài)上構建出一套完全對齊RabbitMQ協(xié)議的高性能、高可用、云原生消息隊列,相比原生RabbitMQ,我們有何優(yōu)勢,以及我們在過程中遇到的問題,產(chǎn)生的思考。
敬請期待~

掃描下方二維碼關注本公眾號,
了解更多微服務、消息隊列的相關信息!
解鎖超多鵝廠周邊!
