RabbitMQ高可用-鏡像模式部署使用


RabbitMQ高可用-鏡像模式部署使用

一、概述

RabbitMQ的Cluster集群模式一般分為兩種,普通模式和鏡像模式。消息隊列通過rabbitmq HA鏡像隊列進行消息隊列實體復制。
RabbitMQ集群普通模式考慮到性能和存儲空間,僅采用元數據同步的方式。即其他節點不會實際存儲消息數據。
生產者和消費者連接在哪個節點上,則消息就存儲在哪個節點上,其他節點僅會存儲元數據,如果消費者獲取的數據不在當前節點上,則內部會路由到實際存儲消息的節點上。
我們在實際集群部署時,考慮到高可用性,一般都會使用鏡像模式。

在RabbitMQ集群中的節點只有兩種類型:內存節點/磁盤節點,單節點系統只運行磁盤類型的節點。而在集群中,可以選擇配置部分節點為內存節點。內存節點,就是將元數據(metadata)都放在內存里,磁盤節點就是放在磁盤上。如果RabbitMQ是單節點運行,默認就是磁盤節點。在RabbitMQ集群里,至少有一個磁盤節點,它用來持久保存元數據。新的節點加入集群后,會從磁盤節點上拷貝數據。但是,集群里也不必要每個節點都是磁盤節點,這主要是性能問題。例如,壓力大的RPC服務,每秒都要創建和銷毀數百個隊列,如果集群里都是磁盤節點,意味着隊列定義在每個節點上,都要寫入磁盤才算成功,這樣就會非常慢。

如果集群里只有一個磁盤節點,這個節點掛了,會發生什么?此時消息路由機制仍可正常進行(可以正常投遞和消費消息),但是不能做如下事:create queues,create exchanges,create bindings,add users,change permissions,add or remove cluster nodes
所以,考慮到高可用性,推薦在集群里保持2個磁盤節點,這樣一個掛了,另一個還可正常工作。但上述最后一點,往集群里增加或刪除節點,要求2個磁盤節點同時在線。

如果2個節點,則建議都設為磁盤節點,如果3個節點,則可2個磁盤節點+1個內存節點。

RabbitMQ安裝可參考上一篇博文:https://www.cnblogs.com/huligong1234/p/13548573.html


部署方案:
CentOS7.8 x64
mq01:192.168.100
mq02:192.168.101

二、配置普通集群模式


把mq01的cookie值復制到mq02服務器

配置cookie
vi /var/lib/rabbitmq/.erlang.cookie

確保rabbitMQ服務處於停止狀態:service rabbitmq-server stop

確保2個節點的coolie文件使用相同的值
cookie文件默認路徑為/var/lib/rabbitmq/.erlang.cookie(RPM安裝) 
或者$home/.erlang.cookie(解壓方式安裝)

.erlang.cookie設置可寫
chmod u+w /var/lib/rabbitmq/.erlang.cookie

加入集群(默認加入的為磁盤節點)
rabbitmqctl join_cluster rabbit@mq02

如果要使用內存節點,則可以使用
rabbitmqctl join_cluster --ram rabbit@mq02

查看集群狀態
rabbitmqctl cluster_status

三、配置鏡像集群模式

3.1.通過命令行配置


rabbitmqctl set_policy [ha-all] "^" '{"ha-mode":"all"}' //策略正則表達式為 “^” 表示所有匹配所有隊列名稱
rabbitmqctl set_policy -p [虛擬主機名稱] [策略名稱如ha-all ] "^" '{"ha-mode":"all" , "ha-sync-mode":"automatic"}'

在任意一個節點上執行:
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all" , "ha-sync-mode":"automatic"}'

或者指定vhost:
rabbitmqctl set_policy -p demo ha-all "^" '{"ha-mode":"all" , "ha-sync-mode":"automatic"}'
將所有隊列設置為鏡像隊列,即隊列會被復制到各個節點,各個節點狀態保持一直。
到這里,RabbitMQ 高可用集群就已經搭建好了,最后一個步驟就是搭建均衡器。

策略名稱:自定義
“^”:匹配所有隊列
ha-sync-mode: 默認為手動,可以配置為自動,區別在於,如果是自動做鏡像回復,則該隊列會處於不可用狀態直到同步完成

3.2.通過管理界面配置

界面配置示例(http://ip:15672/):

配置完后:

四、配置高可用

可以采用HAProxy+Keepalived 或 Nginx+Keepalived方式來部署實現。

我這里根據實際使用場采用另一種簡潔方案,如下圖所示,僅使用Nginx,配置backup路由策略,減輕部署復雜性。

五、集群常用命令

1、加入集群[--ram添加內存模式 默認disk模式]
rabbitmqctl join_cluster --ram rabbit@mq01

2、查看集群狀態
rabbitmqctl cluster_status

3、更改節點模式[順序 關閉運用-〉更改類型->開啟運用]
rabbitmqctl stop_app  –停止運用服務
rabbitmqctl change_cluster_node_type disc/ram –更改節點為磁盤或內存節點
rabbitmqctl start_app –開啟運用服務

4、創建策略(集群同步策略……)
set_policy [-p vhostpath] {name} {pattern} {definition} [priority]

5、查看策略
rabbitmqctl list_policies

6、移除遠程offline的節點
1.節點2停掉應用
rabbitmqctl stop_app 
2.節點1執行刪除
rabbitmqctl forget_cluster_node rabbit@mq02

7、設置集群名稱
rabbitmqctl set_cluster_name cluster_name

8、設置鏡像模式
Rabbit提供鏡像功能,需要基於rabbitmq策略來實現,政策是用來控制和修改群集范圍的某個vhost隊列行為和Exchange行為 
set_policy [-p vhostpath] {name} {pattern} {definition} [priority]
rabbitmqctl set_policy ha-all "^ha." "{""ha-mode"":""all""}"
rabbitmqctl set_policy ha-all "^" "{""ha-mode"":""all"",""ha-sync-mode"":""automatic""}"
rabbitmqctl set_policy -p demo  ha-all "^" "{""ha-mode"":""all"",""ha-sync-mode"":""automatic""}"

9、手動同步queue
rabbitmqctl sync_queue name

10、取消queue同步
rabbitmqctl cancel_sync_queue name

11、查看所有隊列信息
rabbitmqctl list_queues

12、獲取隊列信息
rabbitmqctl list_queues[-p vhostpath] [queueinfoitem ...]
Queueinfoitem可以為:name,durable,auto_delete,arguments,messages_ready,messages_unacknowledged,messages,consumers,memory。

13、獲取Exchange信息
rabbitmqctl list_exchanges[-p vhostpath] [exchangeinfoitem ...]
Exchangeinfoitem有:name,type,durable,auto_delete,internal,arguments。

14、獲取Binding信息
rabbitmqctl list_bindings[-p vhostpath] [bindinginfoitem ...] 
Bindinginfoitem有:source_name,source_kind,destination_name,destination_kind,routing_key,arguments。

15、獲取Connection信息
rabbitmqctl list_connections [connectioninfoitem ...]
Connectioninfoitem有:recv_oct,recv_cnt,send_oct,send_cnt,send_pend等。

16、獲取Channel信息
rabbitmqctl list_channels[channelinfoitem ...]
Channelinfoitem有consumer_count,messages_unacknowledged,messages_uncommitted,acks_uncommitted,messages_unconfirmed,prefetch_count,client_flow_blocked。

六、rabbitmq中鏡像隊列注意點

RabbitMQ的mirror queue(鏡像隊列)機制是最簡單的隊列HA方案,它通過在cluster的基礎上增加ha-mode、ha-param等policy選項,可以根據需求將cluster中的隊列鏡像到多個節點上,從而實現高可用,消除cluster模式中隊列內容單點帶來的風險。

在使用鏡像隊列之前,有幾點注意事項:
1.鏡像隊列不能作為負載均衡使用,因為每個操作在所有節點都要做一遍。
2.ha-mode參數和durable declare對exclusive隊列都不生效,因為exclusive隊列是連接獨占的,當連接斷開,隊列自動刪除。所以實際上這兩個參數對exclusive隊列沒有意義。
3.將新節點加入已存在的鏡像隊列時,默認情況下ha-sync-mode=manual,鏡像隊列中的消息不會主動同步到新節點,除非顯式調用同步命令。當調用同步命令(via rabbitmqctl or web-based ui)后,隊列開始阻塞,無法對其進行操作,直到同步完畢。當ha-sync-mode=automatic時,新加入節點時會默認同步已知的鏡像隊列。由於同步過程的限制,所以不建議在生產環境的active隊列(有生產消費消息)中操作。
4.每當一個節點加入或者重新加入(例如從網絡分區中恢復回來)鏡像隊列,之前保存的隊列內容會被清空。
5.鏡像隊列有主從之分,一個主節點(master),0個或多個從節點(slave)。當master宕掉后,會在slave中選舉新的master。選舉算法為最早啟動的節點。
6.當所有slave都處在(與master)未同步狀態時,並且ha-promote-on-shutdown policy設置為when-syned(默認)時,如果master因為主動的原因停掉,比如是通過rabbitmqctl stop命令停止或者優雅關閉OS,那么slave不會接管master,也就是說此時鏡像隊列不可用;但是如果master因為被動原因停掉,比如VM或者OS crash了,那么slave會接管master。這個配置項隱含的價值取向是優先保證消息可靠不丟失,放棄可用性。如果ha-promote-on-shutdown policy設置為alway,那么不論master因為何種原因停止,slave都會接管master,優先保證可用性。
7.鏡像隊列中最后一個停止的節點會是master,啟動順序必須是master先起,如果slave先起,它會有30秒的等待時間,等待master啟動,然后加入cluster。當所有節點因故(斷電等)同時離線時,每個節點都認為自己不是最后一個停止的節點。要恢復鏡像隊列,可以嘗試在30秒之內同時啟動所有節點。
8.對於鏡像隊列,客戶端basic.publish操作會同步到所有節點;而其他操作則是通過master中轉,再由master將操作作用於salve。比如一個basic.get操作,假如客戶端與slave建立了TCP連接,首先是slave將basic.get請求發送至master,由master備好數據,返回至slave,投遞給消費者。
9.由8可知,當slave宕掉時,除了與slave相連的客戶端連接全部斷開之外,沒有其他影響。當master宕掉時,會有以下連鎖反應: 1)與master相連的客戶端連接全部斷開。 2)選舉最老的slave為master。若此時所有slave處於未同步狀態,則未同步部分消息丟失。 3)新的master節點requeue所有unack消息,因為這個新節點無法區分這些unack消息是否已經到達客戶端,亦或是ack消息丟失在到老master的通路上,亦或是丟在老master組播ack消息到所有slave的通路上。所以處於消息可靠性的考慮,requeue所有unack的消息。此時客戶端可能受到重復消息。 4)如果客戶端連着slave,並且basic.consume消息時指定了x-cancel-on-ha-failover參數,那么客戶端會收到一個Consumer Cancellation Notification通知,Java SDK中會回調Consumer接口的handleCancel()方法,故需覆蓋此方法。如果不指定x-cancel-on-ha-failover參數,那么消費者就無法感知master宕機,會一直等待下去。 上面列出的注意事項整理自官方的HA文檔。

七、rabbitmq中鏡像隊列的故障恢復

前提:兩個節點(A和B)組成一個鏡像隊列。

1.場景1:A先停,B后停。 該場景下B是master(disk,A是ram),只要先啟動B,再啟動A即可。或者先啟動A,再在30秒之內啟動B即可恢復鏡像隊列。
2.場景2: A, B同時停。 該場景可能是由掉電等原因造成,只需在30秒之內連續啟動A和B即可恢復鏡像隊列。
3.場景3:A先停,B后停,且A無法恢復。 該場景是場景1的加強版,因為B是master,所以等B起來后,在B節點上調用rabbitmqctl forget_cluster_node A,解除與A的cluster關系,再將新的slave節點加入B即可重新恢復鏡像隊列。
4.場景4:A先停,B后停,且B無法恢復。 該場景是場景3的加強版,比較難處理,早在3.1.x時代之前貌似都沒什么好的解決方法,但是現在已經有解決方法了,在3.4.2版本親測有效(我們當前使用的是3.3.5)。因為B是master,所以直接啟動A是不行的,當A無法啟動時,也就沒辦法在A節點上調用rabbitmqctl forget_cluster_node B了。新版本中,forget_cluster_node支持–offline參數,offline參數允許rabbitmqctl在離線節點上執行forget_cluster_node命令,迫使RabbitMQ在未啟動的slave節點中選擇一個作為master。當在A節點執行rabbitmqctl forget_cluster_node –offline B時,RabbitMQ會mock一個節點代表A,執行forget_cluster_node命令將B剔出cluster,然后A就能正常啟動了。最后將新的slave節點加入A即可重新恢復鏡像隊列。
5.場景5: A先停,B后停,且A、B均無法恢復,但是能得到A或B的磁盤文件。 該場景是場景4的加強版,更加難處理。將A或B的數據庫文件(默認在$RABBIT_HOME/var/lib目錄中)拷貝至新節點C的目錄下,再將C的hostname改成A或B的hostname。如果拷過來的是A節點磁盤文件,按場景4處理方式;如果拷過來的是B節點磁盤文件,按場景3處理方式。最后將新的slave節點加入C即可重新恢復鏡像隊列。
6.場景6:A先停,B后停,且A、B均無法恢復,且無法得到A或B的磁盤文件。 洗洗睡吧,該場景下已無法恢復A、B隊列中的內容了。

八、更多參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM