Apache RocketMQ 5.0 在Stream場景的儲存增強

語言: CN / TW / HK

1.jpeg

本文作者:劉振東,Apache RocketMQ PMC Member

RocketMQ基礎介紹

2.png

RocketMQ的誕生是為了解決微服務解耦的問題。微服務解耦指將傳統的巨大服務拆分為分散式的微服務。

拆分之後,產生了一個新的問題:服務之間需要進行通訊才能對外形成完整的服務。通訊方式分為兩種:其一為RPC方式,也稱為同步通訊;其二為非同步通訊方式,比如RocketMQ。

RocketMQ的廣泛使用證明非同步通訊方式存在極大優勢。最顯著的特點即非同步解耦,所謂解耦指一個服務不需要知道另外一個服務的存在。比如開發A服務,即使其他服務需要A服務的資料,A服務也並不需要知道它們的存在,不需要依賴其他服務的釋出,其他服務的新增也不會對A服務造成影響,從而實現了團隊的解耦,指一個微服務由一個特定的團隊去完成,而其他團隊並不需要知道該團隊的存在,只需要根據事先約定的資料格式,通過RocketMQ實現非同步通訊。這種組織方式大大促進了生產力的發展,自然也促使RocketMQ得到廣泛應用。

3.png

在非同步解耦過程中,有的元件生產訊息,有的元件消費訊息。RocketMQ的API model是其非同步解耦過程的抽象概念。API model 的兩端是RocketMQ領域最典型的兩個概念:其一為producer,指訊息的生產方或者資料生產方;其二為consumer,指訊息的消費方。

除此之外,topic也是API model的一個重要概念。因為非同步解耦的需要,一條資料從producer發出到最終被consumer消費的過程並不是直接連線,中間有一個抽象層,這個抽象概念稱為topic,相當於一個邏輯地址。topic就像一個倉庫,當一條資料被髮送到一個topic時,它會負責將訊息暫存,其他元件需要使用時可以拿取。

RocketMQ是一個分散式的訊息中介軟體,因此topic實質上是一個邏輯概念,真正的物理概念是分佈在每一個broker上的佇列,即message queue。一個topic可以具有很多message queue,可以分佈在很多broker上,從而具有了無限擴充套件的能力,這是topic的一個基本特性。

此外,topic接收訊息還有一個非常重要的特性,即訊息不可變。訊息的不可變特性使其可以被重複地讀取。通過引入consumer group 的概念,可以看到不同組的消費者讀取訊息的行為相互之間不會造成影響。Topic裡的資料不會因為有consumer去讀取而消失,可實現一處傳送多處消費的能力。比如在一個組織內,訂單團隊發了一條訊息到訂單topic,該組織內的其他所有團隊都可以直接進行讀取,且一個團隊的讀取並不會影響其他團隊的讀取,實現了讀取的相互獨立。

4.png

MQ的一個重要特性是非同步解耦,在網際網路的超大流量場景下,非同步解耦之後往往會跟隨著削峰填谷問題。為了實現削峰填谷,需要持久化的能力。MQ是一個儲存引擎,它可以暫存傳送者的資料。如果消費者暫時無法處理,資料可以先堆積在MQ ,等到有足夠的能力消費時再讀取資料。

持久化也更好地支援了非同步解耦的特性,即使consumer 全部不線上也並不影響producer的傳送。持久化是MQ的一項重要能力。在持久化能力裡,為了配合順序的特性,MQ的引擎是一個順序儲存的引擎。

RocketMQ設計時略微有所不同,它將所有訊息集中式地儲存,再根據不同的topic、不同的佇列分別建立索引。這種設計是RocketMQ針對微服務場景特別優化的,它具有能夠很好地支援同步刷盤的能力,在海量Topic的場景下寫入延遲依然能夠保持平穩,這也是RocketMQ可與其他訊息引擎競爭的重要特性。

5.png

流場景最初應用於使用者行為分析。使用者行為分析指根據使用者的行為日誌去猜測使用者的喜好。比如推薦系統的搜尋推薦廣告等業務就是流場景最典型的場景。

流場景的第一步為將各個系統裡產生的使用者行為,包括日誌、資料庫記錄等,集中匯入到某些分析引擎。過程中資料來源多,資料的分析引擎也很多,包括離線引擎、實時引擎等。

為了降低複雜度,我們引入了類似MQ的工具,使得資料來源和資料使用者不直接互動,而是先將資料傳送到MQ裡,整個系統的連線複雜度會從O(N2)變為O(N),複雜度大大降低。

從使用者行為或者流處理的角度分析MQ扮演的角色以及它最終所期望的IT架構,可以發現其與微服務解耦的架構非常相似,兩者之間的所有概念比如consumer、producer、topic、message queue、分片等,都可以一一對應。因此,如果只考慮RocketMQ的功能,它本身就能支援流處理場景。

目前有很多公司在使用RocketMQ進行流處理,但RocketMQ在解決流處理問題時仍然存在可優化的空間。

Stream場景特徵分析

6.png

流處理的場景具有三個特點:

(1)單條訊息size很小:微服務解耦中,一條訊息一般就是一條訂單,包含的資料非常多,買家、賣家等各種資訊糅雜在一起發給下游,一條訊息通常會達到至少1KB甚至幾KB。但在流場景裡,資料類似於使用者的行為日誌,比如某個使用者登入、某個使用者下線、某個使用者瀏覽某個頁面等描述。使用者行為的表達很可能只佔幾個位元組到100個位元組。

(2)訊息數量很多:使用者的瀏覽行為數量遠遠大於操作行為數量,整體訊息數量急劇增多。通常在微服務解耦場景中,單機不會超過10萬TPS。但是在流場景或者日誌蒐集等場景當中,單機百萬TPS很常見。

(3)Catch Up讀常態化:在流場景中,經常有任務的replay,即讀取歷史資料再計算曆史結果,也稱為cache up read。相對於微服務解耦場景,catch up read在流場景中會更常見。

總而言之,在整個流場景裡,吞吐變得更加重要。

儲存增強三步曲——批、分、合

7.png

RocketMQ起初為微服務解耦設計時,是面向單條記錄,因此吞吐並不高。RocketMQ 5.0針對吞吐引入了一個新特性batch。

在傳統RocketMQ裡,一條訊息一條記錄,一條訊息一條索引。這種傳統設計的優點是能夠保證延遲更加穩定,但也意味著吞吐不高。因為通訊鏈路層的RPC次數太多,對CPU的消耗太大。因此,RocketMQ 5.0針對該問題,推出了batch功能。

Batch的基本邏輯是:在客戶端自動組裝,將多條訊息按照topic和佇列合併,作為一個請求傳送到服務端;服務端收到訊息一般不解壓,而是直接儲存;消費端一次拿下一批,將多個byte的訊息拿到本地,再進行解壓。如果每個 batch包含10條訊息,TPS可以很輕鬆地上升10倍。原本一條訊息要發一次遠端請求,而加入batch後10條訊息發一次遠端請求即可。

因為服務端不進行解壓,所以對服務端的CPU增加非常小,將解壓和合並的功能下放到各個客戶端,從而使服務端資源不容易形成瓶頸,TPS可以很輕鬆地得到提高。

8.png

流場景中另一個典型問題是擴容和資料重均衡。在微服務場景中,流量不大的情況下,擴容問題並不明顯。但是在流場景中,單機流量本來就高,一旦擴容,擴容和資料重均衡問題就難以忽略。在擴容過程中,假如原先是一個node,需要擴容變成兩個node,則會產生重均衡的問題。

為了解決該問題,通常有兩個辦法:

(1)直接增加佇列的數量,即“Add a Shard”。這種方法會產生一個問題,佇列的數量發生變化導致整個資料的分佈也發生變化。比如做word count單詞個數計算,原本A單詞位於佇列0,佇列數發生變化之後,A單詞位於佇列2,計算的結果會出現問題。因此如果增加佇列個數,流計算任務需要重新執行一遍來修正資料。另一問題為分片數,如果每動一次就增加分片數,則會導致分片數量膨脹而且很難減少,這也會產生問題。

(2)不增加佇列,但是複製佇列。比如原本佇列1在node 0上,增加一個node 1,將佇列1從node 0轉移到 node 1,過程中佇列數量沒有發生變化,資料分佈也沒發生變化,因此客戶端、傳送端、消費端等流接收任務都不需要重跑。此方法對使用者很友好,但也會帶來一個新的問題:複製過程會導致額外頻寬消耗。在流場景中需要擴容的本質原因是機器的流量過高,但是為了將流量引走還需要新增一個複製任務,在還未完成引流之前就給系統帶來額外的效能消耗,可能會導致擴容的過程直接產生網路風暴,系統崩潰。另外,複製分割槽時,因為流計算任務的每個分片資料量很大,複製過程耗時會很長。

因此採用複製方式來解決大資料儲存引擎的擴容其實很困難,可用性與可靠性難以權衡。

9.png

RocketMQ針對該問題提出了logic queue解決方案。logic queue是暴露給客戶的佇列,一個物理queue分佈在一個node上,用於實際儲存資料的佇列。一個logic queue由多個物理queue通過位點對映組合而成。

位點對映的原理如下:假設LogicQueue-1由Queue-1和Queue-2組成,Queue-1包含0到100,Queue-2包含101到200,可對映成一個總位點是0到 200的LogicQueue-1。

上述情況下,只需修改對映關係,將邏輯佇列修改到新node上的佇列裡,即可實現擴容。

寫入時,新進的資料寫入新節點,即實現了寫入端的負載均衡。而讀取過程有所不同,最新的資料會從本機讀取,老資料會採用遠端讀取。

在流計算的整個生命週期中,資料在不斷產生、不斷地消費。因此在大多數情況下,如果沒有產生堆積,遠端讀取的數量很小,幾乎能夠瞬間完成,寫入和讀取都在新節點上,以此完成擴容。這種擴容有兩個明顯優勢:其一是不需要搬運資料;其二是分片數量不用發生變化。這也意味著上下游的客戶端都無需重啟,也不用發生變化,資料任務都是完整而正確的。

10.png

嚴格意義上來看,RocketMQ是一個流儲存引擎。但RocketMQ 5.0推出了RocketMQ Streams——一個輕量級的流計算。

在RocketMQ Streams中,source 端是資料來源頭,中間有運算元,最後資料會進入Sink端。通常它們都是有狀態的,比如計算word count,每一條資料進來,一個新的單詞出現,首先要拿取過去資料的count值,加1後生成新的count值,這個中間的資料為狀態村塾,一般稱為state store。

State store的特徵包括:

(1)本地化locality:一個輕量級的流計算如果要遵循高效的計算效能,通常需要本地化。本地化指將state store的資料和計算節點放在一起,至少要快取到計算節點裡。從state store裡面取資料,就相當於從本地取資料,提升效能。如果每次讀取state store都是遠端讀取,可想而知效能會顯著下降。

(2)持久化persistency:一旦災難發生後,其他計算節點要能完整地讀到state store。例如原本在A計算節點計算資料,A計算節點出問題後要到B計算節點計算,在B計算節點也需要恢復出state store。

(3)可搬運exchangeable:state store需要能便利地從一個系統搬到另外一個系統。比如算完word count,一個BI系統或者一個網站系統想嘗試感知到該變化,則需要將資料從state store搬運到系統裡。

11.png

針對以上三個特性,RocketMQ推出了一種新的topic,稱為compacted topic。compacted topic的儲存方式和使用方式和與正常topic 一樣,唯一區別在於其服務端會將key相同的record刪掉,進行規整。

比如圖中原本offset=3的節點是K1V4,會覆蓋之前的offset=0的K1V1和offset=2的K1V3,使最後只剩下一個K1V4。此設計的優點在於重新恢復時需要讀取的資料量非常少。

State store是一個NoSQL型的table,比如word count就是一個KV 結構,key是單詞,count是單詞出現的個數,但是word count 在不斷變化,需要將錶轉變成一個流,表發生的所有變化形成的數、記錄的列表就形成了一個流,該過程稱為流轉,即將一個錶轉成一個流。RocketMQ可以通過以上方式輕鬆地將一張動態表存下來。

Compacted topic相當於一張動態表,且為流的形式,因此compacted topic是一種流表二象性的狀態。這種特殊的topic可以充當state store的儲存層——一個持久化層。

State store本身是表,且key和value不斷變化。為了實現容災的特性,需要將該表持久化,將該表的所有修改記錄形成一個流,存到RocketMQ的一個compacted topic,state store即相當於被持久化。假如一個計算節點A崩潰,B計算節點接管任務時,可以將topic以普通API的方式讀出,再在本地恢復state store,以此實現流計算任務的disaster recovery,即實現了容災特性,可以幫助RocketMQ構建一個輕量級、沒有任何外部依賴的流計算引擎。

12.png

Batch、logic queue、compacted topic三個儲存的基本特性,分別用於解決增強吞吐的問題、彈性的問題以及state store的問題。將三個儲存特性進行結合,再配合RocketMQ Streams,可以形成一個輕量級的流計算解決方案。只需要RocketMQ和RocketMQ Streams,即可實現一個通用的流計算儲存引擎。

13.png

RocketMQ 5.0從原先的微服務解耦轉變為流儲存引擎,原先的非同步解耦、削峰填補等特性依然可以在新場景中充分得以使用。

此外,RocketMQ 5.0針對流儲存的場景實現了三個重大特性的增強:其一是batch,可提升效能,將吞吐能力提升10倍;其二是logic queue,可以實現秒級擴容,並且無需搬運資料,也無需改變分片數量;其三是針對流計算場景中所用state store實現了compacted topic。

經過增強,RocketMQ向流儲存引擎發展的過程更進了一步。

加入 Apache RocketMQ 社群

十年鑄劍,Apache RocketMQ 的成長離不開全球接近 500 位開發者的積極參與貢獻,相信在下個版本你就是 Apache RocketMQ 的貢獻者,在社群不僅可以結識社群大牛,提升技術水平,也可以提升個人影響力,促進自身成長。

社群 5.0 版本正在進行著如火如荼的開發,另外還有接近 30 個 SIG(興趣小組)等你加入,歡迎立志打造世界級分散式系統的同學加入社群,新增社群開發者微信:rocketmq666 即可進群,參與貢獻,打造下一代訊息、事件、流融合處理平臺。

14.jpeg

微信掃碼新增小火箭進群

另外還可以加入釘釘群與 RocketMQ 愛好者一起廣泛討論:

15.png

釘釘掃碼加群

關注「Apache RocketMQ」公眾號,獲取更多技術乾貨