在本章節中我們將覆蓋:
- 創建一個本地服務器集群
- 創建一個簡單集群
- 自動添加一個RabbitMQ 集群
- 引入消息負載均衡器
- 創建集群客戶端
介紹
RabbitMQ提供了各種各樣的特性以及集群功能.
通過使用集群,一組適當配置的主機的行為與單個broker實例一樣,但集群帶有下面的目的:
- 高可用性: 如果一個節點宕機了,分布式broker仍然能接受和處理消息.這方面內容會在Chapter 7,Developing High-availability Applications中深入探討.
- 可伸縮的消息負載:消息路由在集群節點間是分布式的.
- 連接客戶端的伸縮性:每個節點都可以用來處理可用客戶端的某部分子集.
TIP
RabbitMQ集群節點應該在LAN內. RabbitMQ 集群不能很好的容忍網絡分化,因為網絡分化期間,每個節點都是單獨工作的,目前還沒有機制來防止所謂的"split-brain syndrome" (可在 http://en.wikipedia.org/wiki/Consensus_(computer_science)找到解決這個問題的參數).在本地網絡中, RabbitMQ使用短超時來確定兄弟節點的可用性。更多信息,可參考http://www.rabbitmq.com/nettick.html.
RabbitMQ集群中所有節點除了隊列外,可以共享虛擬主機,用戶,交換器的定義,物理上它們只存在于創建的節點內. 另一方面,它們是全局定義的,可通過集群的任何節點進行連接。
如果一個客戶端從還沒有創建隊列的節點上生產或消費消息,其性能會降低,因為客戶端需要多個跳躍才能到達物理上持有隊列的節點。
TIP
默認情況下,隊列不會在集群節點間復制,因此當出現節點故障時,你可能會丟失數據.可參考Chapter 7, Developing High-availability Applications 來解決這個問題。
在章節中,我們將展示RabbitMQ集群伸縮性方面的例子,同時也會展示設計集群AMQP客戶端的正確方法.
創建一個本地服務器集群
本地集群指的是在同一臺主機上將多個RabbitMQ實例以單一集群的方式進行配置。
實際上,在產品環境中,通常來說,這沒有多大用處,因為它不提供任何可伸縮性和可靠性改進. 然而,創建本地集群來測試配置是相當用的,如:開發PC。
準備
為了付諸實施,我們需要安裝有RabbitMQ,并能正常運行。即使嚴格上意義來不是必要的,我們也會安裝管理插件,就如Chapter 3, Managing RabbitMQ中展示的一樣.在這種情況下,我們需要為每個broker指定不同的web控制臺TCP端口.
如何做
要創建一個本地集群,我們需要執行下面的步驟:
1. 從root shell (Linux)中,使用下面的命令來啟動另一個RbbitMQ實例:
env RABBITMQ_NODENAME=node01 RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]"
rabbitmq-server -detached
2. 使用下面的命令將此實例加入到默認那個節點:
rabbitmqctl -n node01 stop_app
rabbitmqctl -n node01 join_cluster rabbit@$HOSTNAME
rabbitmqctl -n node01 start_app
3. 使用下面的命令來檢查運行的集群狀態:
rabbitmqctl cluster_status
4. 使用下面的命令退出集群,并回歸到單獨節點狀態:
rabbitmqctl -n node01 stop_app
rabbitmqctl -n node01 reset
rabbitmqctl -n node01 start_app
如何工作
通過覆蓋某些配置選項,可在同臺機器上運行多個RabbitMQ 服務器實例. 尤其是在已經安裝了broker的情況下,新安裝的broker必須強制指定不同的broker端口(默認為5672)以及管理插件端口(默認為15672)。
這可以通過修改環境變量來完成(步驟1).目前,可用的RabbitMQ環境變量如下:
- RABBITMQ_MNESIA_BASE
- RABBITMQ_LOG_BASE
- RABBITMQ_NODENAME
- RABBITMQ_NODE_IP_ADDRESS
- RABBITMQ_NODE_PORT
你可以在shell提示窗口中,輸入下面的命令來查看rabbitmqserver指南頁面中所有前面變量的詳細描述:
man rabbitmq-server
在這里,我們設置了node名稱,TCP端口,以及一些自定義參數:
RABBITMQ_NODENAME=node01
RABBITMQ_NODE_PORT=5673
RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]"
TIP 在Windows中,步驟1中的命令可通過在命令行中進行設置.你可以將下面的腳本拷貝到一個.bat文件中來達到此目的:
set RABBITMQ_NODENAME=%1
set RABBITMQ_NODE_PORT=%2
set RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,%3}]" "SBIN_FULL_PATH_HERE\rabbitmq-server" -detached
此時,第二臺服務器相對于第一臺服務器來說,仍然是獨立運行的。我們必須運行步驟2中的三個命令,這樣兩個服務器才會綁定到同一個集群中。
TIP
在 Windows中,你需要使用 %COMPUTERNAME% 來代替$HOSTNAME.
通過在集群環境中運行提供的例子,你可以很容易地進行檢查.節點上創建的以及代碼中使用的交換器將會復制到新添加的節點上,反之亦然. 可單獨訪問http://localhost:15672 和 http://localhost:15673 管理插件來了解此種情況。
另外, 你也可以使用-n選項來指定特定節點來執行rabbitmqctl命令,就像步驟2和步驟4中展示的一樣.
如果你不使用-n選項,命令會直接在默認rabbitmq節點上執行.
更多
兩個節點神奇般地可以互相說話了,這要多虧它們共享了相同的Erlang cookie,因為它們在同一臺機器上.
事實上,多個不同RabbitMQ實例與任何Erlang分布式程序一樣,都會使用基本認證方案.兩個應用程序實例要能相互通信,它們必須有相同的Erlang cookie(一個包含任意數據的文件).它可以是字符串,GUID,或者是你能想到的任何東西.
TIP
Erlang cookie事實是上一個密鑰,如果沒有適當的保護, Erlang則不允許使用,并且不會工作.你可以為其設置適當的權限,如下所示:
chmod 400 .erlang.cookie
你可在http://www.erlang.org/doc/getting_started/conc_prog.html#id67454找到更多關于Erlang cookies的信息.
在不同主機上搭建集群中,必須強制性在各個主機上使用相同的Erlang cookie,在后續食譜中我們將看到這方面的內容。
創建一個簡單集群
設置一個RabbitMQ集群也就是幾分鐘的事情,只需要配置幾個步驟,高可用集群就可以部署運行。
事實上,相對于本地集群,它更容易,可參考創建本地集群食譜,因為每個節點都會使用標準端口設置.
準備
要準備此食譜,你至少需要安裝在兩臺主機上安裝RabbitMQ實例,并將它們配置為獨立broker.
TIP
要使集群能正常工作,必須確保所有主機上的RabbitMQ和Erlang是一致的.
主機可以是物理機,也可以是云實例,還可以是虛擬機器.
TIP
Amazon Web Services (AWS) 預先安裝的RabbitMQ通常都是過期的,我們建議安裝主流的Linux AMI,然后安裝最新的RabbitMQ版本,可參考(http://www.rabbitmq.com/download.html).
如何做
在下面的步驟中,我們將節點命名為node01, node02, node03.作為一種選擇,你可以使用你當前的主機名稱,從而可以越過步驟1到4.
1. 如果節點已經運行,通過下面的命令來停止RabbitMQ server:
service rabbitmq-server stop
2. 在node01上, 在/etc/hosts中追加所有IP名稱綁定,如下所示(將你的IP地址放在這里):
10.0.0.1 node01
10.0.0.2 node02
...
3. 從node1中拷貝下面的文件到所有其它節點上,以保證有相同的主機名稱定義:
scp /etc/hosts 10.0.0.2:/etc/hosts
scp /etc/hosts 10.0.0.3:/etc/hosts
...
4. 在所有節點上設置本地主機名稱(每個服務器都設為不同的主機名稱):
echo node01 > /etc/hostname
hostname –F /etc/hostname
然后,我們配置RabbitMQ.
5. 從node01中拷貝RabbitMQ Erlang cookie到其它所有節點上:
scp /var/lib/rabbitmq/.erlang.cookie node02:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie node03:/var/lib/rabbitmq/.erlang.cookie
...
6. 重啟所有節點上的RabbitMQ server:
service rabbitmq-server start
7. 將所有節點加入到node01.在除node01的所有節點上,運行下面的命令:
rabbitmqctl stop_app
rabbitmqctl join_cluster --ram rabbit@node01
rabbitmqctl start_app
此時,集群已能正常運行了.我們可以執行一些更多的命令:
1. 檢查集群狀態:
rabbitmqctl cluster_status
2. 修改node02的節點類型:
rabbitmqctl stop_app
rabbitmqctl change_cluster_node_type disc
rabbitmqctl stat_app
3. 讓集群忘了node02,它是從node01來執行的:
rabbitmqctl forget_cluster_node rabbit@node02
4. 讓刪除的node02忘記其集群狀態.在node02上使用下面的命令:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
如何工作
集群中的所有服務器必須通過主機名來互相感知,這是很重要的,因為IP地址對于RabbitMQ來說還不夠。因此,你必須為所有服務器配置/etc/hosts (或者配置windows中類似的hosts文件。
TIP
所有節點都需要使用短主機(short hostnames)來尋址. 如果你試圖使用全限定域名(FQDN), RabbitMQ可能不能正常工作。
使用外部名稱服務器也是可以的,但在這種情況下,集群需要對它進行依賴. 通常的慣例是在集群的前端設置了一個名稱服務器,并依賴靜態主機信息來配置集群。
在所有節點配置之后,需要對它們進行同步,以在其它服務器上共享同一個cookie. cookie文件可包含任意的字符串,以在節點間實現簡單地相互認證。(步驟5)
TIP
通過指定-n選項,也可以配置Erlang cookie來讓rabbitmqctl與遠程節點一同工作.
此時,可能過下面的命令來創建集群:
rabbitmqctl join_cluster --ram rabbit@node01
如果我們正確地執行了所有步驟,我們可以得到下面的輸出:
Clustering node rabbit@node02 with rabbit@node01 ...
...done.
通過使用 --ram 選項,我們將RabbitMQ 節點類型聲明為RAM.RAM類型的節點不會在磁盤上保存信息,它只是比磁盤節點(默認節點類型)更快速.
在RabbitMQ集群的介紹中,至少在集群中有一個節點的類型為磁盤節點.這樣,在服務器重啟或某個磁盤節點出現故障時,所有配置(交換器,隊列等)才會安全。
TIP
實際上,由于你已在所有節點上拷貝了Erlang cookies,因此你可以通過-n選項,可在node01上來執行指定節點上的所有操作:
rabbitmqctl -n rabbit@node02 stop_app
rabbitmqctl -n rabbit@node02 join_cluster rabbit@node01
rabbitmqctl -n rabbit@node02 start_app
更多
為了大型集群上準備這種配置,通常最佳實踐是使用分布式shell前端.
最初, dsh只能應用于IBM AIX,但在現代的Linux系統中,你可以找到pdsh和pdcp (通常在pdsh包中)命令來執行同樣的操作。
你也可以在老的或window上使用相似的前端工作(如dancer工具:http://www.netfort.gr.jp/~dancer/software/dsh.html.en).
另外,你也可以使用你喜歡的集群管理軟件來執行相同的操作.
也可參考
你可在http://www.rabbitmq.com/clustering.html找到更多關于集群指南的信息.
自動添加一個RabbitMQ集群通常情況下,當服務器啟動時,我們需要準備加入集群的操作系統鏡像.通過一些腳本,我們可以很容易地實現這種任務,但RabbitMQ提供了更簡單的更優雅的方法。在本食譜中,我們將進行介紹。
準備
為了準備這個食譜,我們至少兩臺已經安裝RabbitMQ的主機,并將它們配置為獨立broker.同時,這些主機還應該有相同版本的RabbitMQ 和 Erlang.
如何做
在本食譜中,我們啟動了兩個高可用性RabbitMQ核心broker,它們滿足集群正常工作,具備高可靠性的最小條件 。然后,我們將其它所有節點配置為自動配置(通過在rabbitmq.config文件中編寫配置)。
1. 配置服務器主機名已在Creating a simple cluster 食譜的步驟1 到 4中看過了.
2. 為所有服務器配置相同的Erlang cookie.
3. 在節點node01和node02上啟動RabbitMQ,并根據它們來創建一個集群,正如前面食譜中看過的.
4.如果節點已經被使用了,重設所有其它節點并停止,就像下面這樣:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
5. 在所有其它節點上,設置RabbitMQ配置文件rabbitmq.config內容(最后的圓點是配置文件的一部分):
[{rabbit,
[{cluster_nodes, {['rabbit@node01', 'rabbit@node02'],
ram}}]}].
6. 在所有節點上重啟RabbitMQ,如下所示:
service rabbitmq-server start
如何工作
這種配置最適合在預先部署OS鏡像和RabbitMQ. 這些鏡像可以在不傷害現有集群的情況下進行部署和使用.
RabbitMQ在啟動時,會讀取 rabbitmq.config文件. RabbitMQ將忽略該節點的集群自動配置,除非它是一個完全干凈的狀態, 也就是要啟用集群自動配置,需要滿足下面兩個條件中的任何一個:
- RabbitMQ實例已經被重置和停止,正如步驟4中所展示的一樣
- RabbitMQ實例已經安裝且從沒有啟動過
在后一種情況中,你不需要執行步驟6,只需要將RabbitMQ配置文件放置到正確的位置,然后再啟動RabbitMQ (如果我們是以鏡像方式來運行的,那么它將在服務器啟動時,自動運行),隨后游戲就結束了。
TIP
默認的RabbitMQ配置文件稱為rabbitmq.config,其位置根據安裝時配置是變化的.下面是典型的位置:
- /etc/rabbitmq/ (大多數分發是這樣)
- Rabbitmqdir/etc/rabbimq/ (Mac OSX)
- %APPDATA%\RabbitMQ\ (Windows)
一旦節點啟動了,它就會重復地嘗試連接指定節點,作為步驟5中列表節點元組的第一個元素.只要它成功連上了節點列表中的一個,它就會以RAM節點加入到集群中,即作為元組的第二個元素 (或者你也可以指定一個磁盤節點).
介紹消費者負載均衡器
為了有一個多節點的RabbitMQ集群, clients必須知道所有的IP地址,如果集群配置是動態的,clients應該收到任何變化的通知。
此外, clients可以使用一些方法聯系很少負載的clients.
通常的解決方案是在集群的前端增加一個負載均衡器.
負載均衡器可以硬件解決方案或軟件包,可在一般器上進行安裝和配置.而且,也有多種不同的負載均衡技術, 下面是最相關的:
- Round-robin name servers
- TCP load balancers
TCP 負載均衡器可作為:
- Proxy: 在這種情況下,所有連接的接受和執行都在負載均衡器自身上執行
- Direct Server Return (DSR): 只接受連接的初始化 (SYN),然后讓客戶端與服務器在后端直接連接,而不再進行干預(明顯的優勢在于伸縮性和性能)
這并不是全部,但更深入的細節已經超出了本書的范圍. 針對我們的目的來說,我們會使用TCP 軟件負載均衡器-Crossroads (http://crossroads.e-tunity.com/).
當其安裝后,clients將會對它進行連接,它會將連接轉發到后端RabbitMQ服務器,正如下圖所示:

準備
在本食譜中,我們需要三臺機器;兩臺用于RabbitMQ集群,一個用于安裝負載均衡器.
在這種情況下,如果clients是從Internet發起連接的話,前面兩臺服務器不需要公網IP地址,負載均衡器有公網IP就足夠了.
如何做
在這個例子中,我們采用了兩個Linux Debian (IP為 192.168.10.2、192.168.10.3) 來作 RabbitMQ服務器,一臺Linux Centos作Crossroads (with IP 192.168.10.1).
使用兩臺機器來創建 RabbitMQ集群的例子,我們已經在創建簡單集群食譜中看過了.
下面的步驟只針對Centos 機器(192.168.10.1):
1. 為了編譯Crossroads, 你需要 C++ 編譯器和GNU make. 同時你也需要系統標準C包;執行下面的命令來準備機器:
yum groupinstall "Development Tools"
2. 然后, 執行wget http://crossroads.e-tunity.com/downloads/crossroads-stable.tar.gz 下載最新的Crossroads的穩定版本到你的源碼目錄中(如: /usr/local/src/),
3. 使用下面的解壓命令:
tar xvzf crossroads-stable.tar.gz
4. 進入解壓目錄,cd crossroads-2.74, 執行make install, 然后等待… 最后會出現下面的截屏:

5. 為RabbitMQ配置負載均衡器:
xr -v --server tcp:0:5672 --backend 192.168.10.2:5672 --backend 192.168.10.3:5672 2>&1 >> /var/log/xr-rmq.log &
6. 如果你啟用了RabbitMQ web管理插件(參考 Chapter 3,Managing RabbitMQ),你也可以為其創建一個負載均衡器:
xr -v --server tcp:0:80 --backend 192.168.10.2:15672 --backend 192.168.10.3:15672 2>&1 >> /var/log/xr-web.log &
7. 在瀏覽器中打開http://192.168.10.1.
如何工作
在創建簡單集群之后(步驟1),我們安裝并配置了負載均衡器;對于Crossroads,我們假設你使用的是Centos Linux distribution.跟隨步驟2到5,你可以編譯和安裝Crossroads, 然后你可以配置負載均衡器角色。最初,我們使用下面的命令來運行crossroads的負載均衡器(步驟6):
xr -v --server tcp:0:5672 --backend 192.168.10.2:5672
--backend 192.168.10.3:5672
2>&1 >> /var/log/xr-rmq.log &
xr –v server tcp:0:5672命令將5672端口(RabbitMQ默認TCP端口)與服務器TCP監聽器進行了關聯, --backend 參數 用于重定向連接,在我們這里,將會重定向到192.168.10.2:5672 and 192.168.10.3:5672.
我們使用>>/var/log/xr-rmq.log將輸出寫到日志文件中.
為了從負載均衡器訪問web管理插件,在步驟7中,我們使用15672端口又執行另一個XR服務器.
Crossroads 可使用不同的分發算法,但默認情況下,它使用簡單的 round-robin 算法,這就是說,連接會均勻地重定向到每個后端服務器上。
此時,你可以使用crossroadsIP代替服務器IP地址來運行任何的RabbitMQ client示例.連接會自動地轉發到后端brokers上.
在下章節中,我們將看到負載均衡器的使用和其它高可用方案.
更多
Crossroads是簡單地Linux負載均衡器,可參考http://crossroads.etunity.com/documentation.xr 來了解全部信息。 另一種廣泛地負載均衡方案是HAProxy (http://haproxy.1wt.eu/)
也可參考
可閱讀章節-從客戶端來連接集群(http://www.rabbitmq.com/clustering.html)來了解詳情.
創建集群客戶端
當你創建了簡單集群后,客戶端需要指定多個broker地址來連接broker.在本食譜中,我們將看到在RabbitMQ Java client中,如何使用多個地址來連接broker.
注意:與集群前端負載均衡器不同,在那里并不需要指定多個地址,只需要指定前端均衡器地址即可。
準備
你需要Java 1.6+和Apache Maven.
如何做
首先,你需要一個簡單集群.
然后,你可以使用下面的代碼來進行連接:
Address[] addrArr = new Address[]{ new Address("node01",portnode1), new Address("node02", portnode2)};
connection = factory.newConnection(addrArr);
如何工作
在RabbitMQ包中,你可以傳遞多個host/IP給連接工廠.這種特性可用于小型和大型場景.例如,如果你有兩個節點,并且你想避免使用DNS或負載均衡器,那么你可以直接在client中傳遞所有的broker地址. client會嘗試連接第一個地址,如果第一個地址連接失敗,client會在不拋出異常的情況下,繼續嘗試連接下一個地址。
同樣的方案可應用于更為復雜的架構.如,假設你有下面兩個主機:
- myrmqcluster_production.internal.com
- myrmqcluster_maintenance.internal.com
客戶端總是會連接production系統,但如果production 系統正在維護,clients會連接第二個地址.
更多 實際上,在沒有RabbitMQ集群的情況下,你也可以使用這種連接方法.在源碼Chapter06/Recipe06中,我們創建了一種虛擬算法來負載連接。 在這種情況下,你完全可以構建兩個獨立的RabbitMQ實例.
也可參考
在下面的章節中,我們將看到如何通過混合集群,HA策略,客戶端技術來創建一個HA client.
posted on 2016-06-15 20:54
胡小軍 閱讀(1947)
評論(2) 編輯 收藏 所屬分類:
RabbitMQ