abbitMQ的集群主要有配置方式,分別是:本地局域網Cluster,federation,shovel。
RabbitMQ Cluster主要是用於同一個網段內的局域網。
federation和shovel可以用於廣域網,shovel比federation更底層,可以用於更多地方。
RabbitMQ Cluster配置
RabbitMQ Cluster是根據Erlang的實現的。必須滿足一下幾個要求:
- 所有機器上,必須Erlang運行時和RabbitMQ的版本相同。(否則會不能連接到一起)
- 所有機器上,的Erlang的Cookie都相同。
注意:由於RabbitMQ會使用Node@HostName,如果你在/etc/hosts里面定義了IP HostName關系,當你的IP發生變化時,命令行都會失去作用。
查看機器上的Erlang的Cookie。
linux上位置有兩個地方。一個是在$HOME目錄下的.erlang.cookie 另外在/var/lib/rabbitmq/.erlang.cookie
通過修改rabbitmq-server腳本文件和rabbitmqctl,在 erl 后面增加 -setcookie wugetestnodes
注意:必須兩個腳本同時增加-setcookie "所以寫相關cookie",否則rabbitmqctl無法控制對應的rabbitmq
服務器啟動
每個節點運行一下命令:
$rabbitmq-server -detached #讓當前rabbitmq-server的進程后台運行。
每個節點執行以下命令:
$rabbitmqctl cluster_status #獲得集群配置信息。
例子:
將節點加入到主節點中
首先停止正在運行的節點。
在節點2上運行以下命令:
sudo ./rabbitmqctl stop_app #停止rabbitmq運行
sudo .rabbitmqctl join_cluster --ram rabbit@cs_hd_os1 #加入到rabbit節點中,使用內存模式。
sudo ./rabbitmqctl cluster_status #查看狀態
sudo ./rabbitmqctl start_app #啟動rabbitmq
sudo ./rabbitmqctl cluster_status #查看狀態
默認分布式現象
當設置完成基本Cluster結構之后,會將 Vhost為"/"下面的Queue隊列同步。同步效果如下
節點1:
節點2
無論是從同一個Cluster中那個節點消費,隊列狀態都會進行同步.
修改節點類型
我們要將節點2的RAM類型修改為Disc類型。
./rabbitmqctl stop_app
./rabbitmqctl change_cluster_node_type disc
./rabbitmqctl start_app
./rabbitmqctl cluster_status
當Cluster集群中僅有一台機器為Disc情況下,這台機器不能修改存儲狀態。
當集群節點使用./rabbitmqctl stop_app情況下,集群其他節點保存停止節點的信息。但是運行狀態會改變。
構建Cluster的數據高可靠性
場景描述:
有兩台服務器,服務器一:cs_hd_os1。服務器二:cs_hd_os2 設置cs_hd_os2加入到cs_hd_os1的集群里面。
初始化創建Cluster集群數據情況
這里沒有配置Policy相關文件。
- 當兩台服務器rabbitmq都運行時候。在cs_hd_os1和cs_hd_os2可以看到在 vhost為"/"下的內容相互復制。(Exchange,Bind, Queue)都會復制到對方里面。
- 當其中一台停機之后,另外一台智能看到Exchange名稱,Bind,Queue都消失了。
注意:兩個RabbitMQ的Queue不能重名,重名之后會有異常產生。
當其中一個Node失效后,另外一個Node也失效
先啟動最后一個失效的節點,節點不能啟動。
這是因為數據庫崩潰了。刪除掉RabbitMQ的數據庫就可以恢復了。
為節點配置HA策略
HA策略主要配置
HA的策略主要分為 三種:
ha-mode | ha-params | 說明 |
---|---|---|
all | 空 | 鏡像隊列將會在整個集群中復制。當一個新的節點加入后,也會在這個節點上復制一份。 |
exactly | count | 鏡像隊列將會在集群上復制count份。如果集群數量少於count時候,隊列會復制到所有節點上。如果大於Count集群,有一個節點crash后,新進入節點也不會做新的鏡像。(這位阻止集群雪崩) |
nodes | node name | 鏡像隊列會在node name中復制。如果這個名稱不是集群中的一個,這不會觸發錯誤。如果在這個node list中沒有一個節點在線,那么這個queue會被聲明在client連接的節點。 |
節點策略與集群遷移
如果master節點沒有包含在這個策略中的時候,只有當有一個slave node與Master同步完成之后,master才會離開。client將要重新連接服務器。
獨有的隊列(Exclusive queue)
獨有的隊列不會被鏡像話,因為狀態無法保證。
設置策略方法
方法1 :使用命令行來設置
set_policy [-p vhostpath] [--priority priority] [--apply-to apply-to] {name} {pattern} {definition}
ha-mode | ha-params | 說明 |
---|---|---|
-p /wuge | 設置vhost信息。 | |
--priority 10 | 設置優先級。高數字會優先處理。 | |
--apply-to queue | 作用對象。queue、exchanges,all | |
name | 規則名稱 |
./rabbitmqctl set_policy -p '/wuge' --priority 9 --apply-to all testctl "^hello" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
方法2:通過restful API
/api/policies/%2Fwuge/testctl
{"vhost":"/wuge","name":"testctl","pattern":"^hello","apply-to":"all","definition":{"ha-mode":"all","ha-sync-mode":"automatic"}}
定義ha-sync-mode說明
ha-sync-mode分為兩種狀態設置:一種為手動"manual",另一種為自動"automatic"。 默認的設置為manual
我們可以通過使用rabbitmqctl來同步數據。
說明 | 命令 |
---|---|
設置那兩個系統之間進行同步 | rabbitmqctl list_queues name slave_pids synchronised_slave_pids |
手動同步那個隊列 | rabbitmqctl sync_queue name |
手動終止對應的隊列 | rabbitmqctl cancel_sync_queue name |
分布式數據同步
新的Slave節點加入的處理方法
一個新的Slave節點加入,他需要同步其他節點的數據。而當同步數據的時候,當前同步的Queue就不能被使用。(無法發送消息到Queue中,也無法從里面獲取消息進行處理)。
在Slave之間進行數據同步的時候,如果是police策略范圍內的。(例如本例:task_police策略中,有task名稱開頭,性能下降嚴重)。所有的消息發送和消息消費,性能都降低到極點。僅僅是非同步策略的1/10。
而發送到一個沒有策略的數據時候,性能得到很高的提升。與原來相同。
我們可以得到以下結論:
- 在策略下,多個node節點Mirror會降低性能。
- 同步狀態下,同步的Queue不能接受數據。其他Queue性能會受到影響。(有同步策略的Queue都有影響,性能降低到1/10。沒有同步策略的Queue,性能幾乎沒有變化。如果沒有同步狀態,對比單服務器性能下降到1/3)。
- 同步狀態下,對非同一個同步策略下的Queue影響。
兩個Slave節點的Queue數據之間進行同步之前,最好讓Queue中數據被消費完全。否則同步會造成性能的集體降低。
RabbitMQ網絡分區影響和選擇
在rabbitMQ中,我們可能會因為network partition,導致rabbitmq集群出現不同組。rabbitmq給了我們特定的三個選擇。
ignore(默認) | 認為網絡非常好,所有機器都在同一個交換機上。 |
pause_minority | 暫停,選擇最小集群作為可信集群,重新啟動其他集群。 |
autoheal | 根據連接數最高的節點,重啟其他節點。 |
如何判斷cluster保持狀態。 當節點交互keepalive時間超過之后,就會認為節點失敗。
[{rabbit:[{cluster_partiton_handling:ignore},{cluster_keepalive_interval:10000}]}]
RabbitMQ同步討論
當RabbitMQ服務器Mirror Queue隊列的其中一個Slave Node停止之后,重新連接到Master Node之后,無論數據是否有變動,都會重新驗證數據是否同步。(根據同步狀態的時間消耗,可以獲知第一次同步時候,會重新發送消息。而第一次同步之后,再次同步不會所有數據都同步)。
同步會造成發送端暫停,數據不會再被發送,客戶端會一直等待服務器Broker的Queue隊列完成同步。當客戶端Producer一直要發送數據到服務端,從而造成IO等待,不能發送數據完成。
解決相關問題:
1,使用Exchange,動態修改Exchange和Queue的版本。 2,舉例說明:
首先定義一個Exchange。為task_Exchange.
定義兩個queue,為task_queue和task_otherqueue
現將task_Exchange和task_queue構建消費隊列。
發送數據到task_Exchange和task_queue,使用routekey為test。當task_queue堆積過大,而且也需要同步的時候。
可以綁定task_Exchange和task_otherqueue。也是用routekey為test。並且取消task_Exchange和task_queue綁定。數據就會發送到其他隊列。從而減少阻塞造成的影響。
我通過實驗發現,不可以在同步狀態下進行以上操作,必須在非同步狀態下修改。同步狀態會導致客戶端連接錯誤。