前言
這是相關技能的詳解系列,是將東西整理歸納總結,系列的進行記錄與分享,這種方式更有完善性,更能成體系的學習一個技能,方便我們掌握他,這也是我們這種系列的目標,希望在跟着學習了解完這個系列后,就能將其吸收為自己的東西。並且為后續的繼續深入,打下一個基礎。
后續我也將更多的將以前零散的東西整理成多個不同的系列,有序的完善整體的知識樹。與大家共同學習共同成長
話不多說,下面進入正文
RabbitMQ是什么
什么是消息中間件
消息中間件是基於隊列與消息傳遞技術,在網絡環境中為應用系統提供同步或異步以及可靠的消息傳輸的支撐性軟件系統,
一般在系統開發中,常用於將程序解藕,異步,在分布式環境下擴展進程間的通信等。MQ典型應用場景例如:
- 異步處理。把消息放入消息中間件中,等到需要的時候再去處理。
- 流量削峰。例如秒殺活動,在短時間內訪問量急劇增加,使用消息隊列,當消息隊列
滿了就拒絕響應,跳轉到錯誤頁面,這樣就可以使得系統不會因為超負載而崩潰。 - 日志處理
- 應用解耦。假設某個服務A需要給許多個服務(B、C、D)發送消息,當某個服務(例如B)不需要發送消息了,服務A需要改代碼再次部署;當新加入一個服務(服務E)需要服務A的消息的時候,也需要改代碼重新部署;另外服務A也要考慮其他服務掛掉,沒有收到消息怎么辦?要不要重新發送呢?是不是很麻煩,使用MQ發布訂閱模式,服務A只生產消息發送到MQ,B、C、D從MQ中讀取消息,需要A的消息就訂閱,不需要了就取消訂閱,服務A不再操心其他的事情,使用這種方式可以降低服務或者系統之間的耦合。
什么是AMQP
AMQP,即Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標准高級消息隊列協議,是應用層協議的一個開放標准,為面向消息的中間件設計。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件不同產品,不同的開發語言等條件的限制。Erlang中的實現有RabbitMQ等。
所以,總結為一句話就是,AMQP是一個開放的消息隊列標准協議!,而RabbitMQ就是此協議的一個開源實現,所以RabbitMQ與AMQP的協議中的概念是高度重合的。這在下面講到RabbitMQ的使用時,再詳說。
RabbitMQ是什么
RabbitMQ是當前最主流的消息中間件之一!RabbitMQ是一個開源的AMQP實現!
RabbitMQ服務器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用於在分布式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。
當然RabbitMQ除了實現了AMQP協議外,也同時支持MQTT,STOMP,AMQP1.0,HTTP 和 WebSocket等協議,以滿足不同場景下的使用。具體的可查看RAbbitMQ官方文檔
https://www.rabbitmq.com/protocols.html
RabbitMQ 使用與概念
PS: 所有學習都應該以官方文檔為准,所有博客信息都可能會有滯后性,不准確性。這也是我一直的准則,希望教會大家怎么看官方文檔,怎么自我學習。
下面要介紹的內容,也可以直接看官方文檔:https://www.rabbitmq.com/tutorials/amqp-concepts.html
RabbitMQ作為一個消息中間件,其中設計思路基本都來源於AMQP協議,主要有如下幾個重要的概念:
- Server:接收客戶端的連接,實現AMQP實體服務。
- Connection:連接,應用程序與Server的網絡連接,TCP連接。
- Channel:信道,消息讀寫等操作在信道中進行。客戶端可以建立多個信道,每個信道代表一個會話任務。
- Message:消息,應用程序和服務器之間傳送的數據,消息可以非常簡單,也可以很復雜。有Properties和Body組成。Properties為外包裝,可以對消息進行修飾,比如消息的優先級、延遲等高級特性;Body就是消息體內容。
- Virtual Host:虛擬主機,用於邏輯隔離。一個虛擬主機里面可以有若干個Exchange和Queue,同一個虛擬主機里面不能有相同名稱的Exchange或Queue。
- Exchange:交換器,接收消息,按照路由規則將消息路由到一個或者多個隊列。如果路由不到,或者返回給生產者,或者直接丟棄。RabbitMQ常用的交換器常用類型有direct、topic、fanout、headers四種,后面詳細介紹。
- Binding:綁定,交換器和消息隊列之間的虛擬連接,綁定中可以包含一個或者多個RoutingKey。
- RoutingKey:路由鍵,生產者將消息發送給交換器的時候,會發送一個RoutingKey,用來指定路由規則,這樣交換器就知道把消息發送到哪個隊列。路由鍵通常為一個“.”分割的字符串,例如“com.rabbitmq”。
- Queue:消息隊列,用來保存消息,供消費者消費。
其結構大致如下:
如圖,主要分為三部分:
- 生產者
- 消費者
- 服務端
整個消息的發布與消費的流程大致如下:
- 生產者client端指定服務端地址以及vhost虛擬主機,連接服務端
- 建立連接后,創建Channel信道,設置此信道的屬性。
- 通過信道,聲明交換機,隊列,綁定關系,以及相關屬性
- 通過信道,發送Message消息到Exchange交換機
- 交換機通過binding綁定關系與RoutingKey路由鍵,將消息分發到對應的Queue隊列
- 消費者client通過服務端地址以及vhost連接服務端
- 建立連接后,創建信道,設置信道屬性
- 通過信道,開啟消費者監聽隊列,從隊列中獲取消息進行消費
- 根據是否延遲確認,確認消息已經被正常消費成功后,消息從隊列中刪除
Exchange交換機類型
在上述結構中,生產者發送消息,並不是直接發送到隊列的,而是發送到Exchange交換機,再由交換機分發到相應隊列,沒有匹配到隊列則丟棄消息。根據Exchange的類型不同,可靈活實現常見的消息模式。
Exchange交換機共有四種類型:
- direct
- fanout
- topic
- headers
direct
Direct,完全匹配型交換機,此種類型交換機,通過RoutingKey路由鍵將交換機和隊列進行綁定, 消息被發送到exchange時,需要根據消息的RoutingKey,來進行匹配,只將消息發送到完全匹配到此RoutingKey的隊列。
如圖,不同的key綁定不同的隊列,實現不同消息分發至不同隊列。
PS: 注意同一個key,可以綁定多個queue隊列。如圖中,當匹配到key1時,則會將消息分發送至queue1和queue2,這樣兩個隊列都會有相同的消息數據。
fanout
Fanout,扇出類型交換機,此種交換機,會將消息分發給所有綁定了此交換機的隊列,此時RoutingKey參數無效。
此種方式,最簡單快速,性能最好,因為少了中間的匹配判斷環節。
topic
Topic,主題類型交換機,此種交換機與Direct類似,也是需要通過routingkey路由鍵進行匹配分發,區別在於Topic可以進行模糊匹配,Direct是完全匹配。
Topic中,將routingkey通過"."來分為多個部分,通過如下功能字符來進行匹配:
- "*":代表一個部分
- "#":代表一個或多個部分
舉個例子,加入綁定關系如下圖:
然后發送一條信息,routingkey為"a.b.c.d",那么根據"."將這個路由鍵分為了4個部分,此條路由鍵,將會匹配:
- a.b.c. :成功匹配,因為可以代表一個部分
- a.b.# :成功匹配,因為#可以代表一個或多個部分
- a..c.. : 成功匹配,因為第一和第三部分分別為a和c,且為4個部分,剛好匹配
-
.d : 成功匹配,因為最后一個部分為d,前面所有部分被#代表了
PS:如果綁定的路由鍵為 "#" 時,則接受所有消息,因為路由鍵所有都匹配
headers
Headers,headers信息類型交換機,此類型交換機不通過routingkey路由鍵來分發消息,而是通過消息內容中的headers屬性來進行匹配。headers類型交換器性能差,在實際中並不常用。
雖然不常用,但也可以了解一下其,此種交換機不通過routingkey,但是通過headers進行綁定,也就是在聲明binding綁定關系時,需要傳入需要匹配的header的key/value鍵值對。
如圖,綁定關系中,需要指定"x-match"匹配類型:
- all:需要所有的key-value都匹配,才能匹配成功
- any:只需要其中一個key-value匹配,就匹配成功
PS: 不常用,此種方式性能比較差,如果要使用此種方式,使用前可進行性能測試,確保符合業務場景的需求