消息隊列之RabbitMQ-分布式部署

RabbitMQ分布式部署有3種方式:

  • 集群
  • Federation
  • Shovel

Federation與Shovel都是以插件的形式來實現(xiàn),復(fù)雜性相對高驶臊,而集群是RabbitMQ的自帶屬性籽暇,相對簡單局齿。

這三種方式并不是互斥的,可以根據(jù)需求選擇相互組合來達到目的悠菜。

1舰攒、集群

1.1 基本概念

RabbitMQ本身是基于Erlang編寫,Erlang語言天生具備分布式特性(通過同步Erlang集群各節(jié)點的magic cookie來實現(xiàn))悔醋。

因此摩窃,RabbitMQ天然支持Clustering。這使得RabbitMQ本身不需要像ActiveMQ篙顺、Kafka那樣通過ZooKeeper分別來實現(xiàn)HA方案和保存集群的元數(shù)據(jù)偶芍。集群是保證可靠性的一種方式充择,同時可以通過水平擴展以達到增加消息吞吐量能力的目的。

我們把部署RabbitMQ的機器稱為節(jié)點匪蟀,也就是broker椎麦。broker有2種類型節(jié)點:磁盤節(jié)點內(nèi)存節(jié)點。顧名思義材彪,磁盤節(jié)點的broker把元數(shù)據(jù)存儲在磁盤中观挎,內(nèi)存節(jié)點把元數(shù)據(jù)存儲在內(nèi)存中,很明顯段化,磁盤節(jié)點的broker在重啟后元數(shù)據(jù)可以通過讀取磁盤進行重建嘁捷,保證了元數(shù)據(jù)不丟失,內(nèi)存節(jié)點的broker可以獲得更高的性能显熏,但在重啟后元數(shù)據(jù)就都丟了雄嚣。

元數(shù)據(jù)包含以下內(nèi)容:

  • queue元數(shù)據(jù):queue名稱、屬性
  • exchange:exchange名稱喘蟆、屬性
  • binding元數(shù)據(jù):exchange和queue之間缓升、exchange和exchange之間的綁定關(guān)系
  • vhost元數(shù)據(jù):vhost內(nèi)部的命名空間、安全屬性數(shù)據(jù)等

單節(jié)點系統(tǒng)必須是磁盤節(jié)點蕴轨,否則每次你重啟RabbitMQ之后所有的系統(tǒng)配置信息都會丟失港谊。

集群中至少有一個磁盤節(jié)點,當(dāng)節(jié)點加入和離開集群時橙弱,必須通知磁盤 節(jié)點歧寺。

如果集群中的唯一一個磁盤節(jié)點,結(jié)果這個磁盤節(jié)點還崩潰了棘脐,那會發(fā)生什么情況斜筐?集群依然可以繼續(xù)路由消息(因為其他節(jié)點元數(shù)據(jù)在還存在),但無法做以下操作:

  • 創(chuàng)建隊列荆残、交換器奴艾、綁定
  • 添加用戶
  • 更改權(quán)限
  • 添加、刪除集群節(jié)點

也就是說内斯,如果唯一磁盤的磁盤節(jié)點崩潰,集群是可以保持運行的像啼,但不能更改任何東西俘闯。為了增加可靠性,一般會在集群中設(shè)置兩個磁盤節(jié)點忽冻,只要任何一個處于工作狀態(tài)真朗,就可以保障集群的正常服務(wù)。

RabbitMQ的集群模式分為兩種:普通模式鏡像模式僧诚。

1.2 普通模式

普通模式遮婶,也是默認的集群模式蝗碎。

對于Queue來說,消息實體只存在于其中一個節(jié)點旗扑,A蹦骑、B兩個節(jié)點僅有相同的元數(shù)據(jù),即隊列結(jié)構(gòu)臀防。當(dāng)消息進入A節(jié)點的Queue中后眠菇,consumer從B節(jié)點拉取時,RabbitMQ會臨時在A袱衷、B間進行消息傳輸捎废,把A中的消息實體取出并經(jīng)過B發(fā)送給consumer。所以consumer應(yīng)盡量連接每一個節(jié)點致燥,從中取消息登疗。即對于同一個邏輯隊列,要在多個節(jié)點建立物理Queue嫌蚤。否則無論consumer連A或B辐益,出口總在A,會產(chǎn)生瓶頸搬葬。

1.png

隊列所在的節(jié)點稱為宿主節(jié)點荷腊。

隊列創(chuàng)建時,只會在宿主節(jié)點創(chuàng)建隊列的進程急凰,宿主節(jié)點包含完整的隊列信息女仰,包括元數(shù)據(jù)、狀態(tài)抡锈、內(nèi)容等等疾忍。因此,只有隊列的宿主節(jié)點才能知道隊列的所有信息床三。

隊列創(chuàng)建后一罩,集群只會同步隊列和交換器的元數(shù)據(jù)到集群中的其他節(jié)點,并不會同步隊列本身撇簿,因此非宿主節(jié)點就只知道隊列的元數(shù)據(jù)和指向該隊列宿主節(jié)點的指針聂渊。

假如現(xiàn)在一個客戶端需要對Queue A進行發(fā)布或者訂閱,發(fā)起與集群的連接四瘫,有兩種可能的場景:

  • 如果客戶端連接至Broker A汉嗽,Broker A是Queue A的宿主節(jié)點,那么此時的集群中的消息收發(fā)只與Broker A相關(guān)找蜜。
  • 如果客戶端連接至Broker B或Broker C饼暑,不是Queue A的宿主節(jié)點,那么此時的Broker主要起了一個路由轉(zhuǎn)發(fā)作用,根據(jù)這兩個節(jié)點上的元數(shù)據(jù)轉(zhuǎn)發(fā)至Broker A上弓叛。

由于節(jié)點之間存在路由轉(zhuǎn)發(fā)的情況彰居,對延遲非常敏感,應(yīng)當(dāng)只在本地局域網(wǎng)內(nèi)使用撰筷,在廣域網(wǎng)中不應(yīng)該使用集群陈惰,而應(yīng)該用Federation或者Shovel代替。

這樣的設(shè)計闭专,保證了不論從哪個broker中均可以消費所有隊列的數(shù)據(jù)奴潘,并分擔(dān)了負載,因此影钉,增加broker可以線性提高服務(wù)的性能和吞吐量画髓。

但該方案也有顯著的缺陷,那就是不能保證消息不會丟失平委。當(dāng)集群中某一節(jié)點崩潰時奈虾,崩潰節(jié)點所在的隊列進程和關(guān)聯(lián)的綁定都會消失,附加在那些隊列上的消費者也會丟失其訂閱信息廉赔,匹配該隊列的新消息也會丟失肉微。比如A為宿主節(jié)點,當(dāng)A節(jié)點故障后蜡塌,B節(jié)點無法取到A節(jié)點中還未消費的消息實體碉纳。如果做了消息持久化,那么得等A節(jié)點恢復(fù)馏艾,然后才可被消費劳曹;如果沒有持久化的話,然后就沒有然后了……

肯定有不少同學(xué)會問琅摩,想要實現(xiàn)HA方案铁孵,那將RabbitMQ集群中的所有Queue的完整數(shù)據(jù)在所有節(jié)點上都保存一份不就可以了嗎?比如類似MySQL的主主模式房资,任何一個節(jié)點出現(xiàn)故障或者宕機不可用時蜕劝,那么使用者的客戶端只要能連接至其他節(jié)點,不就能夠照常完成消息的發(fā)布和訂閱嗎轰异?

RabbitMQ這么設(shè)計是基于性能和存儲空間上來考慮:

  • 存儲空間岖沛,如果每個集群節(jié)點都擁有所有Queue的完全數(shù)據(jù)拷貝,那么每個節(jié)點的存儲空間會非常大搭独,集群的消息積壓能力會非常弱烫止,無法通過集群節(jié)點的擴容提高消息積壓能力。

  • 性能戳稽,消息的發(fā)布者需要將消息復(fù)制到每一個集群節(jié)點,對于持久化消息,網(wǎng)絡(luò)和磁盤同步復(fù)制的開銷都會明顯增惊奇,無法提升性能互躬。(此處可以引申思考一下kafka中replica的分配方式) 。

1.3 鏡像模式

引入鏡像隊列(Mirror Queue)的機制颂郎,可以將隊列鏡像到集群中的其他Broker節(jié)點之上吼渡,如果集群中的一個節(jié)點失效了,隊列能夠自動切換到鏡像中的另一個節(jié)點上以保證服務(wù)的可用性乓序。

一個鏡像隊列中包含有1個主節(jié)點master和若干個從節(jié)點slave寺酪。其主從節(jié)點包含如下幾個特點:

  • 消息的讀寫都是在master上進行,并不是讀寫分離

  • master接收命令后會向salve進行組播替劈,salve會命令執(zhí)行順序執(zhí)行

  • master失效寄雀,根據(jù)節(jié)點加入的時間,最老的slave會被提升為master

  • 互為鏡像的是隊列陨献,并非節(jié)點盒犹,集群中可以不同節(jié)點可以互為鏡像隊列,也就是說隊列的master可以分布在不同的節(jié)點上

該模式和普通模式不同之處在于眨业,消息實體會主動在鏡像節(jié)點間同步急膀,而不是在consumer取數(shù)據(jù)時臨時拉取。該模式帶來的副作用也很明顯龄捡,除了降低系統(tǒng)性能外卓嫂,如果鏡像隊列數(shù)量過多,加之大量的消息進入聘殖,集群內(nèi)部的網(wǎng)絡(luò)帶寬將會被這種同步通訊大大消耗掉晨雳。所以在對可靠性要求較高的場合中適用。

1.3.1 鏡像隊列的設(shè)置

一個隊列想做成鏡像隊列就斤,需要先設(shè)置policy悍募,然后客戶端創(chuàng)建隊列的時候,rabbitmq集群根據(jù)隊列名稱自動設(shè)置為普通隊列還是鏡像隊列洋机。

鏡像隊列的配置通過添加policy完成坠宴,policy添加的命令為:

rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]

  • -p Vhost: 可選參數(shù),針對指定vhost下的queue進行設(shè)置
  • Name: policy的名稱
  • Pattern: queue的匹配模式(正則表達式)
  • Definition: 鏡像定義绷旗,包括三個部分 ha-mode喜鼓,ha-paramsha-sync-mode
    • ha-mode: 指明鏡像隊列的模式衔肢,有效值為 all/exactly/nodes
    • all表示在集群所有的節(jié)點上進行鏡像
    • exactly表示在指定個數(shù)的節(jié)點上進行鏡像庄岖,節(jié)點的個數(shù)由ha-params指定
    • nodes表示在指定的節(jié)點上進行鏡像,節(jié)點名稱通過ha-params指定
    • ha-params: ha-mode模式需要用到的參數(shù)
    • ha-sync-mode: 鏡像隊列中消息的同步方式角骤,有效值為automatic隅忿,manually
  • Priority: 可選參數(shù)心剥, policy的優(yōu)先級

例如,對隊列名稱以hello開頭的所有隊列進行鏡像背桐,并在集群的兩個節(jié)點上完成鏡像优烧,policy的設(shè)置命令為:

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

1.3.2 鏡像隊列的實現(xiàn)原理

1.3.2.1 綜述

通常隊列由兩部分組成:一部分是AMQQueue,負責(zé)AMQP協(xié)議相關(guān)的消息處理链峭,即接收生產(chǎn)者發(fā)布的消息畦娄、向消費者投遞消息、處理消息confirm弊仪、acknowledge等等熙卡;另一部分是BackingQueue,它提供了相關(guān)的接口供AMQQueue調(diào)用励饵,完成消息的存儲以及可能的持久化工作等驳癌。

鏡像隊列基本上就是一個特殊的BackingQueue,它內(nèi)部包裹了一個普通的BackingQueue做本地消息持久化處理曲横,在此基礎(chǔ)上增加了將消息和ack復(fù)制到所有鏡像的功能喂柒。所有對mirror_queue_master的操作,會通過組播GM(下面會講到)的方式同步到各slave節(jié)點禾嫉。GM負責(zé)消息的廣播灾杰,mirror_queue_slave負責(zé)回調(diào)處理,而master上的回調(diào)處理是由coordinator負責(zé)完成熙参。mirror_queue_slave中包含了普通的BackingQueue進行消息的存儲艳吠,master節(jié)點中BackingQueue包含在mirror_queue_master中由AMQQueue進行調(diào)用。

消息的發(fā)布(除了Basic.Publish之外)與消費都是通過master節(jié)點完成孽椰。master節(jié)點對消息進行處理的同時將消息的處理動作通過GM廣播給所有的slave節(jié)點昭娩,slave節(jié)點的GM收到消息后,通過回調(diào)交由mirror_queue_slave進行實際的處理黍匾。


3.jpeg

GM(Guarenteed Multicast)是一種可靠的組播通訊協(xié)議栏渺,該協(xié)議能夠保證組播消息的原子性,即保證組中活著的節(jié)點要么都收到消息要么都收不到锐涯。它的實現(xiàn)大致如下:

將所有的節(jié)點形成一個循環(huán)鏈表磕诊,每個節(jié)點都會監(jiān)控位于自己左右兩邊的節(jié)點,當(dāng)有節(jié)點新增時纹腌,相鄰的節(jié)點保證當(dāng)前廣播的消息會復(fù)制到新的節(jié)點上霎终;當(dāng)有節(jié)點失效時,相鄰的節(jié)點會接管保證本次廣播的消息會復(fù)制到所有的節(jié)點升薯。在master節(jié)點和slave節(jié)點上的這些gm形成一個group莱褒,group(gm_group)的信息會記錄在mnesia中。不同的鏡像隊列形成不同的group涎劈。消息從master節(jié)點對于的gm發(fā)出后广凸,順著鏈表依次傳送到所有的節(jié)點阅茶,由于所有節(jié)點組成一個循環(huán)鏈表,master節(jié)點對應(yīng)的gm最終會收到自己發(fā)送的消息炮障,這個時候master節(jié)點就知道消息已經(jīng)復(fù)制到所有的slave節(jié)點了目派。

1.3.2.2 新增節(jié)點

slave節(jié)點先從gm_group中獲取對應(yīng)group的所有成員信息,然后隨機選擇一個節(jié)點并向這個節(jié)點發(fā)送請求胁赢,這個節(jié)點收到請求后,更新gm_group對應(yīng)的信息白筹,同時通知左右節(jié)點更新鄰居信息(調(diào)整對左右節(jié)點的監(jiān)控)及當(dāng)前正在廣播的消息智末,然后回復(fù)通知請求節(jié)點成功加入group。請求加入group的節(jié)點收到回復(fù)后再更新rabbit_queue中的相關(guān)信息徒河,并根據(jù)需要進行消息的同步系馆。

4.jpg
5.jpg

1.3.2.3 刪除節(jié)點

當(dāng)slave節(jié)點失效時,僅僅是相鄰節(jié)點感知顽照,然后重新調(diào)整鄰居節(jié)點信息由蘑、更新rabbit_queue、gm_group的記錄等代兵。如果是master節(jié)點失效尼酿,"資格最老"的slave節(jié)點被提升為master節(jié)點,slave節(jié)點會創(chuàng)建出新的coordinator植影,并告知gm修改回調(diào)處理為coordinator裳擎,原來的mirror_queue_slave充當(dāng)amqqueue_process處理生產(chǎn)者發(fā)布的消息,向消費者投遞消息等思币。

6.jpg

上面提到如果是slave節(jié)點失效鹿响,只有相鄰的節(jié)點能感知到,那么master節(jié)點失效是不是也是只有相鄰的節(jié)點能感知到谷饿?假如是這樣的話惶我,如果相鄰的節(jié)點不是"資格最老"的節(jié)點,怎么通知"資格最老"的節(jié)點提升為新的master節(jié)點呢?

實際上博投,所有的slave節(jié)點在加入group時绸贡,mirror_queue_slave進程會對master節(jié)點的amqqueue_process進程(也可能是mirror_queue_slave進程)進行監(jiān)控,如果master節(jié)點失效的話贬堵,mirror_queue_slave會感知恃轩,然后再通過gm進行廣播,這樣所有的節(jié)點最終都會知道m(xù)aster節(jié)點失效黎做。當(dāng)然叉跛,只有"資格最老"的節(jié)點會提升自己為新的master。

1.3.2.4 消息的廣播

消息從master節(jié)點發(fā)出蒸殿,順著節(jié)點鏈表發(fā)送筷厘。在這期間鸣峭,所有的slave節(jié)點都會對消息進行緩存,當(dāng)master節(jié)點收到自己發(fā)送的消息后酥艳,會再次廣播ack消息摊溶,同樣ack消息會順著節(jié)點鏈表經(jīng)過所有的slave節(jié)點,其作用是通知slave節(jié)點可以清除緩存的消息充石,當(dāng)ack消息回到master節(jié)點時對應(yīng)廣播消息的生命周期結(jié)束莫换。

下圖為一個簡單的示意圖,A節(jié)點為master節(jié)點骤铃,廣播一條內(nèi)容為"test"的消息拉岁。"1"表示消息為廣播的第一條消息;"id=A"表示消息的發(fā)送者為節(jié)點A惰爬。右邊是slave節(jié)點記錄的狀態(tài)信息喊暖。

7.jpg

為什么所有的節(jié)點都需要緩存一份發(fā)布的消息呢?

master發(fā)布的消息是依次經(jīng)過所有slave節(jié)點撕瞧,在這期間的任何時刻陵叽,有可能有節(jié)點失效,那么相鄰的節(jié)點可能需要重新發(fā)送給新的節(jié)點丛版。例如巩掺,A->B->C->D->A形成的循環(huán)鏈表,A為master節(jié)點硼婿,廣播消息發(fā)送給節(jié)點B锌半,B再發(fā)送給C,如果節(jié)點C收到B發(fā)送的消息還未發(fā)送給D時異常結(jié)束了寇漫,那么節(jié)點B感知后節(jié)點C失效后需要重新將消息發(fā)送給D刊殉。同樣,如果B節(jié)點將消息發(fā)送給C后州胳,B,C節(jié)點中新增了E節(jié)點记焊,那么B節(jié)點需要再將消息發(fā)送給新增的E節(jié)點。

1.3.2.5 消息的同步

配置鏡像隊列的時候有個ha-sync-mode屬性栓撞,這個有什么用呢?

新節(jié)點加入到group后遍膜,最多能從左邊節(jié)點獲取到當(dāng)前正在廣播的消息內(nèi)容由境,加入group之前已經(jīng)廣播的消息則無法獲取到频伤。如果此時master節(jié)點不幸失效璧尸,而新節(jié)點有恰好成為了新的master厚柳,那么加入group之前已經(jīng)廣播的消息則會全部丟失。

注意:這里的消息具體是指新節(jié)點加入前已經(jīng)發(fā)布并復(fù)制到所有slave節(jié)點的消息句柠,并且這些消息還未被消費者消費或者未被消費者確認秕铛。如果新節(jié)點加入前住涉,所有廣播的消息被消費者消費并確認了木人,master節(jié)點刪除消息的同時會通知slave節(jié)點完成相應(yīng)動作信柿。這種情況等同于新節(jié)點加入前沒有發(fā)布任何消息冀偶。

避免這種問題的解決辦法就是對新的slave節(jié)點進行消息同步。當(dāng)ha-sync-mode配置為自動同步(automatic)時渔嚷,新節(jié)點加入group時會自動進行消息的同步进鸠;如果配置為manually則需要手動操作完成同步。

2形病、Federation

Federation直譯過來是聯(lián)邦客年,它的設(shè)計目標是使 RabbitMQ 在不同的 Broker 節(jié)點之間進行消息傳遞而無須建
立集群。具有以下特點:

  • 支持不同管理域(不同的用戶和vhost窒朋、不同版本的RabbitMQ)中的Broker或集群間傳遞消息
  • 基于AMQP 0-9-1協(xié)議在不同的Broker之間通信搀罢,能容忍不穩(wěn)定的網(wǎng)絡(luò)連接情況

那么它到底有什么用呢?我們可以從一個實際場景入手:

有兩個服務(wù)分別部署在國內(nèi)和海外侥猩,它們之間需要通過消息隊列來通訊。

很明顯無論RabbitMQ部署在海外還是國內(nèi)抵赢,另一方一定得忍受連接上的延遲欺劳。因此我們可以在海外和國內(nèi)各部署一個MQ,這樣一來海外連接海外的MQ,國內(nèi)連接國內(nèi)铅鲤,就不會有連接上的延遲了划提。

但這樣還會有問題,假設(shè)某生產(chǎn)者將消息存入海外MQ中的某個隊列 queueB 邢享, 在國內(nèi)的服務(wù)想要消費 queueB 消息鹏往,消息的流轉(zhuǎn)及確認必然要忍受較大的網(wǎng)絡(luò)延遲 ,內(nèi)部編碼邏輯也會因這一因素變得更加復(fù)雜骇塘。

此外伊履,服務(wù)可能得維護兩個MQ的配置,比如國內(nèi)服務(wù)在生產(chǎn)消息時得使用國內(nèi)MQ款违,消費消息時得監(jiān)聽海外MQ的隊列唐瀑,降低了系統(tǒng)的維護性。

可能有人想到可以用集群插爹,但是RabbitMQ的集群對延遲非常敏感哄辣,一般部署在局域網(wǎng)內(nèi),如果部署在廣域網(wǎng)可能會產(chǎn)生網(wǎng)絡(luò)分區(qū)等等問題赠尾。

這時候力穗,F(xiàn)ederation就派上用場了。它被設(shè)計成能夠容忍不穩(wěn)定的網(wǎng)絡(luò)連接情況气嫁,完全能夠滿足這樣的場景当窗。

2.1 聯(lián)邦交換器

那使用Federation之后是怎樣的業(yè)務(wù)流程呢?

首先我們在海外MQ上定義exchangeA,它通過路由鍵“rkA”綁定著queueA杉编。然后用Federation在exchangeA上建立一條單向連接到國內(nèi)RabbitMQ超全,F(xiàn)ederation則自動會在國內(nèi)RabbitMQ建立一個exchangeA交換器(默認同名)咆霜。

8.png

這時候,如果部署在國內(nèi)的client C在國內(nèi)MQ上publish了一條消息嘶朱,這條消息會通過 Federation link 轉(zhuǎn)發(fā)到海外MQ的交換器exchangeA中蛾坯,最終消息會存入與 exchangeA 綁定的隊列 queueA 中,而client C也能立即得到返回疏遏。

實際上脉课,F(xiàn)ederation插件還會在國內(nèi)MQ建立一個內(nèi)部的交換器:exchangeA→ broker3 B(broker3是集群名),并通過路由鍵 "rkA"將它和國內(nèi)MQ的exchangeA綁定起來财异。接下來還會在國內(nèi)MQ上建立一個內(nèi)部隊列federation: exchangeA->broker3 B倘零,并與內(nèi)部exchange綁定。這些操作都是內(nèi)部的戳寸,對客戶端來說是透明的呈驶。

值得一提的是,F(xiàn)ederation的連接是單向的疫鹊,如果是在海外MQ的exchangeA上發(fā)送消息是不會轉(zhuǎn)到國內(nèi)的袖瞻。

這種在exchange上建立連接進行聯(lián)邦的,就叫做聯(lián)邦交換器拆吆。一個聯(lián)邦交換器接收上游(upstream)的信息聋迎,這里的上游指的是其他的MQ節(jié)點。

對比前面舉的例子枣耀,國內(nèi)MQ就是上游霉晕,聯(lián)邦交換器能夠?qū)⒃景l(fā)送給上游交換器的消息路由到本地的某個隊列中。

2.2 聯(lián)邦隊列

有聯(lián)邦交換器自然也有聯(lián)播隊列捞奕,聯(lián)邦隊列則允許一個本地消費者接收到來自上游隊列的消息 牺堰。

9.png

如圖,海外MQ有隊列A缝彬,給其設(shè)置一條鏈接萌焰,F(xiàn)ederation則自動會在國內(nèi)RabbitMQ建立一個隊列A(默認同名)。

當(dāng)有消費者 ClinetA連接海外MQ并消費 queueA 中的消息時谷浅,如果隊列 queueA中本身有若干消息堆積扒俯,那么 ClientA直接消費這些消息,此時海外MQ中的queueA并不會拉取國內(nèi)中的 queueA 的消息一疯;如果隊列 queueA中沒有消息堆積或者消息被消費完了撼玄,那么它會通過 Federation link 拉取上游隊列 queueA 中的消息(如果有消息),然后存儲到本地墩邀,之后再被消費者 ClientA進行消費 掌猛。

2.3 Federation使用

首先開啟Federation 功能:

##啟用插件
rabbitmq-plugins enable rabbitmq_federation
##啟用管理插件
rabbitmq-plugins enable rabbitmq_federation_management

值得注意的是,當(dāng)需要在集群中使用 Federation 功能的時候,集群中所有的節(jié)點都應(yīng)該開啟 Federation 插件荔茬。

接下來我們要配置兩個東西:upstreams和Policies废膘。

每個 upstream 用于定義與其他 Broker 建立連接的信息。

10.png

通用參數(shù)如下:

  • name: 定義這個upstreams的名稱
  • URI : 定義 upstreams的 AMQP 連接慕蔚。例如amqp://username:password@server-name/my-vhost
  • Prefetch count : 定義 Federation 內(nèi)部緩存的消息條數(shù)丐黄,即在收到上游消息之后且在發(fā)送到下游之前緩存的消息條數(shù)。
  • Reconnect delay: Federation link 由于某種原因斷開之后孔飒,需要等待多少秒開始重新建立連接灌闺。
  • Acknowledgement Mode: 定義 Federation link 的消息確認方式 。其有 3 種: on-confirm坏瞄、 on-publish 桂对、 no-acko 默認為 on-confirm,表示在接收到下游的確認消息之后再向上游發(fā)送消息確認鸠匀,這個選項可以確保網(wǎng)絡(luò)失敗或者 Broker 密機時不會丟失消息蕉斜,但也是處理速度最慢的選項。如果設(shè)置為 on-publish 缀棍,則表示消息發(fā)送到下游后(井需要等待下游的 Basic . Ack)再向上游發(fā)送消息確認蛛勉,這個選項可以確保在網(wǎng)絡(luò)失敗的情況下不會丟失消息,但不能確保 Broker 巖機時不會丟失消息睦柴。 no-ack 表示無須進行消息確認,這個選項處理速度最快毡熏,但也最容易丟失消息坦敌。
  • Expires:連接斷開后,上游隊列的超時時間痢法,默認為none狱窘,表示不刪除,單位為ms财搁。相當(dāng)于設(shè)置隊列的x-expires參數(shù)蘸炸,設(shè)置該值可以避免連接斷開后,生產(chǎn)者一直向上游隊列發(fā)送消息尖奔,造成上游大量消息堆積搭儒。

然后定義一個 Policy, 用于匹配交換器:

11.png

^exchange意思是將匹配所有以exchange名字開頭的交換器提茁,為它們在上游創(chuàng)建連接淹禾。這樣就創(chuàng)建了一個 Federation link。

3茴扁、Shovel

Shovel是RabbitMQ的一個插件铃岔, 能夠可靠、持續(xù)地從一個Broker 中的隊列(作為源端峭火,即source )拉取數(shù)據(jù)并轉(zhuǎn)發(fā)至另一個Broker 中的交換器(作為目的端毁习,即destination )智嚷。作為源端的隊列和作為目的端的交換器可以同時位于同一個 Broker 上,也可以位于不同的 Broker 上纺且。

使用Shovel有以下優(yōu)勢:

  • 松耦合盏道,解決不同Broker、集群隆檀、用戶摇天、vhost、MQ和Erlang版本之間的消息移動
  • 支持廣域網(wǎng)恐仑,基于 AMQP 0-9-1 協(xié)議實現(xiàn)泉坐,可以容忍糟糕的網(wǎng)絡(luò),允許連接斷開的同時不丟失消息
  • 高度定制裳仆,當(dāng)Shovel成功連接后腕让,可以配置

使用Shovel時,通常源為隊列歧斟,目的為交換器:

12.jpeg

但是纯丸,也可以源為隊列,目的為隊列静袖。實際也是由交換器轉(zhuǎn)發(fā)觉鼻,只不過這個交換器是默認交換器。配置交換器做為源也是可行的队橙。實際上會在源端自動新建一個隊列坠陈,消息先存在這個隊列,再被Shovel移走捐康。

使用Shovel插件命令:

##啟用插件
rabbitmq-plugins enable rabbitmq_shovel
##啟用管理插件
rabbitmq-plugins enable rabbitmq_shovel_management

Shovel 既可以部署在源端仇矾,也可以部署在目的端。有兩種方式可以部署 Shovel:

  • 靜態(tài)方式:在 rabbitmq.config 配置文件中設(shè)置
  • 動態(tài)方式:通過 Runtime Parameter 設(shè)置

其主要差異如下:

Static Shovels Dynamic Shovels
基于 broker 的配置文件進行定義 基于 broker 的 parameter 參數(shù)進行定義
需要重啟宿主 broker 以便配置生效 可以在任意時間進行創(chuàng)建和刪除解总,直接生效
更加通用:任何 queue 贮匕、exchange 或 binding 關(guān)系均可在啟動時手動聲明 更具有目標性:被 shovel 所使用的 queue 、exchange 和 binding 關(guān)系能夠自動被聲明

來看一個使用Shovel治理消息堆積的案例花枫。

當(dāng)某個隊列中的消息堆積嚴重時刻盐,比如超過某個設(shè)定的閾值,就可以通過 Shovel 將隊列中的消息移交給另一個集群乌昔。

13.png
  • 情形 1:當(dāng)檢測到當(dāng)前運行集群 cluster1 中的隊列 queue1 中有嚴重消息堆積隙疚,比如超過2 千萬或者消息占用大小(messages bytes) 超過10GB 時,就啟用 shovel1 將隊列 queue1 中的消息轉(zhuǎn)發(fā)至備份集群 cluster2 中的隊列queue2 磕道。
  • 情形 2 :緊隨情形1供屉,當(dāng)檢測到隊列queue1 中的消息個數(shù)低于1 百萬或者消息占用大小低于1GB 時就停止shovel1 ,然后讓原本隊列 queue1 中的消費者慢慢處理剩余的堆積。
  • 情形 3:當(dāng)檢測到隊列 queue1 中的消息個數(shù)低于10 萬或者消息占用大小低于100MB時伶丐,就開啟 shovel2 將隊列 queue2 中暫存的消息返還給隊列queue1 悼做。
  • 情形 4:緊隨情形3 ,當(dāng)檢測到隊列queuel 中的消息個數(shù)超過 1百萬或者消息占用大小高于1GB 時就將shovel2 停掉哗魂。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肛走,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子录别,更是在濱河造成了極大的恐慌朽色,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件组题,死亡現(xiàn)場離奇詭異葫男,居然都是意外死亡,警方通過查閱死者的電腦和手機崔列,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門梢褐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赵讯,你說我怎么就攤上這事盈咳。” “怎么了边翼?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵鱼响,是天一觀的道長。 經(jīng)常有香客問我组底,道長热押,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任斤寇,我火速辦了婚禮,結(jié)果婚禮上拥褂,老公的妹妹穿的比我還像新娘娘锁。我一直安慰自己,他們只是感情好饺鹃,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布莫秆。 她就那樣靜靜地躺著,像睡著了一般悔详。 火紅的嫁衣襯著肌膚如雪镊屎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天茄螃,我揣著相機與錄音缝驳,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛用狱,可吹牛的內(nèi)容都是我干的运怖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼夏伊,長吁一口氣:“原來是場噩夢啊……” “哼摇展!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溺忧,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咏连,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鲁森,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祟滴,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年刀森,在試婚紗的時候發(fā)現(xiàn)自己被綠了踱启。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡研底,死狀恐怖埠偿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榜晦,我是刑警寧澤冠蒋,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站乾胶,受9級特大地震影響抖剿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜识窿,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一斩郎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喻频,春花似錦缩宜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至姻蚓,卻和暖如春宋梧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狰挡。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工捂龄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留释涛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓跺讯,卻偏偏與公主長得像枢贿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刀脏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354