本系列是「RabbitMQ實戰(zhàn):高效部署分布式消息隊列」書籍的總結(jié)筆記。
創(chuàng)新互聯(lián)公司服務項目包括閬中網(wǎng)站建設、閬中網(wǎng)站制作、閬中網(wǎng)頁制作以及閬中網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,閬中網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到閬中省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!
上一篇介紹了各種場景下的最佳實踐,大部分場景可以使用「發(fā)后即忘」的模式,不需要響應,如果需要響應,可以使用RabbitMQ的RPC模型。
RabbitMQ以異步的方式解耦系統(tǒng)間的關(guān)系,調(diào)用者將業(yè)務請求發(fā)送到Rabbit服務器,就可以返回了,Rabbit會確保請求被正確處理,即使遇到網(wǎng)絡異常、Rabbit服務器崩潰、整個機房斷電等特殊場景,針對這些場景,Rabbit提供了各種機制確保其可用性。
本篇通過總結(jié)可能出現(xiàn)的特殊場景,對Rabbit提供的可用性保證進行分析,學習它的實現(xiàn)方式,你會了解到:
在實際工作中,有很大一部分時間用在解決各種異常情況,比如針對用戶輸入的驗證,JDK中提供的各種異常類,網(wǎng)絡異常等,這些相對來說比較好解決。
Rabbit服務作為調(diào)用者和處理者的橋梁,至關(guān)重要,如果因為網(wǎng)絡異常、單臺服務器崩潰、機房癱瘓等原因?qū)е翿abbit服務不可用,會影響所有依賴的業(yè)務系統(tǒng)。
處理者和服務端是通過長連接交互的,這樣可以將消息實時推送,網(wǎng)絡異??赡軙е麻L連接斷開,如果客戶端無法感知,處理者將接收不到任何消息,這種情況稱為「連接丟失」。
通過捕獲連接異常,進行重連,可以解決這種問題,另外,Rabbit客戶端進行了封裝,很容易處理這種問題。
如果只有一臺服務器服務,服務器崩潰將導致服務不可用,一般會使用集群將多個服務器看成一個整體對外提供服務,這樣,單臺服務器崩潰不會影響整體的服務。
使用集群后,就要考慮一些問題:
如果考慮機房癱瘓,就要建多個數(shù)據(jù)中心,RabbitMQ提供了一種機制,可以方便地在不同數(shù)據(jù)中心的Rabbit間復制消息。
RabbitMQ最優(yōu)秀的功能之一就是其內(nèi)建集群,主要用于完成2個目標:
RabbitMQ會始終記錄四種類型的內(nèi)部元數(shù)據(jù)(類似索引):
當引入集群時,就需要追蹤新的元數(shù)據(jù)類型:集群節(jié)點位置,以及節(jié)點與已記錄的其他類型元數(shù)據(jù)的關(guān)系。
不是每個節(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列表。
每個Rabbit節(jié)點,要么是內(nèi)存節(jié)點,要么是磁盤節(jié)點,單節(jié)點系統(tǒng)只運行磁盤類型的節(jié)點,在集群中,可以選擇配置部分節(jié)點為內(nèi)存節(jié)點。
在集群中聲明隊列、交換器或綁定的時候,這些操作直到所有集群節(jié)點都成功提交元數(shù)據(jù)變更后才返回。
RabbitMQ只要求集群中至少有一個磁盤節(jié)點,如果只有一個磁盤節(jié)點,剛好又崩潰了,集群可以繼續(xù)路由消息,但不能創(chuàng)建隊列、交換器、綁定、添加用戶、更改權(quán)限等操作。所以,建議設置兩個磁盤節(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ā)送一個消費者取消通知,告知不再附加在隊列主拷貝了,需要重新連接。
這一小節(jié)主要討論消費者如何檢測連接丟失,并進行重連操作。
處理到集群的重連有多重策略,比較好的一種方式是使用負載均衡,不僅可以減少應用程序處理節(jié)點故障代碼的復雜性,又能確保在集群中連接的平均分配。
關(guān)于負載均衡,網(wǎng)上介紹的比較多了,這里就不再過多介紹了,主要看看如何感知故障,并進行重連操作。
感知故障比較簡單,當長連接斷開時,會拋出異常,捕獲對應的異常即可。
當集群節(jié)點出現(xiàn)故障時,應用程序需要考慮:下一個該連向哪里?這個工作已經(jīng)交由負載均衡器決定。
關(guān)于重連處理,要考慮:
當對可用性要求特別高時,不允許消息丟失,需要將隊列、交換器、消息設置成持久化,如果一個節(jié)點崩潰了,在恢復之前,將無法轉(zhuǎn)發(fā)消息,因為默認的群集架構(gòu)不允許在集群其他節(jié)點創(chuàng)建隊列,防止故障節(jié)點恢復后,歷史消息丟失。
可以通過構(gòu)建主/備機的獨立RabbitMQ,也就是warren模式,解決這個問題。一個warren是指一對主/備獨立服務器,并前置一套負載均衡器來處理故障轉(zhuǎn)移。
主服務器和備用服務器之間沒有協(xié)作,只有當主服務器崩潰時,備用服務器才會處理消息??梢员WC,主節(jié)點故障后,通過備用節(jié)點重新創(chuàng)建隊列、交換器繼續(xù)服務,故障節(jié)點恢復后,可以繼續(xù)消費主節(jié)點未消費的消息。
在只有一個數(shù)據(jù)中心的時候,RabbitMQ集群對于提升消息通信性能來說是很棒的方案,但需要把消息從一個程序路由到另一個城市的時候,就比較麻煩了,可以通過Shovel解決。
Shovel是RabbitMQ的一個插件,可以使你能夠定義RabbitMQ上的隊列和另一個RabbitMQ上的交換器之間的復制關(guān)系。說白了就是生產(chǎn)者和消費者離得比較遠。
通過在機房1創(chuàng)建一個新的隊列,用于接收網(wǎng)站發(fā)布的消息,然后讓shovel消費這些消息并重新將消息通過WAN連接發(fā)布到機房2上的交換器。
這樣對于用戶來說,只要發(fā)布到機房1的隊列即可返回,減少了響應時間。機房1可以持續(xù)將消息發(fā)布到機房2上。
通過上面的介紹可以看到,保證高可用需要做很多工作,可以根據(jù)業(yè)務對可用性的要求,選擇不同的架構(gòu)方式。
下一篇重點介紹RabbitMQ管理界面和監(jiān)控。
歡迎掃描下方二維碼,關(guān)注我的個人微信公眾號 ~
另外有需要云服務器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。