溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

RabbitMQ實戰(zhàn):可用性分析和實現(xiàn)

發(fā)布時間:2020-07-02 02:47:00 來源:網(wǎng)絡 閱讀:563 作者:情情說 欄目:開發(fā)技術

本系列是「RabbitMQ實戰(zhàn):高效部署分布式消息隊列」書籍的總結(jié)筆記。

上一篇介紹了各種場景下的最佳實踐,大部分場景可以使用「發(fā)后即忘」的模式,不需要響應,如果需要響應,可以使用RabbitMQ的RPC模型。

RabbitMQ以異步的方式解耦系統(tǒng)間的關系,調(diào)用者將業(yè)務請求發(fā)送到Rabbit服務器,就可以返回了,Rabbit會確保請求被正確處理,即使遇到網(wǎng)絡異常、Rabbit服務器崩潰、整個機房斷電等特殊場景,針對這些場景,Rabbit提供了各種機制確保其可用性。

本篇通過總結(jié)可能出現(xiàn)的特殊場景,對Rabbit提供的可用性保證進行分析,學習它的實現(xiàn)方式,你會了解到:

  • 總結(jié)異常場景
  • 集群并處理失敗
  • 連接丟失和故障轉(zhuǎn)移
  • 主/備方式
  • 跨機房復制
異常場景

在實際工作中,有很大一部分時間用在解決各種異常情況,比如針對用戶輸入的驗證,JDK中提供的各種異常類,網(wǎng)絡異常等,這些相對來說比較好解決。

Rabbit服務作為調(diào)用者和處理者的橋梁,至關重要,如果因為網(wǎng)絡異常、單臺服務器崩潰、機房癱瘓等原因?qū)е翿abbit服務不可用,會影響所有依賴的業(yè)務系統(tǒng)。

網(wǎng)絡異常

處理者和服務端是通過長連接交互的,這樣可以將消息實時推送,網(wǎng)絡異常可能會導致長連接斷開,如果客戶端無法感知,處理者將接收不到任何消息,這種情況稱為「連接丟失」。

通過捕獲連接異常,進行重連,可以解決這種問題,另外,Rabbit客戶端進行了封裝,很容易處理這種問題。

服務器崩潰

如果只有一臺服務器服務,服務器崩潰將導致服務不可用,一般會使用集群將多個服務器看成一個整體對外提供服務,這樣,單臺服務器崩潰不會影響整體的服務。

使用集群后,就要考慮一些問題:

  • 客戶端連接到哪臺服務器是隨機的,而一個隊列只會在某個服務器中,所以,每臺服務器都要保存隊列元數(shù)據(jù)(類似索引),并且可從其他服務器獲取實際的隊列數(shù)據(jù);
  • 服務器崩潰,會導致非持久化的隊列、交換器丟失,客戶端端重連后,要再次進行創(chuàng)建,但未消費的消息將無法恢復;
  • 如果隊列、交換器、消息等是持久化的,如何進行恢復呢,Rabbit提供了幾種方式進行處理,后面會詳細介紹;
  • 訂閱者也需要重新建立連接,進行監(jiān)聽;
機房癱瘓

如果考慮機房癱瘓,就要建多個數(shù)據(jù)中心,RabbitMQ提供了一種機制,可以方便地在不同數(shù)據(jù)中心的Rabbit間復制消息。

集群并處理失敗

RabbitMQ最優(yōu)秀的功能之一就是其內(nèi)建集群,主要用于完成2個目標:

  • 允許消費者和生產(chǎn)者在Rabbit節(jié)點崩潰的情況下繼續(xù)運行;
  • 通過添加更多的節(jié)點線性擴展消息通信的吞吐量;
集群架構

RabbitMQ會始終記錄四種類型的內(nèi)部元數(shù)據(jù)(類似索引):

  • 隊列元數(shù)據(jù):隊列名稱和它的屬性;
  • 交換器元數(shù)據(jù):交換器名稱、類型和屬性;
  • 綁定元數(shù)據(jù):一張簡單的表格展示了如何將消息路由到隊列;
  • vhost元數(shù)據(jù):為vhost內(nèi)的隊列、交換器和綁定提供命名空間和安全屬性;

當引入集群時,就需要追蹤新的元數(shù)據(jù)類型:集群節(jié)點位置,以及節(jié)點與已記錄的其他類型元數(shù)據(jù)的關系。

不是每個節(jié)點都有所有隊列的完全拷貝,如果在集群中創(chuàng)建隊列,只會在單個節(jié)點上創(chuàng)建完整的隊列信息(元數(shù)據(jù)、狀態(tài)、內(nèi)容),所有其他節(jié)點只知道隊列的元數(shù)據(jù)和指向該隊列的節(jié)點指針。

如果節(jié)點崩潰了,附加在隊列上的消費者也就無法接收新的消息了??梢宰屜M者重連到集群并重新創(chuàng)建隊列,這種做法僅當隊列沒設置持久化時才可行,這是為了確保當失敗的節(jié)點恢復后加入集群,節(jié)點上的隊列消息不會丟失。

為什么不將隊列內(nèi)容和狀態(tài)復制到所有節(jié)點:第一,存儲空間,如果每個集群節(jié)點都擁有所有隊列的完全拷貝,添加新節(jié)點不會帶來更多存儲空間;第二,性能,消息的發(fā)布者需要將消息復制到每一個集群節(jié)點,對于持久化消息,網(wǎng)絡和磁盤復制都會增加。

而交換器只是一張查詢表,而非實際的消息路由器,因此將交換器在整個集群中進行復制會更加簡單

可以把每個隊列想象成節(jié)點上運行的進程,每個進程擁有自己的進程ID,交換器只是路由模式列表和匹配消息應發(fā)往的隊列進程ID列表。

RabbitMQ實戰(zhàn):可用性分析和實現(xiàn)

每個Rabbit節(jié)點,要么是內(nèi)存節(jié)點,要么是磁盤節(jié)點,單節(jié)點系統(tǒng)只運行磁盤類型的節(jié)點,在集群中,可以選擇配置部分節(jié)點為內(nèi)存節(jié)點。

在集群中聲明隊列、交換器或綁定的時候,這些操作直到所有集群節(jié)點都成功提交元數(shù)據(jù)變更后才返回。

RabbitMQ只要求集群中至少有一個磁盤節(jié)點,如果只有一個磁盤節(jié)點,剛好又崩潰了,集群可以繼續(xù)路由消息,但不能創(chuàng)建隊列、交換器、綁定、添加用戶、更改權限等操作。所以,建議設置兩個磁盤節(jié)點,當內(nèi)存節(jié)點重啟后,會連接到預先配置的磁盤節(jié)點,下載當前集群元數(shù)據(jù)拷貝,所以要將所有磁盤節(jié)點告訴內(nèi)存節(jié)點。

鏡像隊列

前面提到,隊列只會在集群中的一個節(jié)點,節(jié)點崩潰后,隊列消息就會丟失,RabbitMQ2.6版本之后,提供了鏡像隊列,一旦主隊列不可用,從隊列將被選舉為新的主隊列。

對于鏡像隊列,除了將消息按照路由綁定規(guī)則投遞到合適的隊列,也會將消息投遞到鏡像隊列的從拷貝。

對于發(fā)送方確認消息,Rabbit會在所有隊列和隊列的從拷貝安全地接收到消息時,才會通知發(fā)送方。

另外,使用鏡像隊列時,有一個問題:如果主拷貝節(jié)點發(fā)送故障,從隊列會選舉Wie主隊列,所有該隊列的消費者需要重新附加并監(jiān)聽新的隊列主拷貝。對于通過故障節(jié)點進行連接的消費者,可以通過丟失到節(jié)點的TCP連接檢測到,但對于那些通過節(jié)點附加到鏡像隊列且正常運行的消費者將無法檢測到。

Rabbit通過給消費者發(fā)送一個消費者取消通知,告知不再附加在隊列主拷貝了,需要重新連接。

連接丟失和故障轉(zhuǎn)移

這一小節(jié)主要討論消費者如何檢測連接丟失,并進行重連操作。

處理到集群的重連有多重策略,比較好的一種方式是使用負載均衡,不僅可以減少應用程序處理節(jié)點故障代碼的復雜性,又能確保在集群中連接的平均分配。

關于負載均衡,網(wǎng)上介紹的比較多了,這里就不再過多介紹了,主要看看如何感知故障,并進行重連操作。

感知故障比較簡單,當長連接斷開時,會拋出異常,捕獲對應的異常即可。

當集群節(jié)點出現(xiàn)故障時,應用程序需要考慮:下一個該連向哪里?這個工作已經(jīng)交由負載均衡器決定。

關于重連處理,要考慮:

  • 如果重連到新的服務器,信道以及其上的所有消費循環(huán)都會失效,需要對他們進行重建;
  • 當進行重連時,所有的隊列、綁定有可能都不存在了,需要重新構造隊列和綁定。
主/備方式

當對可用性要求特別高時,不允許消息丟失,需要將隊列、交換器、消息設置成持久化,如果一個節(jié)點崩潰了,在恢復之前,將無法轉(zhuǎn)發(fā)消息,因為默認的群集架構不允許在集群其他節(jié)點創(chuàng)建隊列,防止故障節(jié)點恢復后,歷史消息丟失。

可以通過構建主/備機的獨立RabbitMQ,也就是warren模式,解決這個問題。一個warren是指一對主/備獨立服務器,并前置一套負載均衡器來處理故障轉(zhuǎn)移。

主服務器和備用服務器之間沒有協(xié)作,只有當主服務器崩潰時,備用服務器才會處理消息??梢员WC,主節(jié)點故障后,通過備用節(jié)點重新創(chuàng)建隊列、交換器繼續(xù)服務,故障節(jié)點恢復后,可以繼續(xù)消費主節(jié)點未消費的消息。

跨機房復制

在只有一個數(shù)據(jù)中心的時候,RabbitMQ集群對于提升消息通信性能來說是很棒的方案,但需要把消息從一個程序路由到另一個城市的時候,就比較麻煩了,可以通過Shovel解決。

Shovel是RabbitMQ的一個插件,可以使你能夠定義RabbitMQ上的隊列和另一個RabbitMQ上的交換器之間的復制關系。說白了就是生產(chǎn)者和消費者離得比較遠。

通過在機房1創(chuàng)建一個新的隊列,用于接收網(wǎng)站發(fā)布的消息,然后讓shovel消費這些消息并重新將消息通過WAN連接發(fā)布到機房2上的交換器。

這樣對于用戶來說,只要發(fā)布到機房1的隊列即可返回,減少了響應時間。機房1可以持續(xù)將消息發(fā)布到機房2上。

RabbitMQ實戰(zhàn):可用性分析和實現(xiàn)

通過上面的介紹可以看到,保證高可用需要做很多工作,可以根據(jù)業(yè)務對可用性的要求,選擇不同的架構方式。

下一篇重點介紹RabbitMQ管理界面和監(jiān)控。

歡迎掃描下方二維碼,關注我的個人微信公眾號 ~

RabbitMQ實戰(zhàn):可用性分析和實現(xiàn)

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI