參考文檔: 本文涉及rabbitmq的基本安裝,基本的集群配置。 一.環境 1. 操作系統 CentOS-7-x86_64-Everything-1511 2. 版本 haproxu版本:1.7.7 erlang版本:20.0 rabbitmq版本:rabbitmq-server-3.6.10 ht ...
參考文檔:
- EPEL(Using EPEL部分):http://fedoraproject.org/wiki/EPEL/FAQ#howtouse
- erlang:https://www.erlang-solutions.com/resources/download.html
- rabbitmq download:http://www.rabbitmq.com/download.html
- rabbitmq install guide:http://www.rabbitmq.com/install-rpm.html
- 兩種集群模式的配置與管理:http://www.ywnds.com/?p=4741
本文涉及rabbitmq的基本安裝,基本的集群配置。
一.環境
1. 操作系統
CentOS-7-x86_64-Everything-1511
2. 版本
haproxu版本:1.7.7
erlang版本:20.0
rabbitmq版本:rabbitmq-server-3.6.10
3. 拓撲
- 採用VMware ESXi虛擬出的4台伺服器1台haproxy,3台rabbitmq-server,地址172.16.3.230/231/232/233;
- haproxy的預安裝配置請參考:http://www.cnblogs.com/netonline/p/7593762.html
二.RabbitMQ安裝配置(單機)
以節點rmq-node1為例,rmq-node2/3適當調整。
1. 安裝erlang
RabbbitMQ基與erlang開發,首先安裝erlang,這裡採用yum方式。
1)更新EPEL源
#yum官方源無erlang; #安裝EPEL:http://fedoraproject.org/wiki/EPEL/FAQ#howtouse [root@rmq-node1 ~]# rpm -Uvh http://download.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-9.noarch.rpm [root@rmq-node1 ~]# yum install foo
2)添加erlang解決方案庫
#如果不添加erlang解決方案,yum安裝的erlang版本會比較老; #解決方案添加及安裝請見(根據OS選擇):https://www.erlang-solutions.com/resources/download.html [root@rmq-node1 ~]# wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm [root@rmq-node1 ~]# rpm -Uvh erlang-solutions-1.0-1.noarch.rpm #需要安裝驗證簽名的公鑰; [root@rmq-node1 ~]# rpm --import https://packages.erlang-solutions.com/rpm/erlang_solutions.asc
3)安裝erlang
#下載速度會比較慢 [root@rmq-node1 ~]# yum install erlang -y
2. 安裝RabbitMQ
1)下載RabbitMQ
[root@rmq-node1 ~]# wget https://bintray.com/rabbitmq/rabbitmq-server-rpm/download_file?file_path=rabbitmq-server-3.6.10-1.el7.noarch.rpm [root@rmq-node1 ~]# mv download_file\?file_path\=rabbitmq-server-3.6.10-1.el7.noarch.rpm rabbitmq-server-3.6.10-1.el7.noarch.rpm
2)導入認證簽名
[root@rmq-node1 ~]# rpm --import https://www.rabbitmq.com/rabbitmq-release-signing-key.asc
3)安裝
#yum安裝使用已下載的rpm包本地安裝,但可能會涉及到取依賴包,同樣需要導入認證簽名; #下載安裝請見:http://www.rabbitmq.com/install-rpm.html [root@rmq-node1 ~]# yum install rabbitmq-server-3.6.10-1.el7.noarch.rpm -y
3. 啟動
1)設置開機啟動
[root@rmq-node1 ~]# systemctl enable rabbitmq-server
2)啟動
[root@rmq-node1 ~]# systemctl start rabbitmq-server
4. 驗證
1)查看狀態
[root@rmq-node1 ~]# systemctl status rabbitmq-server
2)查看日誌
#日誌中給出了rabbitmq啟動的重要信息,如node名,$home目錄,cookie hash值,日誌文件,數據存儲目錄等; #給出的信息會指出無配置文件(如下圖),預設安裝沒有此文件 [root@rmq-node1 ~]# cat /var/log/rabbitmq/[email protected]
5. rabbitmq.conf
#手工建目錄,將配置樣例文件拷貝到配置目錄並改名 [root@rmq-node1 ~]# mkdir -p /etc/rabbitmq [root@rmq-node1 ~]# cp /usr/share/doc/rabbitmq-server-3.6.10/rabbitmq.config.example /etc/rabbitmq/rabbitmq.config #配置重啟生效 [root@rmq-node1 ~]# systemctl restart rabbitmq-server #另外還可以建環境配置文件:/etc/rabbitmq/rabbitmq-env.conf
6. 安裝web管理插件
#management plugin預設就在RabbitMQ的發佈版本中,enable即可 #服務重啟,配置生效 [root@rmq-node1 ~]# rabbitmq-plugins enable rabbitmq_management
7. 設置iptables
#tcp4369埠用於集群鄰居發現; #tcp5671,5672埠用於AMQP 0.9.1 and 1.0 clients使用; #tcp15672埠用於http api與rabbitadmin訪問,後者僅限在management plugin開啟時; #tcp25672埠用於erlang分散式節點/工具通信 [root@rmq-node1 ~]# vim /etc/sysconfig/iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 4369 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 5671 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 5672 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 15672 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 25672 -j ACCEPT [root@rmq-node1 ~]# service iptables restart
8. Management plugin登錄賬
1)guest賬號
#rabbit預設只有guest賬號,但為了安全,guest賬號只能從localhost登錄,如果需要guest賬號可以遠程登錄,可以設置rabbitmq.conf文件: #根據說明,取消第64行參數的註釋與句末的符號;建議不開啟guest賬號的遠程登錄; #服務重啟,配置生效。 [root@rmq-node1 ~]# vim /etc/rabbitmq/rabbitmq.config
2)CLI創建登錄賬號
#“rabbitmqctl add_user”添加賬號,並設置密碼 [root@rmq-node1 ~]# rabbitmqctl add_user admin admin@123 #”rabbitmqctl set_user_tags”設置賬號的狀態 [root@rmq-node1 ~]# rabbitmqctl set_user_tags admin administrator #“rabbitmqctl set_permissions”設置賬號的許可權 [root@rmq-node1 ~]# rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*" #“rabbitmqctl list_users”列出賬號 [root@rmq-node1 ~]# rabbitmqctl list_users
9. Management plugin登錄驗證
瀏覽器訪問:http://172.16.3.231:15672
1)guest賬號登錄
2)CLI創建的賬號登錄
三.集群配置
RabbitMQ利用erlang的分散式特性組建集群,erlang集群通過magic cookie實現,此cookie保存在$home/.erlang.cookie,這裡即:/var/lib/rabbitmq/.erlang.cookie,需要保證集群各節點的此cookie一致,可以選取一個節點的cookie,採用scp同步到其餘節點。
1. 同步cookie
#註意.erlang.cookie文件的許可權,rabbitmq賬號,許可權400或600即可,為組或other賬號賦權會報錯 [root@rmq-node1 ~]# scp /var/lib/rabbitmq/.erlang.cookie [email protected]:/var/lib/rabbitmq/ [root@rmq-node1 ~]# scp /var/lib/rabbitmq/.erlang.cookie [email protected]:/var/lib/rabbitmq/
2. 配置hosts
#組建集群時採用”cluster@node”的格式,需要提前設置hosts文件; #rmq-node2/3配置相同 [root@rmq-node1 ~]# echo -e "172.16.3.231 rmq-node1\n172.16.3.232 rmq-node2\n172.16.3.233 rmq-node3" >> /etc/hosts
3. 使用-detached參數啟動節點
#rmq-node2/3因更換了.erlang.cookie,使用此命令會無效並報錯,可以依次採用“systemctl stop rabbitmq-server”停止服務,“systemctl start rabbitmq-server”啟動服務,最後再“rabbitmqctl stop” [root@rmq-node1 ~]# rabbitmqctl stop [root@rmq-node1 ~]# rabbitmq-server -detached
4. 組建集群(rmq-node2&rmq-node3)
1)組建集群(disk節點)
#“rabbitmqctl join_cluster rabbit@rmq-node1”中的“rabbit@rmq-node1”,rabbit代表集群名,rmq-node1代表集群節點;rmq-node2與rmq-node3均連接到rmq-node1,它們之間也會自動建立連接。 #如果需要使用記憶體節點,增加一個”--ram“的參數即可,如“rabbitmqctl join_cluster --ram rabbit@rmq-node1”,一個集群中至少需要一個”disk”節點 [root@rmq-node2 ~]# rabbitmqctl stop_app [root@rmq-node2 ~]# rabbitmqctl join_cluster rabbit@rmq-node1 [root@rmq-node2 ~]# rabbitmqctl start_app [root@rmq-node3 ~]# rabbitmqctl stop_app [root@rmq-node3 ~]# rabbitmqctl join_cluster rabbit@rmq-node1 [root@rmq-node3 ~]# rabbitmqctl start_app
2)修改disk節點到記憶體節點
#如果節點已是"disk"節點,可以修改為記憶體節點 [root@rmq-node3 ~]# rabbitmqctl stop_app [root@rmq-node3 ~]# rabbitmqctl change_cluster_node_type ram [root@rmq-node3 ~]# rabbitmqctl start_app
5. 查看集群狀態
[root@rmq-node1 ~]# rabbitmqctl cluster_status
- 3個節點正常運行,其中rmq-node3是記憶體節點;
- 另外節點間的元數據也會同步,如前文只在rmq-node1節點創建的admin賬號,此時也可在其他兩個節點查詢;
- 但節點間的配置文件不會同步,如前文在rmq-node1節點允許的guest賬號遠程登錄,此時其他節點的guest賬號並不具備登錄許可權。
6. 設置鏡像隊列高可用
到目前為止,集群雖然搭建成功,但只是預設的普通集群,exchange,binding等數據可以複製到集群各節點。
但對於隊列來說,各節點只有相同的元數據,即隊列結構,但隊列實體只存在於創建改隊列的節點,即隊列內容不會複製(從其餘節點讀取,可以建立臨時的通信傳輸)。
這樣此節點宕機後,其餘節點無法從宕機節點獲取還未消費的消息實體。如果做了持久化,則需要等待宕機節點恢復,期間其餘節點不能創建宕機節點已創建過的持久化隊列;如果未做持久化,則消息丟失。
#任意節點執行均可如下命令:將所有隊列設置為鏡像隊列,即隊列會被覆制到各個節點,各個節點狀態保持一直; #可通過命令查看:rabbitmqctl list_policies; #鏡像隊列相關解釋與設置&操作等請見:http://www.ywnds.com/?p=4741 [root@rmq-node1 ~]# rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
四.設置Haproxy
1. haproxy.cfg
#這裡只給出針對rabbit_cluster的監控配置,global與default配置請見:http://www.cnblogs.com/netonline/p/7593762.html [root@haproxy-1 ~]# vim /usr/local/haproxy/etc/haproxy.cfg listen RabbitMQ_Cluster #監控模式 mode tcp #負載均衡模式 balance roundrobin #訪問埠 bind 0.0.0.0:5672 #後端伺服器檢測 server rmq-node1 172.16.3.231:15672 check inter 2000 rise 2 fall 3 server rmq-node2 172.16.3.232:15672 check inter 2000 rise 2 fall 3 server rmq-node3 172.16.3.233:15672 check inter 2000 rise 2 fall 3
2. 效果驗證
五.註意事項與遇到的問題
1. 註意事項
- cookie在所有節點上必須完全一樣,同步時註意;
- erlang是通過主機名來連接服務,必須保證各個主機名之間可以ping通,可以通過編輯/etc/hosts來手工添加主機名和IP對應關係,如果主機名ping不通,rabbitmq服務啟動會失敗;
- 如果queue是非持久化queue,則如果創建queue的那個節點失敗,發送方和接收方可以創建同樣的queue繼續運作;如果是持久化queue,則只能等創建queue的那個節點恢復後才能繼續服務。
- 在集群元數據有變動的時候需要有disk node線上,但是在節點加入或退出時,所有的disk node必須全部線上;如果沒有正確退出disk node,集群會認為這個節點宕掉了,在這個節點恢復之前不要加入其它節點。
2. 網路分區問題
在完成集群後,遇到過1個"partitioned network"的錯誤。
網路分區具體問題請參考:https://www.rabbitmq.com/partitions.html
中文翻譯:https://my.oschina.net/moooofly/blog/424660
1)現象
rmq-node1& rmq-node3與rmq-node2分裂成了兩個網路分區
2)查看日誌
查看rmq-node1與rmq-node2日誌可以印證網路分區的形成時間
3)原因
如果其他節點無法連接該節點的時間達到1分鐘以上(net_ticktime設定),則Mnesia判定某個其他節點失效。當這兩個連接失效的節點恢復連接狀態時,都會認為對端已down 掉,此時Mnesia將會判定發生了網路分區,這種情況會被記錄進 RabbitMQ 的日誌文件中。
導致網路分區的原因有很多,常見如下:
- 網路本身的原因;
- 掛起與恢復節點也會導致網路分區,最常見與節點本身是vm,而虛擬化操作系統的監控程式便有掛起vm的功能;
- vm遷移(飄移)也會導致虛擬機掛起。
發生網路分區時,各分區均能夠獨立運行,同時認為其餘節點(分區)已處於不可用狀態。其中 queue、binding、exchange 均能夠在各個分區中創建和刪除;當由於網路分區而被割裂的鏡像隊列,最後會演變成每個分區中產生一個 master ,並且每一個分區均能獨立進行工作,其他未定義和奇怪的行為也可能發生。
4)恢復
手工處理
- 選擇一個可信分區;
- 對於其餘非可信分區的節點,停止服務,重新加入集群,此操作會導致非信任分區內的操作丟失;
- 重啟信任分區內的節點,消除告警(此點是官網上明確的,但經實際驗證似乎不需要)。
#更簡單直接的方式是:重啟集群所有節點,但需要保證重啟的第一個節點是可信任的節點。
#同時也可以觀察3個節點的日誌。
自動處理
RabbitMQ提供3種自動處理方式:pause-minority mode, pause-if-all-down mode and autoheal mode;預設的行為是ignore mode,不做處理,此模式適合網路非常穩定的場景。
- pause-minority:此模式下,如果發現有節點失效,RabbitMQ將會自動停止少數派集群(即少於或等於半數節點數)中的所有節點。這種策略選擇了CAP 理論中的分區容錯性(P),而放棄了可用性(A),保證了在發生網路分區時,最多只有一個分區中的節點會繼續工作;而處於少數派集群中的節點將在分區發生的開始就被停止,在分區恢復後重新啟動(繼續運行但不監聽任何埠或做其他工作,其將每秒檢測一次集群中的其他節點是否可見,若可見則從pause狀態喚醒)。對於節點掛起引起的網路分區,此模式無效,因為掛起節點不能看到其餘節點是否恢復"可見",因而不能觸發從cluster中斷開。
- pause-if-all-down:此模式下,RabbitMQ會自動停止集群中的節點,只要某節點與列舉出來的任何節點之間無法通信。這與pause-minority模式比較接近,但該模式允許管理員來決定採用哪些節點做判定;可能存在列舉出來的多個節點本身就處於無法通信的不同分區中,此時不會有任何節點被停掉。
- autoheal:此模式下,RabbitMQ將在發生網路分區時,自動決定出一個勝出分區(獲勝分區是獲得最多客戶端連接的那個分區;如果產生平局,則選擇擁有最多節點的分區;如果仍是平局,則隨機選擇),並重啟不在該分區中的所有節點。與pause_minority模式不同的是,autoheal 模式是在分區結束階段(已經形成穩定的分區)時起作用,而不是在分區開始階段(剛剛開始分區)。此模式適合更看重服務的可持續行勝於數據完整性的場景。
自動處理配置文件:/etc/rabbitmq/rabbitmq.conf,第279行"cluster_partition_handling"項,可配置參數如下:
pause_minority
{pause_if_all_down, [nodes], ignore | autoheal}
autoheal
配置文件請參考:https://www.rabbitmq.com/configure.html#configuration-file