天天看點

RabbitMQ下的生産消費者模式與訂閱釋出模式

所謂模式,就是在某種場景下,一類問題及其解決方案的總結歸納。生産消費者模式與訂閱釋出模式是使用消息中間件時常用的兩種模式,用于功能解耦和分布式系統間的消息通信,以下面兩種場景為例:

資料接入 

假設有一個使用者行為采集系統,負責從App端采集使用者點選行為資料。通常會将資料上報和資料處理分離開,即App端通過REST API上報資料,後端拿到資料後放入隊列中就立刻傳回,而資料處理則另外使用Worker從隊列中取出資料來做,如下圖所示。

RabbitMQ下的生産消費者模式與訂閱釋出模式

這樣做的好處有:第一,功能分離,上報的API接口不關心資料處理功能,隻負責接入資料;第二,資料緩沖,資料上報的速率是不可控的,取決于使用者使用頻率,采用該模式可以一定程度地緩沖資料;第三,易于擴充,在資料量大時,通過增加資料處理Worker來擴充,提高處理速率。這便是典型的生産消費者模式,資料上報為生産者,資料處理為消費者。

事件分發 

假設有一個電商系統,那麼,使用者“收藏”、“下單”、“付款”等行為都是非常重要的事件,通常後端服務在完成相應的功能處理外,還需要在這些事件點上做很多其他處理動作,比如發送短信通知、記錄使用者積分等等。我們可以将這些額外的處理動作放到每個子產品中,但這并不是優雅的實作,不利于功能解耦和代碼維護。 

我們需要的是一個事件分發系統,在各個功能子產品中将對應的事件釋出出來,由對其感興趣的處理者進行處理。這裡涉及兩個角色:A對B感興趣,A是處理者,B是事件,由事件處理器完成二者的綁定,并向消息中心訂閱事件。服務子產品是後端的業務邏輯服務,在不同的事件點釋出事件,事件經過消息中心分發給事件處理器對應的處理者。整個流程如下圖所示。這邊是典型的訂閱釋出模式。

RabbitMQ下的生産消費者模式與訂閱釋出模式

  可以看到,生産消費者模式與訂閱釋出模式都離不開消息中間件來作為消息中轉站,開源的消息中間件有很多,各有優劣。本文将重點探讨RabbitMQ的特性,以及如何實作上述的兩種場景。

RabbitMQ核心概念

通信方式 

RabbitMQ是基于AMQP協定來實作的消息中間件。AMQP,類似于HTTP協定,也是一個應用層的協定,網絡層使用TCP來通信。是以,RabbitMQ也是典型的C-S模型,準确地說是C-S-C模型,因為伴随着RabbitMQ的使用,總是會有Producer與Consumer兩個Client和一個Broker Server。

RabbitMQ下的生産消費者模式與訂閱釋出模式

Client要與Server進行通信,就必須先建立連接配接,RabbitMQ中有Connection與Channel兩個概念,前者就是一個TCP連接配接,後者是在這個連接配接上的虛拟概念,負責邏輯上的資料傳遞,是以,為了節省資源,一般在一個用戶端中建立一個Connection,每次使用時再配置設定一個Channel即可。

消息體 

Message是RabbitMQ中的消息體概念。類似HTTP傳輸中,有header和body兩部分資料,Message中也有Attributes和Payload兩部分資料,前者是一些元資訊,後者是傳遞的消息資料實體。

消息投遞 

RabbitMQ下的生産消費者模式與訂閱釋出模式

那麼,具體實作時,如何完成這三者關系的綁定?總結起來是兩點:第一,在Consumer Worker中,聲明自己對哪個Exchange感興趣,并将自己的Queue綁定到自己感興趣的一組routing_key上,建立相應的映射關系;第二,在Producer中,将消息投遞一個Exchange中,并指明它的routing_key。由此可見,Queue這個概念隻是對Consumer可見,Producer并不關心消息被投遞到哪個Queue中。 

看過RabbitMQ的”Hello World”教程的童鞋可能會發現在那裡面的圖中并沒有看到Exchange和routing_key的蹤迹,但這并不意味着RabbitMQ可以支援直接将消息投遞到Queue中,而是在内部使用了預設的Exchange和routing_key了。預設情況下,RabbitMQ使用名稱為“amq.direct”的Direct Exchange,routing_key預設名字與Queue保持一緻。 

搞清楚上述概念,就不難了解Exchange的四種類型了。Direct、Fanout、Topic、Headers,差別在于如何将消息從Exchange投遞到Queue中。Direct使用具體的routing_key來投遞;Fanout則忽略routing_key,直接廣播給所有的Queue;Topic是使用模糊比對來對一組routing_key進行投遞;Headers也是忽略routing_key,使用消息中的Headers資訊來投遞。

消息可靠性 

不同于HTTP的同步通路,RabbitMQ中,Producer并不知道消息是否被可靠地投遞到了Consumer中處理。那麼,RabbitMQ是如何保證消息的可靠投遞?主要是兩點:第一,消息确認機制。Consumer處理完消息後,需要發送确認消息給Broker Server,可以選擇“确認接收”、“丢棄”、“重新投遞”三種方式。如果Consumer在Broker Server收到确認消息之前挂了,Broker Server便會重新投遞該消息。第二,可以選擇資料持久化,這樣即使RabbitMQ重新開機,也不會丢失消息。

生産消費者模式

  搞清楚了RabbitMQ的核心概念,要針對特定的場景來設計使用方案就很簡單了,基本上就是上述RabbitMQ架構圖的變遷。讓我們先來看看文章開頭提到的“資料接入”場景,如何實作生産消費者模式。 

RabbitMQ下的生産消費者模式與訂閱釋出模式

這裡增加了一下場景複雜度:對于上報的資料,如果是special的行為,需要優先處理。從上圖可以看到,資料上報端負責将資料投遞到RabbitMQ對應的Exchange,并指明routing_key是common還是special。資料處理端,可以根據情況啟多個Woker來消費資料,但至少需要兩個,一個用來處理common資料,一個用來處理special的資料。注意:當需要增加多個Worker來消費同一類資料時,需要保持Queue名字一緻,比如上面的Common資料。

訂閱釋出模式

  再來看“事件分發”的場景,架構如下圖所示,使用event name/id來作為RabbitMQ的routing key的名字。Event Processor 01對event 01 和event 02感興趣,則在啟動Consumer Worker時,将自己的Queue綁定到這兩個routing key上即可,其他Event Processor也是如此,這樣便完成了事件的訂閱。當有事件釋出時,消息便會按照event name/id被投遞到對應的Queue中。 

RabbitMQ下的生産消費者模式與訂閱釋出模式

  由此可見,在不同的應用中,變化的隻是routing_key與Consumer Queue的綁定關系,在充分了解RabbitMQ的核心概念後處理這些應該也是得心應手了。

出處:http://blog.csdn.net/zwgdft/article/details/53561277

繼續閱讀