如何理解 Pulsar 中 backlog,TTL,Retention 和 Storage Size

本文未經授權,禁止轉載,想要轉載本文,請聯系作者

本文是 http://www.lxweimin.com/p/31e7d4e5aa42 系列的第二篇,主要從 Pulsar 設計的原理以及在 BookKeeper 中如何存儲做一個梳理。

背景

在社區中,我們經常可以看到用戶有關 backlog,storage size 和 retention 等策略的困惑,比較常見的一些問題,諸如:

  • 我沒有設置 retention 策略,為什么通過 topics stats 可以查看到 storage size 遠大于 backlog size?
  • 我的 msg backlog size 很小,但是 storage size 確一直在增長?
  • ...

Pulsar 的消息模型

首先,我們先來看一下 Pulsar 的消息模型

image.png

如上圖所示,Pulsar 提供了最基本的 pub-sub 的處理模型。

Producer

首先 Producer 端生產消息,將消息以 append 的形式追加到 topic 中,這里具體分發到哪一個 topic 中,根據消息是否設置了 msg key 會有所不同。

  • 設置了 msg key,消息會基于 key 做 hash,將消息分發到不同的 partitions 中
  • 未設置 msg key,消息會以 round robin 的形式,分發到不同的 partitions 中

在消息分發的模型中,pulsar 與 kafka 類似。

Consumer

在 consumer 之外,Pulsar 抽象了一層訂閱層,用于訂閱 topic。通過訂閱層的抽象,Pulsar 可以靈活的支持 Queue 和 Streaming 這兩種類型的消息隊列。每一個 sub 都可以拿到這個 topic 中所有數據的完整 copy,有點類似 kafka 中的 consumer group。根據訂閱類型的不同,每一個訂閱下面可以有一個或者多個 consumer 來接收消息。

目前,Pulsar 支持如下四種消息訂閱模型:

  • Exclusive
  • Failover
  • Shared
  • Key_Shared

存儲模型

  1. 消息在每個 Partition Topic 的分布式日志中只存儲一次

這就意味著,當 producer 成功發送消息到 Topic 之后,這個消息只會在存儲層存儲一次,無論你有多少個 Subscription 訂閱到這個 topic 中,實際上操作的都是同一份數據。基于這個基礎,我們可以看到 Apache Pulsar 從上到下的層級抽象概念如下圖所示:

image.png

首先第一層抽象是 Topic(Partition),用來存儲 Producer 追加的 messages 信息,Topic 之下對應的是一個個的 ledger,ledger 里面又劃分為一個個的分片,在一個個的分片中存儲了更小粒度的 ertries,entries 中存儲的是 【一條】或者 【一個 batch】 的消息。

Tips: 在 Pulsar 中,一個 batch 在 broker 端會被當作一條消息來處理,batch 解析的具體邏輯是在 consumer 端接收消息時候去操作的。

Node: 在 Bookkeeper 中,對數據操作的最小單元是按照 segment 這個粒度來進行操作的。

為什么需要做分層抽象呢?

在這里最直白的解釋其實就是,為了確保數據被在每一個 bk 節點中打的足夠散,分布的足夠均勻。這也是分層分片架構設計的好處之一。

Ack 機制

在 Pulsar 中支持了兩種 Ack 的機制,分別是單條 Ack 和批量 Ack。單條 Ack(AckIndividual)是指 consumer 可以根據消息的 messageID 來針對某一個特定的消息進行 Ack 操作;批量 Ack(AckCumulative)是指一次 Ack 多條消息。

訂閱機制

為了更好的理解 Strorage Size 以及 Backlog, 我們首先需要去了解 Pulsar 中的訂閱機制,如下圖所示:

image.png

Producer 還是按照追加的形式不斷往 Topic 中發送消息,Consumer 端會創建一個 Subscription 去訂閱這個 Topic,當成功訂閱時,會初始化一個 Cursor 指向具體的消息的位置,默認情況下是 Latest。

Cursor 是用來存儲一個訂閱中消費的狀態信息

上圖中,我們可以看到該訂閱下面的 Topic 已經成功 receive 并且 ack 掉了 m4 這條消息。那么包含 m4 在內的所有的消息狀態都會被標記為可刪除的狀態。在 Pulsar 中,使用 MarkDeletePosition 來標記這個位置。之后的所有消息,代表這個訂閱還沒有消費的消息。

隨著時間的推移,假設在 AckCumulative 的場景下,上述訂閱中的 Consumer 又消費了一些消息,目前 cursor 的位置移動到了 m8 的位置,意味著 m8 之前的消息都可以進入刪除狀態。

image.png

假設是在 AckIndividual 的場景下,上述訂閱中的 Consumer 只消費了 m7 這條消息并且發送了 Ack 請求,m5, m6 這兩條消息仍然沒有被成功消費,那么目前處于可刪除狀態的消息是 m4 之前的消息和 m7 這條消息。也就是說,在這種場景下,由于使用單條 Ack 導致 topic 中間出現了 ack 的空洞。

Cursor = Offset + IndevidualDeletes, Ack 會觸發 cursor 的移動,但是不會刪除任何消息

image.png

隨著時間的推移,在單條 Ack 的場景下,Ack 的空洞可能會自己消失,如下圖所示:

image.png

上面我們描述了,單個訂閱在單條 Ack 和批量 Ack 混合的場景下,Topic 中 cursor 的移動情況。假設目前有多個 Subscription 訂閱了這個 Topic,那么每一個 Subscription 都可以拿到這個 Topic 中數據的完整 Copy,也就是一個 Subscription 會在這個 Topic 中初始化一個新的 Cursor, 每一個 Cursor 之間消費的進度是沒有交集、互不影響的,所以就可能出現下圖中的情況:

image.png

在上圖中,針對該 Topic,有兩個訂閱:Subscription-1 和 Subscription-2。Subscription-1中的 consumer 消費掉了 m4 之前的消息,Subscription-2 中的 consumer 消費掉了 m8 之前的消息。而 m4-m8 之間的這四條消息,雖然被 Subscription-2 消費完成,但是 Subscription-1 還沒有消費完成這部分數據,所以這部分消息還不可以被刪除。目前處于可刪除狀態的消息是 m4 之前的消息,即這個 Topic 中消費進度最慢的那個 Subscription 所消費完成的消息。那么這就會有一個問題,假設我目前 Subscription-1 掉線了,它的 cursor 的位置一直沒有變化,這就會導致這個 Topic 中的數據一直處于不可刪除的狀態。

針對上述場景,Pulsar 引入了 TTL 的概念,即允許用戶設置 TTL 的時間,當消息到達 TTL 指定的閾值 cursor 仍然沒有移動的話,那么會觸發 TTL 的機制,將 cursor 自動向后移到指定的位置。在這里需要注意的一點是,我們一直強調的是 TTL 會移動 cursor 的位置,到目前為止,我們還沒有提到消息刪除的概念,不要將二者混淆了。TTL 會做的只是去移動 cursor 的位置,不會有任何跟消息刪除的邏輯。

Backlog

為了更好的表述 Topic 中沒有被消費的數據,Pulsar 引入了 backlog 的概念來描述這一部分消息。Backlog 可以分為如下兩種形式:

  • Topic Backlog: 最慢的那個訂閱的 backlog 的集合
  • Subscription Backlog: 指針對單個訂閱級別的沒有消費的數據的集合

如下圖所示:Backlog A 屬于 Topic Backlog;Backlog A 屬于 Subscription-1 Backlog;Backlog B 屬于 Subscription-2 的 Backlog。

image.png

隨著時間的推移,Backlog 的會不斷的變化,如下圖所示:

image.png

在這里需要說明的一點是,這里的 backlogSize 記錄的是帶 batch 的消息,也就是一個 batch 會被當作一條消息來進行處理。因為在 broker 端去解析整個 batch 會給 broker 帶來一定的負擔,同時浪費大量的 CPU 資源,所以,具體 batch 邏輯的解析放到了 consumer 端來進行處理。所以 backlog 本質上記錄的是上面我們提到的 entries 的數量。

在 Pulsar 中,針對 backlog 有兩個指標,具體如下:

  • msgBacklog: 記錄的是所有未被 Ack 的 entries 的集合
  • backlogSize:記錄的是所有沒有被 Ack 的消息的大小

有關更多 backlog 的介紹,可以參考 http://www.lxweimin.com/p/31e7d4e5aa42

Retention 機制

在 Apache Pulsar 中,使用了 BookKeeper 來作為存儲層,允許用戶將消息持久化,為了確保消息不會無限期的持久化下去,pulsar 引入了 retention 的機制,允許用戶來配置消息持久化的策略。默認情況下,持久化的機制是關閉的,即消息被 ack 之后,就會進入刪除的邏輯。

配置 Retention 策略時,有如下兩個參數可以指定:

  • size:指持久化大小的閾值。0 代表不配置 retention 大小策略,-1 代表設置的大小無限大
  • time:指持久化時間的閾值。0 代表不配置 retention 時間策略,-1 代表時間無限大

在引入 retention 策略之后,整個 topic 表示的視圖如下所示,m0-m5 代表已經被所有訂閱確認的消息并且已經超過了 retention 策略的閾值,即這些消息正在 準備刪除。注意,我這里描述的是 【準備刪除】具體是否可以被刪除,現在還不能確定。

image.png

在最開始,我們從最上層的 topic 一步步抽象到了一條具體的 msg,(在這里為了方便描述,我們忽略掉 batch 的概念,即一條 msg 等價于一個 entry)現在我們再反過來把所有的概念都疊加回去。因為在 bk 中,允許操作的最小的單元是一個 segment,所以在具體的 msg(entry)級別,是沒辦法針對一條消息進行刪除的,刪除操作需要針對一個 segment 來進行操作。如下圖所示:

假設 m0-m3 屬于 segment3;m4-m7 屬于segment2;m8-m11 屬于 segment1。按照上圖的描述,m0-m5 的消息都可以進行刪除操作, 但是 segment 2 中包含了 m6, m7 并沒有達到 retention 的閾值,所以 segment 目前還不可以被刪除。

image.png

Storage Size

為了更方便的表述當前消息占用的存儲空間的大小,pulsar 引入了 storageSize 來描述整個概念。如下圖所示:當 backlog B 與 storage Size 標識的消息相同時,backlogSize 等價于 storageSize。

image.png

當由于引入單條 ack,retention 策略以及 Bookkeeper 基于 segment 刪除的設定,那么很有可能造成 Storage Size 大于 backlog Size 的場景,如下圖所示:

image.png

總結

  1. 消息在每個 Partition Topic 的分布式日志中只會存儲一次
  2. cursor 是用來存儲一個訂閱下 consumer 的消費狀態的
  3. Cursor 等價于 offset(kafka)+ individualDeletes
  4. Ack 會去更新 topic 中 cursor 的位置
  5. 當某條消息被所有訂閱者都 ack 之后,這條消息進入【可以被刪除】的狀態
  6. 所有沒有被確認的消息會一直保存在 Subscription backlog 中
  7. TTL 可以通過設定一個時間閾值來自動更新 cursor 的位置
  8. Retention 策略是用來操作那些被 ack 之后的消息應該怎么處理
  9. 消息的刪除是以 segment 為單位的,而不是 entry。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,702評論 2 380

推薦閱讀更多精彩內容