rabbitmq分佈式集羣學習

集羣部署方式

rabbitmq有三種方式來部署分佈式集羣系統。php

  • Cluster
  • Federation
  • Shovel

開始學習

  • Cluster

咱們日常本地開發用的通常是單機模式,這種僅此使用本地啦,生產環境通常都是Cluster集羣。而Cluster集羣通常也會分紅兩種,普通集羣模式和鏡像集羣模式。html

使用cluster集羣,通常也有一些前提條件:node

· 屬於同一網段內的局域網節點,不支持跨網段
· rabbitmq、erlang版本須要相同
· 不一樣rabbitmq節點所使用的'.erlang.cookie'須要一致

此外還須要瞭解一些概念。git

節點類型github

· 磁盤節點(disc):將元數據存儲在磁盤中,單節點系統只容許磁盤類型的節點,防止重啓RabbitMQ的時候,丟失系統的配置信息。

· 內存節點(ram):內存節點將全部的隊列、交換機、綁定、用戶、權限和vhost的元數據定義存儲在內存中,好處是可使得像交換機和隊列聲明等操做更加的快速。

集羣元數據安全

RabbitMQ 內部有各類基礎構件,包括隊列、交換器、綁定、虛擬主機等,這些構件以元數據的形式存在:

Queue元數據:隊列的名稱和聲明隊列時設置的屬性(是否持久化、是否自動刪除、隊列所屬的節點) 
Exchange元數據:交換機的名稱、類型、屬性(是否持久化等)  
Binding元數據:一張簡單的表格展現瞭如何將消息路由到隊列。包含的列有 Exchange名稱、Exchange類型、routing\_key、queue\_name等  
vhost元數據:爲vhost內隊列、交換機和綁定提供命名空間和安全屬性

通常啓動rabbitmq時默認就爲磁盤節點。cookie

一、普通集羣模式
rabbitmq01 disc
rabbitmq02 disc網絡

在rabbitmq02上進行操做,執行命令加入集羣app

# 
# rabbitmqctl stop_app
Stopping rabbit application on node xnkl@rabbitmq02 ...
# rabbitmqctl join_cluster xnkl@rabbitmq01
Clustering node xnkl@rabbitmq02 with xnkl@rabbitmq01
# rabbitmqctl start_app
Starting node xnkl@rabbitmq02 ...
 completed with 3 plugins.
#

觀看rabbitmq02管控臺,顯示加入集羣正常分佈式

image.png

接下在rabbitmq02上操做,添加exchange。能夠看到添加交換機時,沒有節點配置的選項,這是由於rabbitmq的集羣,對於exchange的元數據在全部節點上都是一致的,並無說是歸屬某個某個節點。

image.png

而後添加queue,能夠看到當添加隊列的時候,能夠進行節點配置選擇。意思是指明這個queue的全部者節點

image.png

而後在rabbitmq01的管控臺上查看,在rabbitmq02上添加的exchange、queue都能同步到rabbitmq01上。

1.png

經過PHP腳本(PHP腳本鏈接的是rabbitmq01節點)發佈消息,發如今rabbitmq0一、rabbitmq02都能查看獲得消息,而後在rabbitmq01設置消費者取出消息並ack,發現兩個節點的隊列‘queue02’都沒有消息了。說明這個時候消息同步是正常的。

爲做測試,發佈5條消息進到隊列‘queue02’,消息都爲持久化消息。

image.png

繼續測試異常狀況。由於‘queue02’是屬於節點rabbitmq02的,如今把rabbitmq02服務關閉,在rabbitmq02服務異常的狀況下,能夠從rabbitmq01的管控臺看到‘queue02’隊列的狀態爲‘down

image.png

沒法正常查看隊列的詳情。

image.png

且經過管控臺交換機列表,查看該隊列的綁定關係,發現綁定暫時消失了。

image.png

此時再經過PHP腳本發佈消息,發現不能正常投遞(basic_publish),觸發了'return_listener',如下爲PHP腳本記錄的日誌內容。若是再聲明該隊列(queue_declare),會報錯"NOT_FOUND - home node 'xnkl@rabbitmq02' of durable queue 'queue02' in vhost '/' is down or inaccessible"。若是設置消費者消費該隊列(basic_consume),會報錯NOT_FOUND - no previously declared queue

2020-04-23 17:15:03.579[ERROR]-[23]-[App\Utility\RabbitMQ\MQCommon.App\Utility\RabbitMQ\{closure}.(/www/mqs/App/Utility/RabbitMQ/MQCommon.php:323)]: MQS_MSG_PUBLISH_ERROR|消息投遞到目標隊列不成功|replyCode:312|replyText:NO_ROUTE|exchangeName:exchange02|routingKey:exchange02|logMark:|msg:createTime: 1587633303 usedCount: 0

當隊列的全部者節點服務故障時,期間其餘節點沒法操做該隊列(包括隊列聲明、隊列消費、投遞消息),也有一些異常狀況出現(包括該隊列狀態爲‘down’,有關該隊列的綁定會暫時消失),只能等待該節點服務恢復正常,這是普通集羣模式的缺點。

當rabbitmq02服務恢復正常時,再觀察管控檯面板狀況,隊列元數據、綁定元數據、隊列消息都正常恢復。

image.png

2.png

·
·
·
·

上面測試的狀況rabbitmq02是磁盤節點,如今換成內存節點再從新測試一遍看看。更換磁盤節點類型前,須要先把rabbitmq服務先停掉,不然會報錯。執行如下命令:

# 
# rabbitmqctl change_cluster_node_type ram
Error: this command requires the 'rabbit' app to be stopped on the target node. Stop it with 'rabbitmqctl stop_app'.
Arguments given:
    change_cluster_node_type ram

Usage

rabbitmqctl [--node <node>] [--longnames] [--quiet] change_cluster_node_type <disc | ram>
# rabbitmqctl stop_app
Stopping rabbit application on node xnkl@rabbitmq02 ...
# rabbitmqctl change_cluster_node_type ram
Turning xnkl@rabbitmq02 into a ram node
# rabbitmqctl start_app
Starting node xnkl@rabbitmq02 ...
 completed with 3 plugins.
#

能夠看到更換成功。

image.png

可是更換節點類型以後,發現剛纔的隊列消失了(那隊列裏面原來的消失固然會隨之消失),估計是更換節點類型會致使隊列元數據清空的緣由(猜想,沒證明)。

image.png

可是exchange仍是存在的,不過能夠觀察到綁定元數據也消失了。

image.png

image.png

此時建立隊列、配置路由鍵,再進行上面的異常測試,把rabbitmq02節點服務停掉。發現出現的狀況跟rabbitmq02爲磁盤節點時一致(包括沒法隊列聲明、隊列消費、投遞消息、該隊列狀態爲‘down’、有關該隊列的綁定會暫時消失)。

這可能跟在網上別的博客文章描述的有一點差別,就是若是隊列的全部者節點(不管是內存節點仍是磁盤節點)發生崩潰時,該節點上的隊列元數據、綁定元數據不會丟失下圖是截自網上別的文章,能夠參考一下,由於可能存在版本不一樣而致使的不一樣結果。

image.png

因此,對於普通集羣模式的隊列,若是某個節點服務發生崩潰,那麼歸屬該節點的隊列都沒法正常操做,只能等到該節點服務恢復。

二、鏡像集羣模式

鏡像集羣模式,是在普通集羣模式的基礎上實現高可用的。就是把交換機隊列等作成鏡像,存在於多個節點當中,屬於rabbitmq的‘HA’策略方案。

在添加策略以前,隊列‘queue02’裏有5條消息。

image.png

先添加一個簡單的策略,pattern=^是匹配全部的交換機和隊列,priority優先級能夠不設,ha-mode=all爲針對集羣內的全部節點。

image.png

當添加完上面的策略以後,查看隊列的特色,能夠看到應用的策略。但也發現一些紅色異常的地方,意思應該是,rabbitmq01這個鏡像尚未進行同步,由於在添加策略前,隊列裏已經存在一些消息。‘+1’的意思是當前集羣只有2個節點,其中有一個節點還沒進行同步。

image.png

這個時候,若是rabbitmq02的服務崩潰的話,其實也會有一些異常的狀況。
· queue02隊列的狀態顯示不正常,但它不像普通集羣模式那樣顯示down。
· basic_publish,會發現不能正常發佈消息,會觸發return_listener
· queue_delcare,會報錯"NOT_FOUND - failed to perform operation on queue 'queue02' in vhost '/' due to timeout"
· basic_consume,會報錯"NOT_FOUND - no previously declared queue"
· 在管控臺發現也是沒法進行‘publish message’和‘get message’的。

image.png

image.png

這種狀況顯然是異常的,都沒法正常操做隊列。有一種解決辦法就是手動執行同步鏡像,"rabbitmqctl sync_queue queue02"。可是在同步隊列鏡像時,要確保rabbitmq02的服務是正常的,否則只會阻塞等待,而後超時報錯。

image.png

執行完同步命令以後,管控臺的‘紅色’提醒消失。以後再繼續發佈消息也可以正常完成同步。此時,若是把rabbitm02服務中止的話,隊列‘queue02’依然可以正常工做,正常發佈消息,正常消費消息等。

這就是鏡像集羣模式比普通集羣模式好的地方,實現高可用。消息實體會主動在鏡像節點之間實現同步,而不是像普通模式那樣,在consumer消費數據時臨時讀取。缺點就是,集羣內部的同步通信會佔用大量的網絡帶寬。

image.png

還有另一種辦法,就是建立策略時,多設置一些參數,通常來講也不會單單設置一個‘ha-mode’而已,一般會跟這幾個參數一塊兒設置,以下。這樣建立策略時,全部的隊列鏡像都能獲得自動同步,不會再出現紅色的異常提醒。

image.png

這樣,rabbitmq的鏡像集羣算是配置好了。鏡像集羣也是生產應用比較廣泛的模式,應該通常不多會用普通集羣模式,畢竟短板明顯擺在那裏。無論當磁盤節點崩潰,仍是隊列的全部者節點崩潰,服務同樣能夠正常訪問。

image.png

rabbitmq集羣數據同步,由於考慮到存儲空間、性能的緣由,因此集羣內部僅同步元數據。如三個節點組成了一個RabbitMQ的集羣,Exchange A的元數據信息在全部節點上是一致的,而Queue(存放消息的隊列)的完整數據則只會存在於它所建立的那個節點上,其餘節點只知道這個queue的metadata信息和一個指向queue的owner node的指針。


  • Federation

待學習


  • Shovel

待學習


引用參考

https://blog.51cto.com/111346...
https://zhuanlan.zhihu.com/p/...
https://geewu.gitbooks.io/rab...
http://chyufly.github.io/blog...

寫在最後

寫的都是一些本身在開發過程遇到的問題,絕非官方確切解釋,有不對的地方歡迎指正並討論,互相學習互相進步,纔是目的。
相關文章
相關標籤/搜索