RabbitMQ概念及環境搭建(四)RabbitMQ High Availability

####################################################
RabbitMQ High Availability
####################################################
1.高可用queue
默認狀況下RabbitMQ cluster中的queues位於單獨的節點(queues被首次聲明的節點),而exchanges和bindings存在於cluster中各節點。於是每一個節點失效exchanges和bindings並沒有影響,單弱queues所在的節點失效就會影響該節點上存在的queues。可是。queues能夠在多個節點上鏡像。每一個被鏡像的queue包含一個master和一個或者多個slave。若原master失效則最舊的slave被提高爲新的master。

publish到queue的message會被複制到各個slave、consumers不管從cluster中哪一個節點鏈接都會鏈接到master上,對於已經自master上被確認的message各slave會丟棄。因此,queue鏡像只是加強了可用性。並無在各節點間均衡負載。

該方案須要RabbitMQ cluster, 不能再cluster內處理network partitions於是不推薦在WAN中使用,僅用於LAN。

2.配置鏡像
經過policy進行,可在任意時刻更改,將non-mirrored queue改成mirrored queue,或者反之。需注意的是non-mirrored queue與沒有slave的mirrore的queue並不相同,前者無需額外mirroring架構運行的更快。
可用的policy
ha-mode   ha-params   行爲
all                              queue被mirror到cluster中全部節點。
                                 cluster中新添加節點,queue也會被mirror到該節點。
exactly   count            queue被mirror到指定數目的節點。
                                 count大於cluster中節點數則queue被mirror到全部節點。
                                 若count小於cluster中節點數,在包含mirror的某節點down後不會在其餘節點建新的mirror(爲避免cluster中queue migrating)
nodes     node names  queue被mirror到指定名字的節點。
                                 若任一名稱在cluster中不存在並不會引起錯誤。
                                若指定的任何節點在queue聲明時都不在線則queue在被鏈接到的節點建立。

關於nodes類型的policy
設置或更改nodes類型的policy可能引發原master遷移。好比原master沒有出現的新的lolicy節點列表中時。RabbitMQ採起的策略是保持原master直到至少一個新的slave已經同步,一旦同步後原master立刻自動失效。原consumer鏈接會斷掉,需重連。
如,原queue在節點{A,B},A爲master。來一個新的policy{C,D},會有一段時間的狀態爲{A,C,D},待queue同步後A上的master關閉,新的mirror爲{C,D}

特殊queue:Exclusivequeues
exclusive queues不會被鏡像(mirror)也不會被持久化(durable),即便被聲明爲如此。由於一但存放queue的節點down了上邊的鏈接也會斷掉,對於exclusive queues相關的queue會被立刻刪除。

3.鏡像配置示例(可經過多種方式)
下面的例子將「ha.」開頭的queue mirror到cluster中全部節點
rabbitmqctl   rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'
HTTP API    PUT /api/policies/%2f/ha-all {"pattern":"^ha\.", "definition":{"ha-mode":"all"}}
Web UI        Navigate to Admin > Policies > Add / update a policy.
                  Enter "ha-all" next to Name, "^ha\." next to Pattern, and "ha-mode" = "all" in the first line next to Policy.
                  Click Add policy.

下面的例子將「two.」開頭的queue mirror到cluster中兩個節點,且自動同步
rabbitmqctl    rabbitmqctl set_policy ha-two "^two\." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
HTTP API    PUT /api/policies/%2f/ha-two {"pattern":"^two\.", "definition":{"ha-mode":"exactly", "ha-params":2,"ha-sync-mode":"automatic"}}
Web UI        Navigate to Admin > Policies > Add / update a policy.
                   Enter "ha-two" next to Name and "^two\." next to Pattern.
                   Enter "ha-mode" = "exactly" in the first line next to Policy, then "ha-params" = 2 in the second line, then "ha-sync-mode" = "automatic" in the third, and set the type on the second line to "Number".
                   Click Add policy.


下面的例子將「nodes.」開通的queue mirror到cluster中特定的node
rabbitmqctl   rabbitmqctl set_policy ha-nodes "^nodes\." '{"ha-mode":"nodes","ha-params":["nodeA", "nodeB"]}'
HTTP API    PUT /api/policies/%2f/ha-nodes {"pattern":"^nodes\.", "definition":{"ha-mode":"nodes", "ha-params":["nodeA", "nodeB"]}
Web UI        Navigate to Admin > Policies > Add / update a policy.
                   Enter "ha-nodes" next to Name and "^nodes\." next to Pattern.
                   Enter "ha-mode" = "nodes" in the first line next to Policy, then "ha-params" in the second line, set the second line's type to "List", and then enter "nodeA" and "nodeB" in the sublist which appears.
                  Click Add policy.

4.其餘注意事項
非同步的slaves
node可在任意時刻加入RabbitMQ cluster。根據queue的policy,當一個node加入cluster時,queues可能在這個新的node上添加一個slave。此時此刻,新的slave是空的,並不包含被鏡像的queue中存在的內容。該slave將接收publish到其queue的新的message。這樣一來,一段時間後salve上的queue至關於被鏡像的queue的「尾巴」,且隨着時間的推移被鏡像的queue的「頭部」愈來愈小,而salve上的queue的「尾巴」愈來愈長,最終salve的內容會與master上的內容徹底同步。須要注意的是,這裏有個提早提條件,即客戶端需從master上的queue中不斷消耗既存的message以達到master和salve的同步。

所以,新添加進的slave並不能爲該slave被加入前就已存在的queue內容增長額外的冗餘或可用性,直至master/slave徹底同步。由於執行明確的同步操做會使queue無響應,所以只容許非活躍的queues進行明確的同步操做而活躍的queues進行天然的同步操做是一種好的策略。

配置明確的同步
明確的/顯示的同步操做能夠以兩種方式觸發:手動方式和自動方式。若queue被設置爲自動同步則新salve一旦被加入同步便開始進行,queue變的無響應直至同步完成。能夠經過將policy中的ha-sync-mode指定爲automatic來將同步設置爲自動的或者將其指定爲manual或者不指定將同步設置爲手動的。

可經過以下命令確認哪些salve在同步:
rabbitmqctl list_queues name slave_pids synchronised_slave_pids
手動同步queue:
rabbitmqctl sync_queue name
取消queue同步:
rabbitmqctl cancel_sync_queue name
(也可在management plugin中進行)

中止nodes與同步
當停掉運行有被鏡像的queue的master node後,其餘node上的slave將被提高爲新的master(假定當時存在一個已徹底同步的slave)。當繼續停掉nodes後會達到沒有多餘的slave用來鏡像queue的境地,queue此時只存在於一個node中,該node此時爲master。若該queue被聲明爲持久化的,則在僅剩的node被停掉並重啓後被聲明爲持久化的message會仍然存在。一般,這個時候再重啓其他的nodes,若這些nodes以前是鏡像queue的一部分,則會從新加入被鏡像的queue。
然而,目前,在從新加入備鏡像的queue時,salve沒有辦法知道本身的queue中的內容是否和master的queu中的內容存在誤差(這在 network partition時是可能存在的),所以,目前的策略是,當salve從新加入被鏡像的queue時,丟掉本地全部的內容,以空的狀態開始,就比如cluster中加入了新node同樣。

中止只有未同步的salves的master nodes

在關掉master node時全部可用的salves都還未同步完的狀況是可能的。爲了不message丟失,默認狀況下,在有意的/可控的關閉master時(有意的停RabbitMQ服務或關閉OS)RabbitMQ不會fail over到還未同步完成的slave上,相反整個queue將被關閉就好像未同步完成的salve不存在同樣。然而,如果無心的/不可控的關閉master node時(例如RabbitMQ server或者node crash了或者網絡掉電了)將觸發master fail over到slave node即便slave還未同步完成。

若但願在全部情形下(即便slave node還未同步完成)master node都能fail over到其餘slave node,則可經過將policy中的ha-promote-on-shutdown由when-synced值爲always來實現。

全部slaves處於關閉狀態時的master丟失
可能發生這樣一種情形,在queue的全部slaves均處於關閉狀態時queue的master丟失了(可控/不可控的關閉)。正常狀況下queue的nodes中最後一個被關閉的會變成master,在這個節點重啓時咱們仍但願其做爲master(由於該node可能接收了其餘node未接收到的新message)。然而,當調用rabbitmqctl forget_cluster_node命令從cluster中移除一個node時RabbitMQ會試圖爲master在該node上的每一個queue找到一個當前被停掉的salve node並在這個slave node從新啓動後將其「提高」爲新的master。如有多個node可供選擇,則最近被停掉的salve node將被選中。

這裏須要理解爲何在執行forget_cluster_node命令時RabbitMQ只能選擇已中止的slave來提高爲master。之因此這樣是由於就像「
中止nodes與同步」部分將的:任何slave node在從新啓動後會清空本地全部的內容,於是只能選擇還處於中止狀態的salve。所以,當從cluster中移除「丟失的」master時需在slaves重啓以前執行forget_cluster_node命令。

鏡像隊列的實現和語義

對於每一個被鏡像的queue存在一個master和多個slaves,各自在不一樣的node。slaves以徹底相同的順序執行發生在master上的操做所以能夠維護與master一致的狀態。publish操做僅發生在master上而後由master broadcasts到全部的slaves。所以從被鏡像的queue consume message的 client其實是從master consume的。

當一個slave fail後須要作的不多:master仍爲master,全部的client不會被通知slave的fail,也無需其餘額外的操做。注意:slave的失敗可能不會被當即探測到,每一個鏈接的流控機制的干預能夠延遲message的發送。

當master fail時,其中一個slave必須被提高爲master,此時會發生如下狀況:
一個slave被提高爲新的master。被提高的slave是「最舊」的slave。由於該slave與原master中內容徹底同步的概率最大。然而,也有可能全部的salve都未與master徹底同步,此時只有master中存在而slaves中不存在的message將丟失。
slave認爲全部以前的consumers的鏈接忽然斷開了。所以,它從新將已經投遞但還未被確認的messages從新排隊。這些「未被確認的」message可能包含client已發出確認但確認在到達master前丟失了的情形也包含client已發出確認且確認已到達master但在master廣播給slaves時丟失的情形。在上述任意一種狀況下,新的master都必須爲他認爲未收到確認的message從新排隊。
以前請求原master的clients被取消。
因爲從新排隊,從queue從新consume的clients須要知道此時可能接收到以前已經被處理過的message

在選則的salve變成master時,這段時間內發往原被鏡像的queue的message不會丟失:發給被鏡像的queue的message老是直接發給master和全部的slaves。所以,一旦master失敗,messages將繼續被髮往slaves且一旦某個salve被徹底提高爲master這些message將被添加到queue中。

一樣,clients發送的使用publisher confirms確認的message仍然會被正確的確認即便是在message被publish和被confirm之間master(或任何的slave)fail了。所以,從publisher的角度看,發message到mirrored queue與發message到任何其餘類型的queue並沒有差異。

如果從mirrored queue使用noAck=true消費message,message就有可能丟失。RabbitMQ認爲一旦message被髮給了noAck=true的consumer即被視爲確認過了,若這時client意外的斷開了,message將永遠不會被收到。在mirrored queue狀況下,在master故障時queue中被髮給noAck=True的consumer的message將永遠不會被收到,也不會被新的master從新排隊。由於正在consuming的client可能鏈接在存活的node上, Consumer Cancellation Notification機制能夠用於檢測是否發生了上述狀況。固然,在實際應用場景中,若關心message的可靠性則建議使用noAck=false的consumer。

Publisher Confirms 和 Transactions
Mirrored queue支持Publisher Confirms 和 Transactions。在該情形下,confirms和transactions動做在queue的全部mirror中傳播。如,只有transaction在queue的全部mirror中都應用後纔回返回tx.commit-ok 。一樣,只有queue的全部mirror都接收到message後纔會給publisher以確認。

流量控制
RabbitMQ使用基於credit的算法來限制message的發送速率。Publishers只有在接收到queue的全部mirrors反饋的credit時才容許publish message。若salves不能反饋credit則會致使publisher阻塞。Publisher會一直被阻塞直至slaves反饋credit或者直至剩餘的nodes認爲該slave從cluster斷開鏈接。Erlang經過按期發送tick至全部nodes來監測鏈接的斷開。tick的頻率可經過net_ticktime參數配置。

Consumer Cancellation
從mirrored queue消費message的clients可能想要知道它們從中消費message的queue是否發生了fail over。當mirrored queue發生了fail over後,關於messages已被髮送到哪一個consumer的信息將丟失,所以全部未確認的messages會被設置redelivered flag後從新發送。Consumers可能想要知道是否發生了這個過程。Consumer能夠經過將x-cancel-on-ha-failover 設置爲true來達到此目的。這樣一來在failover發生時消費將取消, consumer cancellation notification會被髮出。接下來由consumer決定是否從新html

 

參考:node

http://www.rabbitmq.com/ha.html算法

 

轉載: https://blog.csdn.net/zyz511919766/article/details/41896823api

相關文章
相關標籤/搜索