大曝光!從RabbitMQ平滑遷移至Kafka架構(gòu)設(shè)計方案!
歷史原因,公司存在多個 MQ 同時使用的問題,我們中間件團隊在去年下半年開始支持對 Kafka 和 Rabbit 能力的進行封裝,初步能夠完全支撐業(yè)務團隊使用。
鑒于在之前已經(jīng)基本完全實施 Kafka 管控平臺、以及 Kafka 集群遷移管控,我們基本可以認為團隊對于 Kafka 的把控能力初具規(guī)模。
因此,考慮到以下幾點原因,我們決定對 RabbitMQ 不再做維護和支持。
原因
使用混亂和維護困難
基于我們的數(shù)據(jù)統(tǒng)計和分析發(fā)現(xiàn),基本上沒有服務使用我們自己封裝的 RabbitMQ 能力,用到的基本上是??spring-amqp?
?或者原生的Rabbit 使用方式,存在使用混亂,方式不統(tǒng)一的問題,對于排查問題方面存在更多的問題。
另外考慮到對于 MQ 能力支持要做雙份,Kafka 和 Rabbit 都要支持相同的功能,對于人力資源方面存在浪費,當然也由于本身目前沒有對 RabbitMQ 非常精通的同學,所以對于維護能力這方面存在擔憂。
分區(qū)容錯問題
RabbitMQ 集群對于網(wǎng)絡(luò)分區(qū)的容錯性不高,根據(jù)調(diào)查發(fā)現(xiàn),系統(tǒng)中 RabbitMQ 高可用方案使用鏡像隊列,而當 RabbitMQ 出現(xiàn)網(wǎng)絡(luò)分區(qū)時,不同分區(qū)里的節(jié)點會認為不屬于自身所在分區(qū)的節(jié)點都已經(jīng)掛了,對于隊列、交換器、綁定的操作僅對當前分區(qū)有效。
而且,如果原集群中配置了鏡像隊列,而這個鏡像隊列又牽涉兩個或者更多個網(wǎng)絡(luò)分區(qū)中的節(jié)點時,每一個網(wǎng)絡(luò)分區(qū)中都會出現(xiàn)一個 master 節(jié)點,對于各個網(wǎng)絡(luò)分區(qū),此隊列都是相互獨立的。
在默認的情況下,架構(gòu)本身存在腦裂的風險,在 3.1 版本下是無法自動恢復的,之后的版本才會自動探測網(wǎng)絡(luò)分區(qū),人工介入存在數(shù)據(jù)丟失的風險。
性能瓶頸
鏡像隊列解決了 Rabbit 高可用的問題,但是并不能增加負載和性能,線上曾經(jīng)出現(xiàn)過 RabbitMQ 在高流量下的性能問題,就是因為隊列由單個節(jié)點承載流量,在高并發(fā)情況在集群中單個節(jié)點存在性能瓶頸。
即便我們目前大部分場景下 MQ 流量不高,但是一旦出現(xiàn)問題,將成為整個系統(tǒng)的性能瓶頸。
另外我們對 Rabbit 做了一些性能方面的測試:
測試集群一共有 4 臺磁盤節(jié)點,其中每臺 16 核,如果我們不做 Sharding,單隊列最高 TPS 在 5K 左右,如果是內(nèi)存節(jié)點,官方可以給出的處理極限為 50K/s,如果做 Sharding,單隊列處理能力可以達到 10K/s。
上述結(jié)論都是以消息能夠被正常快速消費為前提,實際上在高流量或者大量消息積壓的情況會導致集群性能急劇下降。
運維&管控
基于以上現(xiàn)有的問題和難點,我們決定對 Rabbit 進行全量遷移至 Kafka,以便能在業(yè)務高速發(fā)展過程中能夠保障對于穩(wěn)定性、高可用、高性能方面的追求。
在方法論和理論體系層面,我們對業(yè)務生產(chǎn)有三板斧:可灰度、可監(jiān)控、可回滾。
同樣,對于消息中間件平臺運維我們希望有三板斧:可運維、可觀測、可管控,那么目前基于 Kafka 的集群管控和 Kafka Manager 的能力我們已經(jīng)基本做到了上述幾點。
- 1. 高可用:根據(jù)自身經(jīng)驗,Kafka 本身擁有極高的平臺可用性
- 2. 高性能:Kafka 可支撐極高的 TPS,并且支持水平擴展,可快速滿足業(yè)務的流量增長需求
- 3. 功能支持:在原有兩個 MQ 能力基礎(chǔ)上,基礎(chǔ)支持順序消息、延時消息、灰度消息、消息軌跡等
- 4. 運維管控:基于 Kafka Manager 基礎(chǔ)上進行二次開發(fā),豐富管控能力和運維支撐能力,提供給開發(fā)、運維、測試更好的使用體驗和運維能力。
模型對比
RabbitMQ
Exchange:生產(chǎn)者將消息發(fā)送到Exchange,由交換器將消息通過匹配Exchange Type、Binding Key、Routing Key后路由到一個或者多個隊列中。
Queue:用于存儲消息,消費者直接綁定Queue進行消費消息
Routing Key:生產(chǎn)者發(fā)送消息給 Exchange 會指定一個Routing Key。
Binding Key:在綁定Exchange與Queue時會指定一個Binding Key。
Exchange Type:
- ? Direct:把消息路由到那些 Binding Key 和 Routing Key 完全匹配的隊列中
- ? Fanout:把消息轉(zhuǎn)發(fā)給所有與它綁定的隊列上,相當于廣播模式
- ? Topic:通過對消息的 Routing Key 和 Exchange、Queue 進行匹配,將消息路由給一個或多個隊列,發(fā)布/訂閱模式
- ? Headers:根據(jù)消息的 Header 將消息路由到不同的隊列,和 Routing Key 無關(guān)
Kafka
Topic:發(fā)送消息的主題,對消息的組織形式
Broker:Kafka 服務端
Consumer Group:消費者組
Partition:分區(qū),topic 會由多個分區(qū)組成,通常每個分區(qū)的消息都是按照順序讀取的,不同的分區(qū)無法保證順序性,分區(qū)也就是我們常說的數(shù)據(jù)分片sharding機制,主要目的就是為了提高系統(tǒng)的伸縮能力,通過分區(qū),消息的讀寫可以負載均衡到多個不同的節(jié)點上
遷移方案
綜上,我們將要對系統(tǒng)中所有使用RabbitMQ的服務進行遷移操作,整個遷移我們應該保證以下 3 點:
- 1. 操作便捷,不能過于復雜,復雜會帶來更多的不可控風險
- 2. 風險可控,盡最大可能降低遷移對業(yè)務的影響
- 3. 不影響業(yè)務正常運行
消費者雙訂閱
- 1. 對消費者進行改造,同時監(jiān)聽 Rabbit 和 Kafka 消息
- 2. 對生產(chǎn)者進行改造,遷移至Kafka發(fā)送消息
- 3. 等待 Rabbit 遺留消息消費完畢之后,直接下線即可
優(yōu)點:可以做到無損遷移
缺點:
- 1. 需要同時維護兩套監(jiān)聽代碼,可能有大量的工作量,遷移完成之后還需要再進行一次老代碼下線
- 2. 消息無法保證順序性
基于灰度單訂閱
這是基于雙訂閱模式的優(yōu)化,通過使用我們的灰度/藍綠發(fā)布的能力,做到可以不雙訂閱,不用同時監(jiān)聽兩個消息隊列的消息。
- 1. 直接修改消費者代碼,發(fā)布灰度/藍節(jié)點,監(jiān)聽 Kafka 消息
- 2. 生產(chǎn)者改造,往 Kafka 發(fā)送消息
- 3. 等待老的 Rabbit 消息消費完畢,下線,這里存在一個問題就是在進行灰度之后全量的過程中可能造成消息丟失的情況,對于這個問題的解決方案要區(qū)分來看,如果業(yè)務允許少量的丟失,那么直接全量即可,否則需要對業(yè)務做一定的改造,比如增加開關(guān),全量之前關(guān)閉發(fā)送消息,等待存量消息消費完畢之后再全量。
優(yōu)點:
- 1. 基于雙訂閱方案改造,可以做到不同時監(jiān)聽兩個隊列的消息,減少工作量
- 2. 可以做到無損遷移
缺點:同樣無法保證消息有序性
實際場景問題
上述只是針對現(xiàn)狀的遷移方案考慮,那么還有一些跟實際和復雜的問題可能需要考慮。
比如消息的場景有可能不是這種簡單的發(fā)布/訂閱關(guān)系,可能存在網(wǎng)狀、環(huán)狀的發(fā)布/訂閱關(guān)系,該如何處理?
其實是一樣的道理,只要我們能夠梳理清楚每個 Exchange 之間的發(fā)布/訂閱的關(guān)系,針對每個 Exchange 進行操作,就能達到一樣的平滑遷移效果。
我們要做的就是針對每個 Exchange 進行遷移,而不是針對服務,否則遷移是無法進行下去的,但是這樣帶來的另外一個問題就是每個服務需要發(fā)布多次,而且如果碰到多個復雜消費或者生產(chǎn)的情況要特別小心。
實施細節(jié)
基于現(xiàn)狀,我們對所有 Rabbit Exchange 的情況進行了詳細的統(tǒng)計,將針對不同的 Exchange 和類型以及功能使用以下方式處理。
- 1. 無用的Exchange、無生產(chǎn)者或者無消費者,還有沒有任何流量的,可以直接刪除
- 2. Fanout 類型,Exchange 對應 Topic,Queue 對應 Consumer Group,還有存在使用隨機隊列的,需要對應多個Consumer Group(單獨做一個簡單的能力封裝處理)
- 3. Direct 類型,RoutingKey 對應 Topic,Queue 對應 Consumer Group
- 4. Topic 類型,RoutingKey 對應 Topic,Queue 對應 Consumer Group,實際并未發(fā)現(xiàn)使用到通配符情況
- 5. 延遲隊列、重試等功能,基于 spring-kafka 做二次封裝
驗證&監(jiān)控&灰度&回滾
驗證
- 遷移后針對 Rabbit 驗證,通過管理平臺流量或者日志輸出來確認,而且現(xiàn)狀是大部分 Exchange 流量都比較小,所以可能需要自行發(fā)送消息驗證遷移效果。
- 遷移后針對 Kafka 流量進行驗證可以通過 Kafka Manager 平臺或者日志
監(jiān)控
監(jiān)控通過 Kafka Manager 平臺或者現(xiàn)有監(jiān)控
灰度
方案本身 Consumer 和 Producer 都可以直接灰度發(fā)布,預發(fā)驗證
回滾
服務回滾,按照發(fā)布順序控制回退順序
巨人的肩膀:
1. https://xie.infoq.cn/article/bf3d9cfd01af72b326254aa81
2. https://developer.aliyun.com/article/772095
3. 《RabbitMQ實戰(zhàn)指南》