1. 程式人生 > >Rabbit MQ持久化

Rabbit MQ持久化

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

RabbitMQ支援訊息的持久化,也就是資料寫在磁碟上,為了資料安全考慮,我想大多數使用者都會選擇持久化。訊息佇列持久化包括3個部分:  (1exchange持久化,在宣告時指定durable => 1
  (2queue持久化,在宣告時指定durable => 1
  (3)訊息持久化,在投遞時指定delivery_mode=> 21是非持久化)

如果exchangequeue都是持久化的,那麼它們之間的binding也是持久化的。如果exchangequeue兩者之間有一個持久化,一個非持久化,就不允許建立繫結。

 生產者在傳送訊息時,都需要指定一個

RoutingKeyExchangeExchange在接到該RoutingKey以後,會判斷該ExchangeType:

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

RabbitMQ系列二(構建訊息佇列) - 網易杭研後臺技術中心 - 網易杭研後臺技術中心的部落格
                  b) 如果是Fanout型別,則會將訊息傳送給所有與該Exchange定義過Binding的所有Queues中去,其實是一種廣播行為。
         
RabbitMQ系列二(構建訊息佇列) - 網易杭研後臺技術中心 - 網易杭研後臺技術中心的部落格 

        c)如果是Topic型別,則會按照正則表示式,對RoutingKey

BindingKey進行匹配,如果匹配成功,則傳送到對應的Queue中。

             RabbitMQ系列二(構建訊息佇列) - 網易杭研後臺技術中心 - 網易杭研後臺技術中心的部落格

3、Exchange型別topic

這個型別的路由規則如果你掌握啦,那是相當的好用,與靈活。他是根據RoutingKey的設定,來做匹配的,其中這裡還有兩個萬用字元為:

*,代表任意的一個詞。例如topic.zlh.*,他能夠匹配到,topic.zlh.one ,topic.zlh.two ,topic.zlh.abc, ....

#,代表任意多個詞。例如topic.#,他能夠匹配到,topic.zlh.one ,topic.zlh.two ,topic.zlh.abc, ....



  1. boolean durable = true;  
  2. channel.queueDeclare("hello", durable, falsefalsenull);  
       儘管這行程式碼是正確的,但他不會在我們當前的設定中起作用。因為我們已經定義了一個名叫hello的未持久化的佇列。RabbitMQ不允許使用不同的引數設定重新定義已經存在的佇列,並且會向嘗試如此做的程式返回一個錯誤。一個快速的解決方案——就是宣告一個不同名字的佇列,比如task_queue。

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

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

  還有幾個概念是上述圖中沒有標明的,那就是Connection(連線),Channel(通道,頻道)。

   Connection : 就是一個TCP的連線。Producer和Consumer都是通過TCP連線到RabbitMQ Server的。以後我們可以看到,程式的起始處就是建立這個TCP連線。

   Channels : 虛擬連線。它建立在上述的TCP連線中。資料流動都是在Channel中進行的。也就是說,一般情況是程式起始建立TCP連線,第二步就是建立這個Channel。

    那麼,為什麼使用Channel,而不是直接使用TCP連線?

    對於OS來說,建立和關閉TCP連線是有代價的,頻繁的建立關閉TCP連線對於系統的效能有很大的影響,而且TCP的連線數也有限制,這也限制了系統處理高併發的能力。但是,在TCP連線中建立Channel是沒有上述代價的。對於Producer或者Consumer來說,可以併發的使用多個Channel進行Publish或者Receive。

最簡單的方式是使RabbitMQ以Windows Service的方式在後臺執行,所以我們需要以管理員許可權開啟cmd,然後切換到sbin目錄下,執行這三條命令即可:

rabbitmq-service install
rabbitmq-service enable
rabbitmq-service start

Start RabbitMQ Service

現在RabbitMQ的服務端已經啟動起來了。

下面可以使用sbin目錄下面的rabbitmqctl.bat這個指令碼來檢視和控制服務端狀態的,在cmd中直接執行rabbitmqctl status。如果看到以下結果:

Unable to connect node

顯示node沒有連線上,需要到C:\Windows目錄下,將.erlang.cookie檔案,拷貝到使用者目錄下 C:\Users\{使用者名稱},這是Erlang的Cookie檔案,允許與Erlang進行互動,現在重複執行剛才的命令就會得到如下資訊:

rabbit mq status

RabbitMQ Server上面也有使用者概念,安裝好之後,使用rabbitmqctl list_users命令,可以看到上面目前的使用者:

RabbitMQ users

可以看到,現在只有一個角色為administrator的名為guest的使用者,這個是RabbitMQ預設為我們建立的,他有RabbitMQ的所有許可權,一般的,我們需要新建一個我們自己的使用者,設定密碼,並授予許可權,並將其設定為管理員,可以使用下面的命令來執行這一操作:

rabbitmqctl  add_user  yy  hello!
rabbitmqctl  set_permissions  yy  ".*"  ".*"  ".*"
rabbitmqctl  set_user_tags yy administrator

Create RabbitMQ user

上面的一條命令添加了一個名為yy的使用者,並設定了密碼hello!,下面的命令為使用者yy分別授予對所有訊息佇列的配置、讀和寫的許可權。

現在我們可以將預設的guest使用者刪掉,使用下面的命令即可:

rabbitmqctl delete_user guest

如果要修改密碼,可以使用下面的命令:

rabbitmqctl change_password {username}  {newpassowrd}

//普通使用方式BasicGet
                    
//noAck = true,不需要回復,接收到訊息後,queue上的訊息就會清除
                    
//noAck = false,需要回復,接收到訊息後,queue上的訊息不會被清除,直到呼叫channel.basicAck(deliveryTag, false); queue上的訊息才會被清除 而且,在當前連線斷開以前,其它客戶端將不能收到此queue上的訊息                    BasicGetResult res = ch.BasicGet("q1"false/*noAck*/);