RocketMQ 流存儲解析:面向流場景的關鍵特性與典型案例

作者:林清山(隆基)

前言:

從初代開源消息隊列崛起,到 PC 互聯網、移動互聯網爆發式發展,再到如今 IoT、雲計算、雲原生引領了新的技術趨勢,消息中間件的發展已經走過了 30 多個年頭。

目前,消息中間件在國內許多行業的關鍵應用中扮演着至關重要的角色。隨着數字化轉型的深入,客戶在使用消息技術的過程中往往同時涉及交叉場景,比如同時進行物聯網消息、微服務消息的處理,同時進行應用集成、數據集成、實時分析等,企業需要爲此維護多套消息系統,付出更多的資源成本和學習成本。

在這樣的背景下,2022 年,RocketMQ 5.0 正式發佈,相對於 RocketMQ 4.0,架構走向雲原生化,並且覆蓋了更多的業務場景。

背景

什麼是流存儲呢?前面我們在 《從互聯網到雲時代,Apache RocketMQ 是如何演進的?》 裏提到 RocketMQ 5.0 具備“消息、事件、流”一體能力。這裏的“流”指的就是流處理,而流存儲是流處理的基石,流存儲也是 RocketMQ 從應用架構集成走向數據架構集成的基礎, 爲大數據架構的數據組件提供異步解耦的能力。

本文第一部分,我們將從使用的角度出發,詳細展示一下流存儲的場景,看看它和業務消息的場景有哪些區別?第二部分,我們會講 RocketMQ 5.0 面向流存儲的場景,提供了哪些特性?第三部分,我們再結合兩個數據集成的案例,來幫助大家瞭解流存儲的用法。

什麼是流場景

先看第一部分,什麼是流場景?我們通過下面這個對比圖來看,消息和流的區別。

前面我們講的消息基礎(《RocketMQ 5.0 架構解析:如何基於雲原生架構支撐多元化場景》《RocketMQ 在業務消息場景的優勢詳解》)、消息進階(《Apache RocketMQ 5.0 消息進階:如何支撐複雜的業務消息場景?》)都側重於講消息的業務集成。這裏 RocketMQ 的主要作用是連接業務應用,解耦業務架構的上下游系統,比如交易系統的解耦。這類場景,更多的是在線業務,由用戶觸發某個業務流程,比如購買。爲了保障用戶體驗,消息系統要優先保障低延遲。這個場景裏和同步通信 RPC 對應,消息系統承擔都是異步通信職責。在消息消費層面,更多的是基於消息數據執行對應的業務邏輯,觸發下一個業務流程。每條消息的處理都是不相關的,無狀態的。側重於業務數字化場景,可類比於數據庫的 OLTP,單次操作數據量少,用於在線交易。

再來看流場景,它主要是側重於數據集成,連接各種數據組件,進行數據分發,解耦數據架構的上下游系統。 比如日誌解決方案,採集日誌數據,進行 ETL 將日誌數據分發到搜索引擎、流計算、數據倉庫等。除了日誌之外,數據庫 Binlog 分發、頁面點擊流也是常見的數據源。在這種場景裏裏面,由於是離線業務,它對低延遲的需求較弱,更加側重於大批量吞吐型負載。另外在消息消費階段,不再是單條消息處理,更多的是批量轉儲,或者批量進行流計算。側重於數字業務化場景,可類比於數據庫的 OLAP,單次操作數據量大,用於離線分析場景。

流存儲特性

1. 流存儲基礎

第二部分我們看看,在流的場景下,對於 RocketMQ 的用法有何不同?

最大的區別就是它對於消息數據的訪問模式:

  • 由於用在數據集成場景,對於大規模的數據集成,不可避免的要涉及到數據的分片,基於數據分片來連接上下游數據系統。爲了提升數據集成的質量,需要 Topic 的分區數不變,這樣才能保證同一個分區的數據不會錯亂。在消息的讀寫方式上,不再是指定 Topic 讀寫,而是指定 Topic 分片,也就是隊列,進行讀寫操作。
  • 作爲流存儲系統,下游的消費通常會是一些流計算引擎,用於有狀態計算。爲了支撐流計算引擎的容錯處理,它需要支持 checkpoint 機制,類似於爲流計算引擎提供 redolog,能夠按照隊列位點重放消息,重新恢復流計算的狀態。它也會要求分片內有序,同一個 key 的數據會 hash 到同一個分片,用於實現 keyby 的操作。

這就是流存儲訪問模式跟消息訪問模式的區別。在消息場景裏,用戶只需要關注到 topic 資源,無需瞭解隊列、位點等概念。

2. 流存儲彈性

2.1 RocketMQ 經典擴容模式

剛纔我們從用戶維度瞭解了流存儲的使用方式,現在我們再從運維角度來看流存儲如何彈性?

我們先回顧一下現在業界的彈性方式。左下圖是 RocketMQ 的經典擴容模式,比如說要將 Topic A 的容量擴容一倍,一般做法是新增一臺機器,然後創建 Topic A,新增同等數量的隊列。這樣的話,分片數量也會擴容一倍,無法滿足流存儲固定分區的場景。

右下圖則是 Kafka 的擴容模式,要將 Topic A 的容量擴容一倍時,需要添加一個新節點,並將原來舊節點的分區 mq-2 遷移到新節點。它雖然可以保證數分區數量不變,但是要對分區數據做遷移。當分區數特別多且數據量大,講對集羣產生流量風暴,嚴重影響穩定性,而且整個擴容時間不可控。

現有的流存儲彈性機制都有所不足。

2.2 RocketMQ 5.0 靜態 Topic 擴容模式

爲了解決經典流存儲的擴容難題,RocketMQ 5.0 提供了一種新的模式,引入靜態 topic 。在靜態 topic 的擴容模式,可以做到分區數不變,且擴容過程無數據遷移,可以實現秒級的擴容。

它的實現關鍵點是引入邏輯隊列的概念。就是對於用戶來說,它的訪問的對象是不再是原來綁定到某個 Broker 的物理隊列,而是 Topic 全局的邏輯隊列,每個邏輯隊列會對應一個或者多個物理隊列。

我們基於實際的案例,來理解邏輯隊列的實現原理。圖爲 Topic A 進行流量擴容一倍的操作,最初邏輯隊列 1 綁定的物理隊列是 Broker1 的 mq1。在擴容完成後,Broker1-mq1 變成只讀狀態,邏輯隊列 1 的最新讀寫操作都在 Broker2-mq1,生產者最新的消息都會發往 Broker2-mq1。消費者如果讀最新數據,則直接從 Broke2-mq1 的物理隊列裏面去讀取;如果它讀的是老數據的話,讀請求講轉發到舊物理隊列 Broker1-mq1。這樣就完成了整個靜態 topic 的擴容流程。既保證的分區數不變,又實現了沒有數據遷移,降低了大量的數據複製,提升了系統的穩定性。

3. 高吞吐

在流場景裏面,還有一個很重要的變化,就是數據類型的變化。

做個簡單對比,業務集成場景,消息的數據承載的是業務事件,比如說訂單操作、物流操作,特點就是數據規模較小,但是每一條數據的價值都特別高,訪問模式是偏向於在線的,單條事務的短平快訪問模式。

而在流場景裏面,更多的是一些非交易型的數據。比如用戶日誌,系統的監控、IoT 的一些傳感器數據、網站的點擊流等等。特點是數據規模有數量級的提升,但單條數據的價值比較低的,訪問模式偏向於離線批量傳輸。所以在流的場景裏面,RocketMQ 存儲要面向高吞吐做更多的優化。

在 RocketMQ 5.0 裏面,我們引入了端到端的批量消息。如何理解端到端呢?就是從客戶端開始,在發送階段,消息在客戶端攢批到一定數量,直接一個 RPC 請求裏面直接發到 Broker 端。Broker 存儲階段,直接把整批消息存儲,用批量索引的技術,一批消息只會構建一個索引,大幅度提升索引構建速度。在消費階段,也是按照整批數據讀取到消費端,先進行解包操作,最後執行消費邏輯。這樣整個 Broker 的消息 TPS 可以從原來的十萬級提升至百萬級。

4. 流的狀態

流存儲通常會對接流計算引擎,比如 Flink、Spark 等。流計算引擎涉及的一些有狀態計算,如數據聚合類的,求平均、求總和、keyby、時間窗口等算子都需要維護計算狀態。

所以在 RocketMQ 5.0 裏面,我們新增了 CompactTopic 的類型,是一種以流爲核心的類 KV 服務,在不引入外部 KV 系統的情況下維護流的狀態。它還適用於一些特殊場景,可作爲最新值隊列,比如用於股票價格流場景,股票交易,用戶只關注每隻股票的最新價格。

我們通過下圖來了解一下 CompactTopic 的實現,在 CompactTopic 裏面,每條消息就是一對 KV。如果用常規的 Topic,那麼同一個 Key 的持續更新會佔用大量的空間,影響讀的效率。在生命週期管理上,也會因爲磁盤佔用過高,按照 FIFO 的方式,舊數據被整批刪除。而對於 CompactTopic 來說,Broker 會定期對同一個 Key 的消息進行合併,節約存儲空間,用戶對 Topic 的流式訪問,也只會讀到每個 Key 的最新值。

我們來結合這個例子,能對 CompactTopic 有更加形象的理解。消息生產沒啥區別,需要爲消息添加 Key。區別主要體現在消費的方式上,首先我們要用 PullConsumer,這是一個用於流場景的的消費者 SDK。然後我們要獲取 Compact topic 的隊列,進行隊列分片。然後每一個消費者實例都會分配到固定的隊列,承載這個分區的流狀態的恢復。在這裏的話,用 HashMap 進行模擬,重放整個隊列,重新構建 KV。

5. 流數據 Schema

隨着 RocketMQ 的數據生態的繁榮,數據集成涉及的上下游組件越來越多,提升數據治理能力也變得迫在眉睫。因此我們在 RocketMQ 5.0 引入 Schema 的概念,爲消息增加結構化的描述。

它帶來了幾個好處:第一個是可以提高類型的安全,避免消息結構變化導致上下游數據集成不兼容,集成失敗。第二個是可以提升數據集成的研發效率,上下游通過 Schema 註冊中心獲取消息結構,節約溝通成本,內置高效序列化機制,無需編寫重複的序列化代碼。同時在流表融合的大背景下面,消息 Schema 能和數據庫的表結構的概念完成映射,提升流式 SQL 親和度。

下圖是就是消息 Schema 的架構。首先會有一個 Schema 註冊中心的組件,維護 Schema 的數據,數據存儲基於 CompactTopic。在消息收發的過程中,客戶端都會先去獲取 Schema 的格式,進行格式的校驗,用內置的序列工具進行序列化,從而完成整個消息收發的鏈路。

我們再來看 Schema 的代碼示例。左邊是生產者、右邊是消費者,代碼結構和常規的方式接近。唯一的區別是,發送的對象是業務領域對象,無需自行轉成 byte 數組。對於消費者也一樣,消費者直接獲取業務對象執行業務邏輯,減少了序列化、反序列化等繁雜的工作,提高了研發的效率。

典型案例

最後我們再來看幾個 RocketMQ 流存儲的例子。

案例 1 :日誌的採集和流 SQL 分析

首先,我們通過批量的索引,提升日誌採集的吞吐量,降低機器成本。我們爲日誌消息引入 Schema,如這是用戶在電商平臺的行爲操作,如商品進行收藏、加購、購買等操作,使得消息數據就像流動的表。在流存儲下游對接 FlinkSQL 或者 RSQLDB,完成流式 SQL 分析。

案例 2 :異構數據庫的同步

如下圖,我們有兩個數據庫,一個是按照買家 ID 的維度進行分庫分表的,另外一個是按照賣家 ID 的維度進行分庫分表,我們需要實時同步兩個數據庫的訂單狀態。基於 RocketMQ 的的流存儲的能力,上游按照訂單的 ID 去對 Binlog 進行分片,確保同一個記錄的 Binlog 數據能分發到同一個隊列。在消費階段按照順序重放隊列裏的 Binlog 數據,把數據同步到賣家庫。當流量不足時, RocketMQ 對靜態 Topic 進行擴容,分區數不變,保障了數據同步的正確性。

總結

這篇文章,我們瞭解了流存儲用於數據集成的場景,它可以作爲大數據架構的數據樞紐,連接數據的上下游組件。而 RocketMQ 的流存儲的特性,既包含功能層面,提供流式的訪問接口、狀態存儲、數據治理的能力,也包括了流的彈性、流的高吞吐能力。最後,我們也展示了兩個數據集成的案例,包括日誌的分析以及異構數據庫的同步。

我們將持續爲您帶來深度剖析 RocketMQ 5.0 的系列文章,歡迎點擊此處進入官網瞭解更多詳情,也歡迎填寫表單進行諮詢:https://survey.aliyun.com/apps/zhiliao/bzT3AfPaq

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章