RabbitMQ集羣搭建

推薦相關文章閱讀:前端

入門RabbitMQ

RabbitMQ核心原理和知識點

實戰RabbitMQ

 

安裝和準備節點

 

一、準備3個節點(下面是筆者的主機列表):java

 

主機名稱node

iplinux

node1nginx

10.68.212.101正則表達式

node2瀏覽器

10.68.212.102服務器

node3cookie

10.68.212.103網絡

 

官方強烈建議集羣節點數量爲奇數,例如:一、三、五、7。

 

二、每一個節點安裝好rabbitmq服務,關於安裝能夠查看本人前面發佈的文章。

 

入門RabbitMQ 

 

三、修改每一個對應節點的hostname:

 

  •  
# node1節點執行hostnamectl set-hostname node1# node2節點執行hostnamectl set-hostname node2# node3節點執行hostnamectl set-hostname node3reboot #重啓

 

 

由於集羣節點之間默認經過節點名稱標識相互聯繫,因此集羣節點名稱必須惟一。節點名稱默認爲:rabbit@hostname,例如node1節點的默認節點名稱爲rabbit@node1,這裏hostname很重要,必定是本機hostname,且要確保全部節點正確配置了/etc/hosts,由於節點之間是經過節點名稱的hostname部分進行通訊的,除了默認以外節點名稱還能夠經過配置環境變量RABBITMQ_NODENAME來修改,可是格式必定要符合xxx@hostname。

 

四、每一個節點配置/etc/hosts,經過hostname獲取主機節點名稱後進行配置,筆者這裏配置以下:

 

 

  •  
10.68.212.101  node110.68.212.102  node210.68.212.103  node3
#經過ping進行測試ping node1ping node2ping node3

 

五、經過下面命令啓動每一個節點rabbitmq服務,確保可以正常啓動:

  •  
rabbitmq-server -detached

六、經過下面命令查看每一個節點的集羣狀態,默認單節點啓動就是一個單節點的集羣:

  •  
rabbitmqctl cluster_status

 

 

正常狀況下能夠看到以下輸出:

 

 

  •  
Cluster name: rabbit@node1  #集羣名稱,默認是節點名稱Disk Nodes # 磁盤類型節點列表rabbit@node1 # 節點名稱Running Nodes # 正在運行節點列表rabbit@node1............省略其它

至此,3個節點安裝完畢,且可以正常啓動,下面咱們開始建立集羣。

 

建立集羣

 

一、由於集羣節點之間須要互相通訊,因此須要開通端口策略,簡單粗暴方式是直接關閉防火牆,可是生產環境不推薦這麼作,推薦作法是全部節點執行下面linux命令開通必要的端口:

  •  
firewall-cmd --zone=public --add-port=4369/tcp --permanentfirewall-cmd --zone=public --add-port=25672/tcp --permanentfirewall-cmd --zone=public --add-port=5672/tcp --permanentfirewall-cmd --zone=public --add-port=15672/tcp --permanentfirewall-cmd --zone=public --add-port=35672-35682/tcp --permanentfirewall-cmd --reload

 

二、配置cli命令工具和rabbitm服務身份驗證的erlang cookie,對每一個節點經過以下方式進行配置:

 

  •  
# 中止全部節點的rabbitmq服務和erlang jvm進程rabbitmqctl stop# 配置root用戶使用CLI命令cookie爲123456(123456能夠改成其它複雜的值)echo "123456" > /root/.erlang.cookie# 建立rabbitmq服務端cookie目錄和文件mkdir -p /var/lib/rabbitmqtouch /var/lib/rabbitmq/.erlang.cookie# 配置rabbitmq服務端cookie爲123456echo "123456" > /var/lib/rabbitmq/.erlang.cookie

 

三、經過下面命令啓動因此節點:

  •  
rabbitmq-server -detached

 

四、將node2節點重置後加入node1節點集羣,在node2節點上執行下面的命令:

 

  •  
rabbitmqctl stop_apprabbitmqctl resetrabbitmqctl join_cluster rabbit@node1

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

五、查看node1集羣狀況,回到node1節點,執行下面的命令:

  •  
rabbitmqctl cluster_status

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

六、回到node2執行下面命令,啓動node2節點:

  •  
rabbitmqctl start_app

 

七、再次回到node1,查看集羣狀態:

  •  
rabbitmqctl cluster_status

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

八、繼續將node3加入node1集羣:

 

  •  
rabbitmqctl stop_apprabbitmqctl resetrabbitmqctl join_cluster rabbit@node1rabbitmqctl start_app

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

九、回到node1節點查看集羣狀態,固然也能夠直接在node2和node3節點經過查看集羣狀態顯示的結果也是和在node1節點查看顯示結果是同樣的:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

十、至此,由3個節點組成的集羣建立完畢。如今咱們還能夠中止集羣中的某個節點,例如中止node1,在node1節點上執行下面命令:

  •  
rabbitmqctl stop

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

而後在node2或node3節點上查看集羣狀態:

 

  •  
rabbitmqctl cluster_status

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

而後下面命令再次啓動node1,此時node1將會從中止時標記的對等節點同步集羣數據信息,若是對等節點不可用,則node1將啓動失敗,後面會提到如何解決沒法啓動的狀況。

  •  
rabbitmq-server -detached

 

 

十一、將某個節點重置後,該節點將忘記集羣,等同退出集羣,例如在node3節點上執行:

 

  •  
rabbitmqctl stop_apprabbitmqctl resetrabbitmqctl start_app

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

同時查看原理集羣信息以下:

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

十二、若是某個節點宕機沒法訪問,那麼咱們能夠從其它可用的集羣節點上剔除該不可用的宕機節點,例如咱們模擬把node1節點停掉,而後在node2節點上剔除node1節點,命令以下:

 

 

  •  
# node1節點執行 rabbitmqctl stop
# node2節點執行rabbitmqctl forget_cluster_node rabbit@node1

 

 

如今在node2節點查看集羣狀態信息以下:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

注意,如今node2仍然保留原來集羣最終的狀態,若是要徹底解散集羣,應該繼續將node2進行重置,重置rabbitmq節點將刪除其全部數據。

 

另外,若是此時再次啓動node1,會收到如下報錯信息:

Node rabbit@node1 thinks it's clustered with node rabbit@node2, but rabbit@node2 disagrees

 

緣由是node1中止時將node2標記爲下次啓動時的對等節點,可是node2已經將node1從集羣剔除出去,此時node1啓動請求從node2同步數據時被拒絕,解決這個問題的辦法是當node1在啓動嘗試10次請求鏈接node2的時間窗口內快速執行重置命令將node1進行重置,完整命令以下:

 

 

  •  
rabbitmq-server -detached# 執行完上面命令後快速執行重置命令,注意必定要快rabbitmqctl reset

 

若是前面但願時間窗口加長,能夠經過修改rabbitmq配置文件下面兩個配置項:

 

  •  
#等待60秒而不是30mnesia_table_loading_retry_timeout = 60000#重試15次而不是10mnesia_table_loading_retry_limit = 15

 

默認配置文件位置,新安裝的服務器不存在該文件須要手工建立:

  •  
$RABBITMQ_HOME/etc/rabbitmq/rabbitmq/rabbitmq-env.conf

 

1三、咱們能夠經過下面命令修改節點的類型爲磁盤或RAM:

 

 

  •  
# 修改成磁盤類型rabbitmqctl stop_apprabbitmqctl change_cluster_node_type discrabbitmqctl start_app
# 修改成內存類型rabbitmqctl stop_apprabbitmqctl change_cluster_node_type ramrabbitmqctl start_app
# 或者直接在加入集羣時指定節點以什麼類型加入rabbitmqctl join_cluster --ram rabbit@node1

 

集羣核心原理

 

一、經過前面的方式建立集羣后,集羣全部節點的數據或狀態信息互相同步複製,除了消息隊列外,消息隊列默認狀況下只保存在一個節點上,客戶端若是訪問到其它節點上時,其它節點會路由到對應的隊列主節點上。也就是說集羣並無實現隊列的高可用,若是隊列所在節點掛了,那麼宕機節點上的全部隊列將不可用,若是要實現隊列高可用,後面會單獨介紹一種叫隊列鏡像的方式來實現。

 

二、Admin管理插件會將集羣全部節點信息彙總一併展現到前端頁面。

 

三、集羣節點數量強烈建議爲奇數,例如:一、三、五、7。

 

四、集羣中節點能夠時磁盤類型,也能夠是RAM內存類型,RAM類型目的是爲了提高吞吐量,因爲RAM類型節點全部數據在啓動時從其它磁盤(只會選擇磁盤類型節點)節點同步,因此一個集羣必須至少有一個磁盤類型節點,一般建議是把所有節點都配置爲磁盤節點。

 

五、集羣節點在中止時會選擇並標識一個可用的對等磁盤類型節點,做用是在下次啓動時從這個標識的對等節點同步數據。若是啓動時這個對等節點不可用(默認是嘗試鏈接10次,每次超時30s),則該啓動失敗。可是若是中止時沒有可用的對等節點,好比最後中止的節點,那麼這個節點在下次啓動時將不會鏈接對等節點來同步數據,而是直接啓動,其它節點可以再次加入它。

 

六、當某個節點被重置後,或修改hostname後,再次重啓將沒法識別原理的集羣,而是以單節點方式啓動。

 

鏡像隊列

 

概念原理部分:

 

前面搭建的集羣除了隊列數據外其它數據例如交換和綁定都是在全部節點進行復制,經過鏡像隊列能夠彌補隊列高可用的問題,鏡像隊列思想是將隊列配置爲一主多從,每一個隊列都有一個主節點,多個鏡像節點,全部操做都是先在主節點上進行,而後複製到鏡像節點,這樣能夠保證消息的FIFO順序。鏡像隊列不會同步被主節點隊列確認的消息。實際上鏡像隊列只實現高可用,而沒有實現負載均衡的效果。若是主服務器發生故障,則將最先的鏡像提高爲主節點。rabbitmq經過策略policy的方式來配置鏡像隊列,policy按名稱正則表達式方式進行隊列的匹配,下面是一個例子:

 

 

  •  
rabbitmqctl set_policy ha-hello "^hello\." \  '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

 

  • set_policy:表示建立policy

  • ha-hello:表示policy名稱

  • ^hello\.:表示該policy匹配名稱以hello開頭的隊列

  • ha-mode:指定鏡像隊列複製因子模式,後面經過表格來講明

  • ha-params: 配套ha-mode可選參數

  • ha-sync-mode:同步模式。

 

ha-mode

ha-params

描述

exactly

數量

指定鏡像隊列副本數量,具體數量由ha-params指定

all

隊列鏡像到集羣全部節點,能夠配合仲裁節點一塊兒使用。

nodes

節點名稱

隊列鏡像到指定的集羣節點名稱。

 

任什麼時候候均可以修改policy,當policy發生變化時,它將努力將其現有鏡像保留到與新策略相適應的程度。rabbitmq鏡像隊列複製數量最佳多少比較合適,官方給出是經驗是3個節點2個,5個節點3個。除了能夠配置鏡像節點數量策略外,還能夠配置主節點位置策略,隊列主節點位置策略是經過建立隊列時指定x-queue-master-locator策略屬性來配置,可配置下面3種策略:

 

策略屬性值

描述

min-masters

選擇託管最少主節點數量的節點做爲當前隊列的主節點

client-local

選擇客戶端鏈接到的節點做爲當前隊列的主節點

random

隨機選擇一個節點做爲當前隊列的主節點

 

實戰部分:

 

一、查看前面搭建的集羣狀態:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

二、經過下面java客戶端代碼建立3個測試隊列:

 

pom.xml座標:

 

  •  
<dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>4.11.3</version></dependency>

 

Main方法測試代碼以下:

 

 

  •  
public class Main {
public static void main(String[] args) throws Exception { ConnectionFactory factory = new ConnectionFactory(); //這裏先訪問其中一個節點,後續經過軟負載均衡器nginx進行rabbitmq集羣服務的負載均衡 factory.setHost("10.68.212.101"); //rabbitmqctl add_user lazy 111111 //rabbitmqctl set_user_tags lazy administrator //rabbitmqctl set_permissions -p / lazy ".*" ".*" ".*" factory.setUsername("lazy"); factory.setPassword("111111"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel();
channel.queueDeclare("hello1-queue", true, false,false, null); channel.queueDeclare("hello2-queue", true, false, false, null); channel.queueDeclare("hello3-queue", true, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); }
}

 

三、登陸集羣任何一個節點能夠查看隊列列表:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

四、兩種方式能夠查看隊列鏡像信息:

 

  •  
# 經過CLI命令行(第一種)rabbitmqctl list_queues name policy pid slave_pids
# 者在全部節點執行下面命令開啓admin管理插件(第二種)rabbitmq-plugins enable rabbitmq_management而後在任何一個節點訪問,後續會搭建nginx進行軟負載:http://10.68.212.101:15672/登陸帳號和密碼爲:lazy / 111111

 

第一種方式截圖:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

第二種方式截圖:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

五、分別建立3個policy:

 

 

  •  
# 將hello1-開頭的全部隊列鏡像模式設置爲exactlyrabbitmqctl set_policy --vhost / --apply-to queues  ha-exactly-demo "^hello1-*" \ '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
# 將hello2-開頭的全部隊列鏡像模式設置爲allrabbitmqctl set_policy --vhost / --apply-to queues ha-all-demo "^hello2-*" \ '{"ha-mode":"all"}'
# 將hello3-開頭的全部隊列鏡像模式設置爲nodes,節點爲node2,node3rabbitmqctl set_policy --vhost / --apply-to queues ha-nodes-demo "^hello3-*" \ '{"ha-mode":"nodes","ha-params":["rabbit@node2", "rabbit@node3"]}'

 

 

六、查看policy生效狀況:

 

# 經過CLI命令行(第一種)查看:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

# 經過管理頁面(第二種)查看:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

深度解答鏡像問題:

 

一、若是修改某個隊列的策略致使新的策略的節點不包含任何原理策略的節點,例如原來策略是node1,node2,新的策略節點配置爲node3,node4,這種狀況下數據如何遷移?

 

答:這種狀況會新的策略會包含node3,node4節點以及原來策略的主節點例如node1,而後node3,node4會從原來策略的主節點node1同步消息數據,直到同步完成纔將node1剔除。

 

二、當rabbitmq鏈接關閉時排他隊列將被刪除,請問排他隊列能夠作鏡像嗎?

 

答:排他隊列永遠不會被鏡像。

 

三、若是rabbitmq鏡像隊列主節點發生故障,如何提高鏡像節點?

答:會將運行時間最長的鏡像節點提高爲主節點。可是默認狀況下

 

四、若是rabbitmq鏡像隊列主節點發生故障,會丟失哪些狀況的數據嗎?

 

答:鏡像節點默認只會同步鏡像節點第一次或從新加入(置空歷史消息數據)作爲主節點那一刻時間以後的主節點新的消息,不會同步加入主節點以前的消息。

從消費端來分析:若是過程當中主節點發生故障,而後提高該鏡像節點爲主節點,那麼可能會丟失鏡像節點加入以前的歷史消息數據(若是消費速度很慢沒有被消費完的話,可是能夠經過配置爲不自動提高非全量同步的鏡像節點爲主節點,而後經過手動同步全量數量後來彌補這個問題,注意同步過程會使全部其它隊列阻塞)。而後從新排隊當前鏡像節點還沒有收到消費者確認的那部分消息發送給消費者,因此消費者必須作好冪等性處理(由於可能會重複),因此消費端可能會丟失數據,也可能會重複收到消息。

從發送端來分析:若是發送者配置爲自動確認模式,若是剛好當發送消息到主節點的同時主節點掛斷,那麼消息可能會丟失。可是發送者若是配置爲手工確認模式,那麼主節點會保證全部鏡像節點都接受到該消息,纔會向發佈者確認並按期被落盤,因此,若是主節點掛斷,那麼發送者能夠正確知道消息確認狀況,因此發送者只要配置確認機制,基本消息不會丟失。不然,會發生丟失的可能。

 

五、鏡像節點如何手工同步主隊列節點的全量消息數據?

答:能夠經過下面命令手工不一樣歷史消息數據:

  •  
 rabbitmqctl sync_queue your_queue_name

 

六、如何配置爲不自動提高非全量同步的鏡像節點?

答:從rabbitmq3.7.5版本開始,能夠經過配置隊列聲明屬性:ha-promote-on-failure值爲:when-synced來確保不自動提高非全量同步的鏡像來防止歷史數據的丟失,默認值爲:always表示老是自動提高非全量同步鏡像節點。當值配置爲:when-synced時,發送者必須使用手動確認模式才能徹底確保消息總體不丟失,不然when-synced配置就是毫無心義的。

 

七、如何查看隊列節點同步狀況?

答:能夠經過下面命令查看:

  •  
rabbitmqctl list_queues name slave_pids synchronised_slave_pids

 

八、如何配置鏡像節點爲老是默認全量同步主隊列全部歷史數據?

答:能夠經過配置隊列聲明屬性:ha-sync-mode值爲:manual表示歷史全量數據須要手動同步,值爲:automatic表示自動同步歷史全量數據。

 

九、手動關閉rabbitmq節點,會提高鏡像隊列嗎?

答:默認狀況下,rabbitmq顯示中止或操做系統關閉時,不會提高鏡像隊列爲主隊列的,此時整個隊列爲關閉狀態。可是若是因爲節點崩潰例如內存溢出,磁盤爆滿或者網絡中斷、剔除集羣等緣由時,纔會提高鏡像隊列爲主隊列。

 

經過Nginx實現集羣節點負載均衡:

 

一、安裝nginx,這裏挑選node1節點來安裝nginx:

 

  •  
cd /opt/tarballwget http://nginx.org/download/nginx-1.16.1.tar.gztar -xvf nginx-1.16.1.tar.gz -C /opt/src/cd /opt/src/nginx-1.16.1/./configure --with-streammakemake install

 

二、配置nginx環境變量:

 

  •  
vi /etc/profilesource /etc/profile

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

三、啓動nginx:

  •  
nginx

 

四、配置nginx負載均衡和代理轉發:

  •  
vi /usr/local/nginx/conf/nginx.conf

 

關鍵配置內容以下:

 

  •  
stream {        upstream rabbitmq_server {                server node1:5672;                server node2:5672;                server node3:5672;        }        server {                listen       18080;                proxy_connect_timeout 5s;                proxy_timeout 5s;                proxy_pass   rabbitmq_server;        }
}
http { upstream rabbitmq_admin { server node1:15672; server node2:15672; server node3:15672;    } server { listen 18081; server_name rabbitmq_admin;
location / { proxy_pass http://rabbitmq_admin; } }}

 

五、修改node1防火牆端口策略:

 

  •  
firewall-cmd --zone=public --add-port=18080/tcp --permanentfirewall-cmd --zone=public --add-port=18081/tcp --permanentfirewall-cmd --reload

 

六、瀏覽器訪問nginx負載均衡admin地址:

http://10.68.212.101:18081/

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

七、java客戶端代碼修改成以下鏈接地址:

 

 

  •  
public class Main {        public static void main(String[] args) throws Exception {                ConnectionFactory factory = new ConnectionFactory();                //訪問nginx地址                factory.setHost("10.68.212.101");                factory.setPort(18080);                //rabbitmqctl add_user lazy 111111                //rabbitmqctl set_user_tags lazy administrator                //rabbitmqctl set_permissions -p / lazy ".*" ".*" ".*"                factory.setUsername("lazy");                factory.setPassword("111111");                Connection connection = factory.newConnection();                Channel channel = connection.createChannel();
channel.queueDeclare("hello1-queue", true, false,false, null); channel.queueDeclare("hello2-queue", true, false, false, null); channel.queueDeclare("hello3-queue", true, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); }
}

 

至此,rabbitmq集羣搭建講解完畢。

 

---------------------- 正文結束 ------------------------

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索