Apache Pulsar 技術系列 - GEO replication 中訂閱狀態的同步原理

導語

Apache Pulsar 是一個多租戶、高性能的服務間消息傳輸解決方案,支持多租戶、低延時、讀寫分離、跨地域複製(GEO Replication)、快速擴容、靈活容錯等特性,GEO Replication 可以原生支持數據和訂閱狀態在多個集羣之間進行復制,GEO 目前在 Apache InLong 內部已經有長期穩定的實踐,本文主要講述 GEO 中的訂閱狀態的同步。 

GEO 簡介

GEO Replication 提供了數據在多個集羣之間進行復制的能力。

圖片

上圖描述了三個集羣,並且集羣之間配置了不同的 GEO Replication 策略,其中

上述描述數據同步 / 複製的一個典型的場景,GEO Replication 中的另外一個場景就是訂閱狀態同步。

訂閱狀態同步的場景

訂閱同步的一個典型的應用常見是集羣容災,正常情況下只有主集羣提供寫入和消費服務,主集羣故障之後,生產和消費會切換到備集羣。

生產的切換是無縫的,切換集羣之後可以繼續寫入;消費比生產會複雜一些,如果只同步數據,在集羣切換之後,備集羣的訂閱會重複消費歷史數據,爲了解決這個問題,就需要在兩個集羣之間同步訂閱的狀態,目前訂閱同步的主要信息就是訂閱的 MarkDeletePosition(MDP) 信息。

圖片

如上圖:在主、備兩個集羣之間,每個 Topic(分區)的 Ledger 並不是一一對應的,比如在主集羣中,訂閱 sub-00 消費到了一條消息,這個消息所在的 Ledger 是 Ledger-x;經過複製之後,在備集羣中這條消息對應的 Ledger 是 Ledger-y,這裏 Ledger-x 和 Ledger-y 沒有直接關係,所以訂閱狀態(MDP)不能簡單的直接映射。

GEO 訂閱狀態同步原理

訂閱狀態的同步,大體上可以分爲兩個主要的步驟:

下面我們來詳細看下整個流程。

MessageId 映射

MessageId 映射最直觀的方法,就是維護主、備集羣中每個 Message 的映射關係,但是這種方案的需要維護的映射關係太多,代價太大。

Pulsar 採用的方式是一個定時任務的方式,每隔一段時間同步一次主、備集羣 LAC 信息之間的關係。假設集羣 A 向集羣 B 複製數據和訂閱狀態信息。

圖片

首先,集羣 A 會定時生產一個 SnapshotRequest 信息,寫入到本地 Topic(分區)中,這個信息會隨着數據複製寫入到集羣 B 的 Topic 中。

圖片

B 集羣會處理 SnapshotRequest 信息,然後將本地 Topic(分區)的 LAC(LAC-B) 信息封裝在 SnapshotRespnse 中,寫入到本地 Topic 中,通過 GEO Replciation 複製到 A 集羣。

圖片

集羣 A 在處理 SnapshotRespnse 時,記錄 SnapshotRespnse 在本地的 MessageId(LocalMessageId) 和 LAC-B 的映射關係,由於 A -> SnapshotRequest -> B -> SnapshotRespnse -> A 的操作順序,可以保證集羣 A 訂閱的 MDP 大於 LocalMessageId 時,LAC-B 對應的數據一定是被消費過的,通過這種方式實現了兩個集羣之間 MessageId 的映射關係。

訂閱信息同步

集羣 A 中的訂閱會不斷消費、Ack,當 Ack 觸發了 MDP 的移動時,集羣 A 會檢查 LocalMessageId 是否小於 MDP,如果發現小於,說明需要更新集羣 B 訂閱的 MDP 信息,此時集羣 A 會根據映射關係,找到 LAC-B 信息,然後構造一個 ReplicatedSubscriptionsUpdate 消息,寫入到本地 Topic,這個 ReplicatedSubscriptionsUpdate 消息會通過 GEO 複製到集羣 B。

圖片

集羣 B 接收到 ReplicatedSubscriptionsUpdate 消息之後,會解析出 LAC 和訂閱信息,然後更新訂閱的 MDP。

至此,就完成了訂閱狀態的一次複製流程。

總結與思考

Pulsar 的訂閱狀態複製,依賴於原生的 GEO Replication 機制,並且需要主備集羣之間雙向的交互,所以對於單向複製的 GEO 集羣,訂閱狀態是不能實現訂閱狀態同步的。

另外,當前的訂閱狀態同步,只考慮了 MDP 信息,實際上對於一個訂閱(尤其是 Shared 和 Key-Shared 類型的訂閱),訂閱的 IndividuallyDeletedMessages 信息也是很重要的,尤其是在有大量 Consumer 都使用 Individual Ack 的場景,如果不同步 IndividuallyDeletedMessages 信息,就會導致數據的重複。

由於 IndiviindividuallyDeletedMessages 記錄的是每個 message 的 Ack 情況,所以要解決這個問題就需要:

備集羣的訂閱在消費數據時,根據主、備 集羣的 MessageId 映射關係以及主集羣複製過來的 IndiviindividuallyDeletedMessages,就可以判定這條消息是否已經被 Ack,如果 Ack 則不推送給 Consumer,這樣就可以實現切換集羣訂閱時數據不重複。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6nOjRc9jA6Bh3uqOOWSKRQ