RabbitMQ訊息佇列名詞解釋[轉]

來源:互聯網
上載者:User

標籤:

從AMQP協議可以看出,MessageQueue、Exchange和Binding構成了AMQP協議的核心,下面我們就圍繞這三個主要組件    從應用使用的角度全面的介紹如何利用Rabbit MQ構建訊息佇列以及使用過程中的注意事項。

  

 

 

1. 聲明MessageQueue

      在Rabbit MQ中,無論是生產者發送訊息還是消費者接受訊息,都首先需要聲明一個MessageQueue。這就存在一個問題,是生產者聲明還是消費者聲明呢?要解決這個問題,首先需要明確:

a)消費者是無法訂閱或者擷取不存在的MessageQueue中資訊。

b)訊息被Exchange接受以後,如果沒有匹配的Queue,則會被丟棄。

在明白了上述兩點以後,就容易理解如果是消費者去聲明Queue,就有可能會出現在聲明Queue之 前,生產者已發送的訊息被丟棄的隱患。如果應用能夠通過訊息重發的機制允許訊息丟失,則使用此方案沒有任何問題。但是如果不能接受該方案,這就需要無論是 生產者還是消費者,在發送或者接受訊息前,都需要去嘗試建立訊息佇列。這裡有一點需要明確,如果用戶端嘗試建立一個已經存在的訊息佇列,Rabbit MQ不會做任何事情,並返回用戶端建立成功的。

       如果一個消費者在一個通道中正在監聽某一個隊列的訊息,Rabbit MQ是不允許該消費者在同一個channel去聲明其他隊列的。Rabbit MQ中,可以通過queue.declare命令聲明一個隊列,可以設定該隊列以下屬性:

a) Exclusive: 排他隊列,如果一個隊列被聲明為排他隊列,該隊列僅對首次聲明它的串連可見,並在串連斷開時自動刪除。這裡需要注意三點:其一,排他隊列是基於串連可見 的,同一串連的不同通道是可以同時訪問同一個串連建立的排他隊列的。其二,“首次”,如果一個串連已經聲明了一個排他隊列,其他串連是不允許建立同名的排 他隊列的,這個與普通隊列不同。其三,即使該隊列是持久化的,一旦串連關閉或者用戶端退出,該排他隊列都會被自動刪除的。這種隊列適用於只限於一個用戶端 發送讀取訊息的應用情境。

b)   Auto-delete:自動刪除,如果該隊列沒有任何訂閱的消費者的話,該隊列會被自動刪除。這種隊列適用於暫存佇列。

c)   Durable:持久化,這個會在後面作為專門一個章節討論。

d)  其他選項,例如如果使用者僅僅想查詢某一個隊列是否已存在,如果不存在,不想建立該隊列,仍然可以調用queue.declare,只不過需要將參數passive設為true,傳給queue.declare,如果該隊列已存在,則會返回true;如果不存在,則會返回Error,但是不會建立新的隊列。

2. 生產者發送訊息

        在AMQP模型中,Exchange是接受生產者訊息並將訊息路由到訊息佇列的關鍵組件。ExchangeType和Binding決定了訊息的路由規 則。所以生產者想要發送訊息,首先必須要聲明一個Exchange和該Exchange對應的Binding。可以通過 ExchangeDeclare和BindingDeclare完成。在Rabbit MQ中,聲明一個Exchange需要三個參數:ExchangeName,ExchangeType和Durable。ExchangeName是該 Exchange的名字,該屬性在建立Binding和生產者通過publish推送訊息時需要指定。ExchangeType,指Exchange的類 型,在RabbitMQ中,有三種類型的Exchange:direct ,fanout和topic,不同的Exchange會表現出不同路由行為。Durable是該Exchange的持久化屬性,這個會在訊息持久化章節討 論。聲明一個Binding需要提供一個QueueName,ExchangeName和BindingKey。下面我們就分析一下不同的 ExchangeType表現出的不同路由規則。

        生產者在發送訊息時,都需要指定一個RoutingKey和Exchange,Exchange在接到該RoutingKey以後,會判斷該ExchangeType:

                         a) 如果是Direct類型,則會將訊息中的RoutingKey與該Exchange關聯的所有Binding中的BindingKey進行比較,如果相等,則發送到該Binding對應的Queue中。


                  b) 如果是Fanout類型,則會將訊息發送給所有與該Exchange定義過Binding的所有Queues中去,其實是一種廣播行為。
          

        c)如果是Topic類型,則會按照Regex,對RoutingKey與BindingKey進行匹配,如果匹配成功,則發送到對應的Queue中。

            

3. 消費者訂閱訊息   

    在RabbitMQ中消費者有2種方式擷取隊列中的訊息:

       a) 一種是通過basic.consume命令,訂閱某一個隊列中的訊息,channel會自動在處理完上一條訊息之後,接收下一條訊息。(同一個channel訊息處理是串列的)。除非關閉channel或者取消訂閱,否則用戶端將會一直接收隊列的訊息。

             b)  另外一種方式是通過basic.get命令主動擷取隊列中的訊息,但是絕對不可以通過迴圈調用basic.get來代替basic.consume,這是因為basic.get RabbitMQ在實際執行的時候,是首先consume某一個隊列,然後檢索第一條訊息,然後再取消訂閱。如果是高吞吐率的消費者,最好還是建議使用basic.consume。

      如果有多個消費者同時訂閱同一個隊列的話,RabbitMQ是採用迴圈的方式分發訊息的,每一條訊息只能被一個訂閱者接收。例如,有隊列Queue,其中ClientA和ClientB都Consume了該隊列,MessageA到達隊列後,被指派到ClientA,ClientA回複伺服器收到響應,伺服器刪除MessageA;再有一條訊息MessageB抵達隊列,伺服器根據“迴圈推送”原則,將訊息會發給ClientB,然後收到ClientB的確認後,刪除MessageB;等到再下一條訊息時,伺服器會再將訊息發送給ClientA。

       這裡我們可以看出,消費者再接到訊息以後,都需要給伺服器發送一條確認命令,這個即可以在handleDelivery裡顯示的調用basic.ack實現,也可以在Consume某個隊列的時候,設定autoACK屬性為true實現。這個ACK僅僅是通知伺服器可以安全的刪除該訊息,而不是通知生產者,與RPC不同。 如果消費者在接到訊息以後還沒來得及返回ACK就斷開了串連,Message Service器會重傳該訊息給下一個訂閱者,如果沒有訂閱者就會儲存該訊息。

        既然RabbitMQ提供了ACK某一個訊息的命令,當然也提供了Reject某一個訊息的命令。當用戶端發生錯誤,調用basic.reject命令拒絕某一個訊息時,可以設定一個requeue的屬性,如果為true,則Message Service器會重傳該訊息給下一個訂閱者;如果為false,則會直接刪除該訊息。當然,也可以通過ack,讓Message Service器直接刪除該訊息並且不會重傳。

4. 持久化:

        RabbitMQ預設是不持久隊列、Exchange、Binding以及隊列中的訊息的,這意味著一旦Message Service器重啟,所有已聲明的隊列,Exchange,Binding以及隊列中的訊息都會丟失。通過設定Exchange和MessageQueue的durable屬性為true,可以使得隊列和Exchange持久化,但是這還不能使得隊列中的訊息持久化,這需要生產者在發送訊息的時候,將delivery mode設定為2,只有這3個全部設定完成後,才能保證伺服器重啟不會對現有的隊列造成影響。這裡需要注意的是,只有durable為true的Exchange和durable為ture的Queues才能綁定,否則在綁定時,RabbitMQ都會拋錯的。持久化會對RabbitMQ的效能造成比較大的影響,可能會下降10倍不止。

5. 事務:

     對事務的支援是AMQP協議的一個重要特性。假設當生產者將一個持久化訊息發送給伺服器時,因為consume命令本身沒有任何Response返回,所以即使伺服器崩潰,沒有持久化該訊息,生產者也無法獲知該訊息已經丟失。如果此時使用事務,即通過txSelect()開啟一個事務,然後發送訊息給伺服器,然後通過txCommit()提交該事務,即可以保證,如果txCommit()提交了,則該訊息一定會持久化,如果txCommit()還未提交即伺服器崩潰,則該訊息不會伺服器就收。當然Rabbit MQ也提供了txRollback()命令用於復原某一個事務。

6. Confirm機制:

      使用事務固然可以保證只有提交的事務,才會被伺服器執行。但是這樣同時也將用戶端與Message Service器同步起來,這背離了訊息佇列解耦的本質。Rabbit MQ提供了一個更加輕量級的機制來保證生產者可以感知伺服器訊息是否已被路由到正確的隊列中——Confirm。如果設定channel為confirm狀態,則通過該channel發送的訊息都會被分配一個唯一的ID,然後一旦該訊息被正確的路由到匹配的隊列中後,伺服器會返回給生產者一個Confirm,該Confirm包含該訊息的ID,這樣生產者就會知道該訊息已被正確分發。對於持久化訊息,只有該訊息被持久化後,才會返回Confirm。Confirm機制的最大優點在於非同步,生產者在發送訊息以後,即可繼續執行其他任務。而伺服器返回Confirm後,會觸發生產者的回呼函數,生產者在回呼函數中處理Confirm資訊。如果Message Service器發生異常,導致該訊息丟失,會返回給生產者一個nack,表示訊息已經丟失,這樣生產者就可以通過重發訊息,保證訊息不丟失。Confirm機制在效能上要比事務優越很多。但是Confirm機制,無法進行復原,就是一旦伺服器崩潰,生產者無法得到Confirm資訊,生產者其實本身也不知道該訊息吃否已經被持久化,只有繼續重發來保證訊息不丟失,但是如果原先已經持久化的訊息,並不會被復原,這樣隊列中就會存在兩條相同的訊息,系統需要支援去重。

轉:

http://backend.blog.163.com/blog/static/202294126201322563245975/

RabbitMQ訊息佇列名詞解釋[轉]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.