本文大綱:
1. RabbitMQ簡介
2. RabbitMQ安裝與配置
3. C# 如何使用RabbitMQ
4. 幾種Exchange模式
5. RPC 遠端過程呼叫
6. RabbitMQ高可用叢集搭建
一、RabbitMQ簡介
1、介紹
RabbitMQ是一個由erlang開發的基於AMQP(Advanced Message Queue )協議的開源實現。用於在分散式系統中儲存轉發訊息,在易用性、擴充套件性、高可用性等方面都非常的優秀。是當前最主流的訊息中介軟體之一。
RabbitMQ官網:http://www.rabbitmq.com
2、AMQP
AMQP是應用層協議的一個開放標準,為面向訊息的中介軟體設計。訊息中介軟體主要用於元件之間的解耦,訊息的傳送者無需知道訊息使用者的存在,同樣,訊息使用者也不用知道傳送者的存在。AMQP的主要特徵是面向訊息、佇列、路由(包括點對點和釋出/訂閱)、可靠性、安全。
3、系統架構
訊息佇列的使用過程大概如下:
(1)客戶端連線到訊息佇列伺服器,開啟一個channel。
(2)客戶端宣告一個exchange,並設定相關屬性。
(3)客戶端宣告一個queue,並設定相關屬性。
(4)客戶端使用routing key,在exchange和queue之間建立好繫結關係。
(5) 客戶端投遞訊息到exchange。exchange接收到訊息後,就根據訊息的
key和已經設定的binding,進行訊息路由,將訊息投遞到一個或多個佇列裡。
如上圖所示:AMQP裡主要說兩個元件:Exchange和Queue。綠色的X就是Exchange ,紅色的是Queue ,這兩者都在Server端,又稱作Broker,這部分是RabbitMQ實現的,而藍色的則是客戶端,通常有Producer和Consumer兩種型別。
4、幾個概念
-
P: 為Producer,資料的傳送方。
-
C:為Consumer,資料的接收方。
-
Exchange:訊息交換機,它指定訊息按什麼規則,路由到哪個佇列。
-
Queue:訊息佇列載體,每個訊息都會被投入到一個或多個佇列。
-
Binding:繫結,它的作用就是把exchange和queue按照路由規則繫結起來。
-
Routing Key:路由關鍵字,exchange根據這個關鍵字進行訊息投遞。
-
vhost:虛擬主機,一個broker裡可以開設多個vhost,用作不同使用者的許可權分離。
-
channel:訊息通道,在客戶端的每個連線裡,可建立多個channel,每個channel代表一個會話任務。
二、RabbitMQ安裝與配置
1、安裝
RabbitMQ是建立在強大的Erlang OTP平臺上,因此安裝RabbitMQ之前要先安裝Erlang。
erlang:http://www.erlang.org/download.html
RabbitMQ:http://www.rabbitmq.com/download.html
注意:
-
現在先別裝最新的 3.6.3 ,本人在安裝完最新的版本,queue 佇列有問題,降到了 3.6.2 就解決了。
-
預設安裝的RabbitMQ監聽埠是:5672
2、配置
(1)安裝完以後erlang需要手動設定ERLANG_HOME 的系統變數。
輸入:set ERLANG_HOME=C:Program Fileserl8.0
(2)啟用RabbitMQ`s Management Plugin
使用Rabbit MQ 管理外掛,可以更好的視覺化方式檢視Rabbit MQ 伺服器例項的狀態,你可以在命令列中使用下面的命令啟用。
輸入:rabbitmq-plugins.bat enable rabbitmq_management
同時,我們也使用rabbitmqctl控制檯命令(位於rabbitmq_server-3.6.3sbin>)來建立使用者、密碼、繫結許可權等。
(3)建立管理使用者
輸入:rabbitmqctl.bat add_user zhangweizhong weizhong1988
(4)設定管理員
輸入:rabbitmqctl.bat set_user_tags zhangweizhong administrator
(5)設定許可權
輸入:rabbitmqctl.bat set_permissions -p / zhangweizhong “.*” “.*” “.*”
(6)其它命令
-
查詢使用者: rabbitmqctl.bat list_users
-
查詢vhosts: rabbitmqctl.bat list_vhosts
-
啟動RabbitMQ服務: net stop RabbitMQ && net start RabbitMQ
以上這些,賬號、vhost、許可權、作用域等基本就設定完了。
3、Rabbit MQ管理後臺
使用瀏覽器開啟http://localhost:15672 訪問RabbitMQ的管理控制檯,使用剛才建立的賬號登陸系統即可。
RabbitMQ管理後臺,可以更好的視覺化方式檢視RabbitMQ伺服器例項的狀態。
4、建立vhosts
建立vhosts,在admin頁面,點選右側Virtual Hosts:
將剛建立的OrderQueue分配給相關使用者。
其它建立exchange 、queue大家自己在後臺建立吧,這裡不再贅述。
三、C# 如何使用RabbitMQ
1、客戶端
RabbitMQ.Client 是RabbitMQ官方提供的的客戶端,net版本地址 :http://www.rabbitmq.com/dotnet.html
EasyNetQ 是基於RabbitMQ.Client 基礎上封裝的開源客戶端。使用非常方便。地址:http://easynetq.com/ 。
本篇使用示例程式碼下載地址:
demo示例下載(http://files.cnblogs.com/files/zhangweizhong/Weiz.RabbitMQ.RPC.rar)
RabbitMQ 還有很多其它客戶端API,都非常好用。我們一直用的都是 EasyNetQ,所以這裡的demo只介紹EasyNetQ客戶端實現。
2、專案結構
說明:前面我們提到過,RabbitMQ由Producer(生成者) 和Consumer(消費者)兩部分組成。Weiz.Consumer就是Consumer(消費者),Weiz. Producer為Producer(生成者),Weiz.MQ為訊息佇列的通用處理類庫。
3、專案搭建
(1)Weiz.MQ 專案,訊息佇列的通用處理類庫,用於正在的訂閱和釋出訊息。
-
通過nuget安裝專案EasyNetQ 相關元件(略)
-
增加BusBuilder.cs管道建立類,主要負責連結RabbitMQ。
-
增加IProcessMessage類,定義了一個訊息方法,用於訊息傳遞
-
增加Message類,定義了訊息傳遞的實體屬性欄位等資訊
-
增加MQHelper類,用於正在的訂閱和釋出訊息。
(2)RabbitMQ由Producer(生成者)
建立一個aspx 頁面,增加如下程式碼:
(3)Weiz.Consumer 就是Consumer(消費者)
-
新增OrderProcessMessage.cs
-
Program 增加如下程式碼:
4、執行
(1)啟動 Weiz.Consumer (消費者),啟動消費者,會自動在RabbitMQ 伺服器上建立相關的exchange 和 queue 。
Consumer 消費者,使用的是Subscribe (訂閱)的模式,所以,Weiz.Consumer客戶端啟動後,會自動建立connection,生成相關的exchange 和queue。
(2)啟動Weiz. Producer 裡的TestMQ.aspx 頁面,往佇列裡面寫一條訊息。訂閱的消費者立馬就能拿到這條訊息。
至此,C#向RabbitMQ訊息佇列傳送訊息已經簡單完成。
四、幾種Exchange模式
本節說些理論的東西——Exchange 的幾種模式。
AMQP協議中的核心思想就是生產者和消費者隔離,生產者從不直接將訊息傳送給佇列。生產者通常不知道是否一個訊息會被髮送到佇列中,只是將訊息傳送到一個交換機。先由Exchange來接收,然後Exchange按照特定的策略轉發到Queue進行儲存。同理,消費者也是如此。Exchange 就類似於一個交換機,轉發各個訊息分發到相應的佇列中。
RabbitMQ提供了四種Exchange模式:fanout、direct、topic、header 。 header模式在實際使用中較少,本文只對前三種模式進行比較。
1、Fanout Exchange
所有傳送到Fanout Exchange的訊息都會被轉發到與該Exchange 繫結(Binding)的所有Queue上。
Fanout Exchange 不需要處理RouteKey 。只需要簡單的將佇列繫結到exchange 上。這樣傳送到exchange的訊息都會被轉發到與該交換機繫結的所有佇列上。類似子網廣播,每臺子網內的主機都獲得了一份複製的訊息。
所以,Fanout Exchange 轉發訊息是最快的。
2、Direct Exchange
所有傳送到Direct Exchange的訊息被轉發到RouteKey中指定的Queue。
Direct模式可以使用RabbitMQ自帶的Exchange:default Exchange 。所以不需要將Exchange進行任何繫結(binding)操作 。訊息傳遞時,RouteKey必須完全匹配,才會被佇列接收,否則該訊息會被拋棄。
3、Topic Exchange
所有傳送到Topic Exchange的訊息被轉發到所有關心RouteKey中指定Topic的Queue上,Exchange 將RouteKey 和某Topic 進行模糊匹配。此時佇列需要繫結一個Topic。可以使用萬用字元進行模糊匹配,符號“#”匹配一個或多個詞,符號“*”匹配不多不少一個詞。因此“log.#”能夠匹配到“log.info.oa”,但是“log.*” 只會匹配到“log.error”。
所以,Topic Exchange 使用非常靈活。
這個是RabbitMQ 的實際使用的幾個場景,熟悉了這個,基本上RabbitMQ也就瞭解了。http://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html
至此,RabbitMQ幾種Exchange 模式已經介紹完了,實際使用過程中,我們會根據不同的場景,來使用不同的exchange模式。
五、RPC 遠端過程呼叫
最近有朋友問我,RabbitMQ RPC 是幹嘛的、有什麼用。其實,RabbitMQ RPC就是通過訊息佇列(Message Queue)來實現RPC的功能,就是客戶端向服務端傳送定義好的Queue訊息,其中攜帶的訊息就應該是服務端將要呼叫的方法的引數 ,並使用Propertis告訴服務端將結果返回到指定的Queue。
1、RabbitMQ RPC的特點
-
Message Queue把所有的請求訊息儲存起來,然後處理,和客戶端解耦。
-
Message Queue引入新的結點,系統的可靠性會受Message Queue結點的影響。
-
Message Queue是非同步單向的訊息。傳送訊息設計成是不需要等待訊息處理的完成。
所以對於有同步返回需求的,Message Queue是個不錯的方向。
2、普通PRC的特點
-
同步呼叫,對於要等待返回結果/處理結果的場景,RPC是可以非常自然直覺的使用方式。當然RPC也可以是非同步呼叫。
-
由於等待結果,客戶端會有執行緒消耗。
如果以非同步RPC的方式使用,客戶端執行緒消耗可以去掉。但不能做到像訊息一樣暫存訊息請求,壓力會直接傳導到服務端。
3、適用場合說明
-
希望同步得到結果的場合,RPC合適。
-
希望使用簡單,則RPC;RPC操作基於介面,使用簡單,使用方式模擬本地呼叫。非同步的方式程式設計比較複雜。
-
不希望客戶端受限於服務端的速度等,可以使用Message Queue。
4、RabbitMQ RPC工作流程
基本概念:
Callback queue 回撥佇列,客戶端向伺服器傳送請求,伺服器端處理請求後,將其處理結果儲存在一個儲存體中。而客戶端為了獲得處理結果,那麼客戶在向伺服器傳送請求時,同時傳送一個回撥佇列地址reply_to。
Correlation id 關聯標識,客戶端可能會傳送多個請求給伺服器,當伺服器處理完後,客戶端無法辨別在回撥佇列中的響應具體和那個請求時對應的。為了處理這種情況,客戶端在傳送每個請求時,同時會附帶一個獨有correlation_id屬性,這樣客戶端在回撥佇列中根據correlation_id欄位的值就可以分辨此響應屬於哪個請求。
流程說明:
-
當客戶端啟動的時候,它建立一個匿名獨享的回撥佇列。
-
在 RPC 請求中,客戶端傳送帶有兩個屬性的訊息:一個是設定回撥佇列的 reply_to 屬性,另一個是設定唯一值的 correlation_id 屬性。
-
將請求傳送到一個 rpc_queue 佇列中。
-
伺服器等待請求傳送到這個佇列中來。當請求出現的時候,它執行他的工作並且將帶有執行結果的訊息傳送給 reply_to 欄位指定的佇列。
-
客戶端等待回撥佇列裡的資料。當有訊息出現的時候,它會檢查 correlation_id 屬性。如果此屬性的值與請求匹配,將它返回給應用
5、完整程式碼
(1)建立兩個控制檯程式,作為RPC Server和RPC Client,引用RabbitMQ.Client
(2) RPC Server
(3)RPC Client
(4)分別執行Server和Client
六、RabbitMQ高可用叢集
RabbitMQ是用erlang開發的,叢集非常方便,因為erlang天生就是一門分散式語言,但其本身並不支援負載均衡。Rabbit模式大概分為以下三種:單一模式、普通模式、映象模式。
-
單一模式:最簡單的情況,非叢集模式。
沒什麼好說的。
-
普通模式:預設的叢集模式。
對於Queue來說,訊息實體只存在於其中一個節點,A、B兩個節點僅有相同的後設資料,即佇列結構。
當訊息進入A節點的Queue中後,consumer從B節點拉取時,RabbitMQ會臨時在A、B間進行訊息傳輸,把A中的訊息實體取出並經過B傳送給consumer。
所以consumer應儘量連線每一個節點,從中取訊息。即對於同一個邏輯佇列,要在多個節點建立物理Queue。否則無論consumer連A或B,出口總在A,會產生瓶頸。
該模式存在一個問題就是當A節點故障後,B節點無法取到A節點中還未消費的訊息實體。
如果做了訊息持久化,那麼得等A節點恢復,然後才可被消費;如果沒有持久化的話,然後就沒有然後了……
-
映象模式:把需要的佇列做成映象佇列,存在於多個節點,屬於RabbitMQ的HA方案。
該模式解決了上述問題,其實質和普通模式不同之處在於,訊息實體會主動在映象節點間同步,而不是在consumer取資料時臨時拉取。
該模式帶來的副作用也很明顯,除了降低系統效能外,如果映象佇列數量過多,加之大量的訊息進入,叢集內部的網路頻寬將會被這種同步通訊大大消耗掉。
所以在對可靠性要求較高的場合中適用(後面會詳細介紹這種模式,目前我們搭建的環境屬於該模式)。
1、叢集中的基本概念
RabbitMQ的叢集節點包括記憶體節點、磁碟節點。顧名思義記憶體節點就是將所有資料放在記憶體,磁碟節點將資料放在磁碟。不過,如前文所述,如果在投遞訊息時,開啟了訊息的持久化,那即使是記憶體節點,資料還是安全的放在磁碟。
一個RabbitMQ叢集中可以共享user、vhost、queue、exchange等,所有的資料和狀態都是必須在所有節點上覆制的,一個例外是那些當前只屬於建立它的節點的訊息佇列,儘管它們可見且可被所有節點讀取。RabbitMQ節點可以動態地加入到叢集中,一個節點它可以加入到叢集中,也可以從叢集環叢集進行一個基本的負載均衡。
叢集中有兩種節點:
-
記憶體節點:只儲存狀態到記憶體(一個例外的情況是:持久的queue的持久內容將被儲存到disk)
-
磁碟節點:儲存狀態到記憶體和磁碟。
記憶體節點雖然不寫入磁碟,但是它執行比磁碟節點要好。叢集中,只需要一個磁碟節點來儲存狀態 就足夠了
如果叢集中只有記憶體節點,那麼不能停止它們,否則所有的狀態,訊息等都會丟失。
思路:
那麼具體如何實現RabbitMQ高可用,我們先搭建一個普通叢集模式,在這個模式基礎上再配置映象模式實現高可用,Rabbit叢集前增加一個反向代理,生產者、消費者通過反向代理訪問RabbitMQ叢集。
架構圖如下:
圖片來自http://www.nsbeta.info
上述圖裡是3個RabbitMQ執行在同一主機上,分別用不同的服務埠。當然我們的生產實際裡,多個RabbitMQ肯定是執行在不同的物理伺服器上,否則就失去了高可用的意義。
2、叢集模式配置
設計架構可以如下:在一個叢集裡,有4臺機器,其中1臺使用磁碟模式,另2臺使用記憶體模式。2臺記憶體模式的節點,無疑速度更快,因此客戶端(consumer、producer)連線訪問它們。而磁碟模式的節點,由於磁碟IO相對較慢,因此僅作資料備份使用,另外一臺作為反向代理。
四臺伺服器hostname分別為:queue 、panyuntao1、panyuntao2、panyuntao3(ip:172.16.3.110)
配置RabbitMQ叢集非常簡單,只需要幾個命令,配置步驟如下:
Step 1:
queue、panyuntao1、panyuntao2做為RabbitMQ叢集節點,分別安裝RabbitMq-Server ,安裝後分別啟動RabbitMq-server。
啟動命令 # Rabbit-Server start ,安裝過程及啟動命令參見:http://www.cnblogs.com/flat_peach/archive/2013/03/04/2943574.html
Step 2:
在安裝好的三臺節點伺服器中,分別修改/etc/hosts檔案,指定queue、panyuntao1、panyuntao2的hosts,如:
172.16.3.32 queue
172.16.3.107 panyuntao1
172.16.3.108 panyuntao2
還有hostname檔案也要正確,分別是queue、panyuntao1、panyuntao2,如果修改hostname建議安裝rabbitmq前修改。
請注意RabbitMQ叢集節點必須在同一個網段裡,如果是跨廣域網效果就差。
Step 3:設定每個節點Cookie
RabbitMQ的叢集是依賴於erlang的叢集來工作的,所以必須先構建起erlang的叢集環境。Erlang的叢集中各節點是通過一個magic cookie來實現的,這個cookie存放在 /var/lib/rabbitmq/.erlang.cookie 中,檔案是400的許可權。所以必須保證各節點cookie保持一致,否則節點之間就無法通訊。
-r——–. 1 rabbitmq rabbitmq 20 3月 5 00:00 /var/lib/rabbitmq/.erlang.cookie
將其中一臺節點上的.erlang.cookie值複製下來儲存到其他節點上。或者使用scp的方法也可,但是要注意檔案的許可權和屬主屬組。
我們這裡將queue中的cookie 複製到 panyuntao1、panyuntao2中,先修改下panyuntao1、panyuntao2中的.erlang.cookie許可權
#chmod 777 /var/lib/rabbitmq/.erlang.cookie
將queue的/var/lib/rabbitmq/.erlang.cookie這個檔案,拷貝到panyuntao1、panyuntao2的同一位置(反過來亦可),該檔案是叢集節點進行通訊的驗證金鑰,所有節點必須一致。拷完後重啟下RabbitMQ。
複製好後別忘記還原.erlang.cookie的許可權,否則可能會遇到錯誤
#chmod 400 /var/lib/rabbitmq/.erlang.cookie
設定好cookie後先將三個節點的RabbitMQ重啟
# rabbitmqctl stop
# rabbitmq-server start
Step 4:
停止所有節點RabbitMQ服務,然後使用detached引數獨立執行,這步很關鍵,尤其增加節點停止節點後再次啟動遇到無法啟動都可以參照這個順序。
分別檢視下每個節點
Step 5:
將panyuntao1、panyuntao2作為記憶體節點與queue連線起來,在panyuntao1上,執行如下命令:
(上方已經將panyuntao1與queue連線,也可以直接將panyuntao2與panyuntao1連線,同樣而已加入叢集中)
panyuntao2# rabbitmqctl start_app
上述命令先停掉RabbitMQ應用,然後呼叫cluster命令,將panyuntao1連線到,使兩者成為一個叢集,最後重啟RabbitMQ應用。在這個cluster命令下,panyuntao1、panyuntao2是記憶體節點,queue是磁碟節點(RabbitMQ啟動後,預設是磁碟節點)。
queue 如果要使panyuntao1或panyuntao2在叢集裡也是磁碟節點,join_cluster 命令去掉–ram引數即可。
#rabbitmqctl join_cluster rabbit@queue
只要在節點列表裡包含了自己,它就成為一個磁碟節點。在RabbitMQ叢集裡,必須至少有一個磁碟節點存在。
Step 6:
在queue、panyuntao1、panyuntao2上,執行cluster_status命令檢視叢集狀態:
這時我們可以看到每個節點的叢集資訊,分別有兩個記憶體節點一個磁碟節點。
Step 7:
往任意一臺叢集節點裡寫入訊息佇列,會複製到另一個節點上,我們看到兩個節點的訊息佇列數一致:
-p引數為vhost名稱
這樣RabbitMQ叢集就正常工作了。
這種模式更適合非持久化佇列,只有該佇列是非持久的,客戶端才能重新連線到叢集裡的其他節點,並重新建立佇列。假如該佇列是持久化的,那麼唯一辦法是將故障節點恢復起來。
為什麼RabbitMQ不將佇列複製到叢集裡每個節點呢?這與它的叢集的設計本意相沖突,叢集的設計目的就是增加更多節點時,能線性的增加效能(CPU、記憶體)和容量(記憶體、磁碟)。理由如下:
1. storage space: If every cluster node had a full copy of every queue, adding nodes wouldn’t give you more storage capacity. For example, if one node could store 1GB of messages, adding two more nodes would simply give you two more copies of the same 1GB of messages.
2. performance: Publishing messages would require replicating those messages to every cluster node. For durable messages that would require triggering disk activity on all nodes for every message. Your network and disk load would increase every time you added a node, keeping the performance of the cluster the same (or possibly worse).
當然RabbitMQ新版本叢集也支援佇列複製(有個選項可以配置)。比如在有五個節點的叢集裡,可以指定某個佇列的內容在2個節點上進行儲存,從而在效能與高可用性之間取得一個平衡。
3、映象模式配置
上面配置RabbitMQ預設叢集模式,但並不保證佇列的高可用性,儘管交換機、繫結這些可以複製到叢集裡的任何一個節點,但是佇列內容不會複製,雖然該模式解決一部分節點壓力,但佇列節點當機直接導致該佇列無法使用,只能等待重啟,所以要想在佇列節點當機或故障也能正常使用,就要複製佇列內容到叢集裡的每個節點,需要建立映象佇列。
我們看看如何映象模式來解決複製的問題,從而提高可用性 。
Step 1:增加負載均衡器
關於負載均衡器,商業的比如F5的BIG-IP,Radware的AppDirector,是硬體架構的產品,可以實現很高的處理能力。但這些產品昂貴的價格會讓人止步,所以我們還有軟體負載均衡方案。網際網路公司常用的軟體LB一般有LVS、HAProxy、Nginx等。LVS是一個核心層的產品,主要在第四層負責資料包轉發,使用較複雜。HAProxy和Nginx是應用層的產品,但Nginx主要用於處理HTTP,所以這裡選擇HAProxy作為RabbitMQ前端的LB。
HAProxy的安裝使用非常簡單,在Centos下直接yum install haproxy,然後更改/etc/haproxy/haproxy.cfg 檔案即可,檔案內容大概如下:
負載均衡器會監聽5672埠,輪詢我們的兩個記憶體節點172.16.3.107、172.16.3.108的5672埠,172.16.3.32為磁碟節點,只做備份不提供給生產者、消費者使用,當然如果我們伺服器資源充足情況也可以配置多個磁碟節點
,這樣磁碟節點除了故障也不會影響,除非同時出故障。
Step 2:配置策略
使用Rabbit映象功能,需要基於RabbitMQ策略來實現,政策是用來控制和修改群集範圍的某個vhost佇列行為和Exchange行為。
在cluster中任意節點啟用策略,策略會自動同步到叢集節點
# rabbitmqctl set_policy -p hrsystem ha-allqueue”^” `{“ha-mode”:”all”}`
這行命令在vhost名稱為hrsystem建立了一個策略,策略名稱為ha-allqueue,策略模式為 all 即複製到所有節點,包含新增節點,策略正規表示式為 “^” 表示所有匹配所有佇列名稱。
例如rabbitmqctl set_policy -p hrsystem ha-allqueue “^message” `{“ha-mode”:”all”}`
注意:”^message” 這個規則要根據自己修改,這個是指同步”message”開頭的佇列名稱,我們配置時使用的應用於所有佇列,所以表示式為”^”
官方set_policy說明參見
set_policy [-p vhostpath] {name} {pattern} {definition} [priority]
(http://www.rabbitmq.com/man/rabbitmqctl.1.man.html)
ha-mode:
Step 3:
建立佇列時需要指定ha 引數,如果不指定x-ha-prolicy 的話將無法複製。
下面為C#程式碼片段:
Step 4:
客戶端使用負載伺服器172.16.3.110 (panyuntao3)傳送訊息,佇列會被複制到所有節點,當然策略也可以配置制定某幾個節點,這時任何節點故障 、或者重啟將不會影響我們正常使用某個佇列。到這裡我們完成了高可用配置(所有節點都當機那沒有辦法了)。
使用RabbitMQ管理端可以看到叢集映象模式中對列狀態
參考:
-
-
http://www.rabbitmq.com/clustering.html
-
http://www.rabbitmq.com/ha.html
-
http://www.rabbitmq.com/parameters.html#policies
-
http://www.nsbeta.info/archives/555
-
http://blog.csdn.net/linvo/article/details/7793706
-