Apache BookKeeper 可觀測性第五篇——讀取指標詳解

語言: CN / TW / HK

本文翻譯自《Apache BookKeeper Observability — Part 5— Read Metrics in Detail》,作者 Jack Vanlightly,Apache BookKeeper Committer。

本文由 StreamNative 組織翻譯並校對。

譯者信息:程興源

本系列基於為 Apache Pulsar 配置的 BookKeeper 4.14。在本系列上一篇文章中,我們通過利用率和飽和度指標,關注讀取路徑中一些比較簡單的過載指標。在本文中,我們將介紹所有可用指標,包括它們的含義以及使用方法。

這篇文章將關注一些 DbLedgerStorage 中較底層的指標。建議先閲讀 深入解析 Apache BookKeeper 系列:第三篇 — 讀操作原理 以瞭解 DbLedgerStorage 組件的內部工作原理。

下圖顯示了 DbLedgerStorage 不同讀取指標的位置。

圖 1. DbLedgerStorage 不同讀取指標的位置

  1. 1. bookie_read_cache_hits 以及 bookie_read_cache_misses(兩者都是 OpStatsLoggers 的屬性):延遲分佈的直方圖和讀取緩存命中與失敗的次數。這些指標將讀取和寫入緩存數據組合在一起,延遲直方圖作用有限,因為內存訪問非常快。計數器(counter)類型的指標(bookie_read_cache_hits_count 和 bookie_read_cache_misses_count)更有用,可用於檢測緩存抖動(cache thrashing),詳細信息請參見下文。

  2. 2. bookie_read_cache_size (儀表盤):這個指標毫無意義,應該忽略。讀取緩存是在啟動時預分配的環形緩衝區。這個指標或多或少只是返回環形緩衝區中的位置,沒有任何意義。

  3. 3. bookie_read_cache_count (儀表盤):所有 DbLedgerStorage 實例讀取緩存中的 entry 總數,該指標用處不大。

  4. 4. bookie_readahead_batch_count (OpStatsLogger):每個預讀操作中讀取的 entry 數的直方圖。我們還有一個用於計算預讀操作速率的 counter 指標(bookie_readahead_batch_count_count)和一個總和指標(bookie_readahead_batch_count_sum),後者表示預讀操作的總 entry 讀取速率。此指標對於診斷緩存抖動非常有用,詳細信息請參見下文。

  5. 5. bookie_readahead_batch_size (OpStatsLogger):每個預讀操作中讀取的字節數的直方圖。

  6. 6. bookie_read_entry (OpStatsLogger):整個讀取操作作為一個整體(在 DbLedgerStorage 內)的延遲直方圖,這意味着它包括跨緩存、從索引讀取、從其 entry 的日誌文件讀取 entry 和預讀的延遲。因為它包含了讀取過程的多個部分,它只能顯示整個讀取的延遲特性。此外,我們還有一個 counter 指標 bookie_read_entry_count(用於讀取速率)和一個延遲總和 bookie_read_entry_sum(用於讀取花費的時間),這兩個指標對於診斷讀取是否為瓶頸很有用。

然而,當前無法通過這些指標排查出 RocksDB 問題。同樣,如果預讀一直佔用時間,我們也無從得知。雖然還有其他獲取該信息的方法,例如火焰圖,不過我們需要訪問 bookie 服務器(或 Kubernetes 環境中的 Pod)。

檢測讀取緩存抖動

我們在 深入解析 Apache BookKeeper 系列:第三篇 — 讀操作原理 中介紹了讀取緩存抖動。這裏再提醒一下,當預讀操作最終在其他客户端能夠讀取 entry 之前將其逐出時會發生讀取緩存抖動。越早驅逐 越多的 entry,意味着有越多的 entry 必須再次從磁盤讀取。當讀取緩存太小而無法滿足需求時,就會發生這種情況。

在糟糕的情況下,這可能會導致每個 entry 從磁盤中被多次讀取,並使讀取吞吐量急劇下降。由此可見,我們應避免 bookie 發生緩存抖動。

幸運的是,檢測抖動並不難。

下面的 Grafana 面板顯示了一個負載測試。在該測試中,我通過增加不同 Topic 的消費者數量,讓它們從 Topic 開頭來讀取數據,以故意引發緩存抖動。這些消息不再在 broker 緩存中,因此 broker 必須向 bookie 發送讀取請求。

在下一個面板中可以看到,就在 22:20 之前,讀取操作速率開始快速下降,而請求率繼續攀升。相應地,由於讀取線程池任務隊列已滿,故障率攀升。讀取操作速率下降的原因是緩存抖動,請求率持續攀升的原因是 bookie 以低延遲立即拒絕請求。

圖 2. 線程池任務隊列已滿導致故障率攀升,讀取操作速率從而降低

讀取請求速率: sum(irate(bookkeeper_server_READ_ENTRY_REQUEST_count[1m])) by (pod)

失敗的讀取請求速率: sum(irate(bookkeeper_server_READ_ENTRY_REQUEST_count{success=”false”}[1m])) by (pod)

讀取操作速率: sum(irate(bookkeeper_server_READ_ENTRY_count[1m])) by (pod)

讀取帶寬: sum(irate(bookie_READ_BYTES[1m])) by (pod)

這些高級指標的具體介紹見本系列第一篇文章。

我們檢測緩存抖動的方法是隻測量讀取磁盤的次數,並與讀取操作的次數比較。針對每一次讀取操作,如果對硬盤讀取超過一次,表示 entry已被提前從緩存中逐出,並且正在再次讀取。

圖3. 讀取緩存抖動的強烈信號

每個讀取操作中讀取到磁盤的次數(請參閲這篇文章底部的解釋): (sum(rate(bookie_readahead_batch_count_count[1m])) by (pod) + sum(rate(bookie_readahead_batch_count_sum[1m])) by (pod)) / sum(rate(bookie_read_entry_count[1m])) by (pod)

緩存未命中率: (sum(irate(bookie_read_cache_misses_count[1m])) by (pod) / sum(irate(bookie_read_cache_hits_count[1m])) by (pod)) * 100

這裏還包括第二個指標,它基於緩存命中率。理想情況下,我們希望比率為 1/“首次讀取的批次大小”(1/”read-head batch size”)。你可以使用 bookie_readahead_batch_count 這個 OpStatsLogger 的屬性作為指標查看批量大小的直方圖。在上述情況下,這個指標的值介於 93 和 110 之間。這意味着健康的比率約為 1%(因為 100 次讀取操作中會有 1 次錯過緩存)。該批大小超過 1% 表明可能發生抖動,但是最終確定的唯一方法是“讀取到磁盤與讀取操作”的比率。

調優措施

如果沒有緩存抖動,那麼:

  1. 1. 首先,如果你在同一捲上運行 Journal 和 DbLedgerStorage,那麼將它們分到單獨的卷運行會很有幫助。

  2. 2. 向集羣添加更多的 bookie 以分散負載。BookKeeper 的特性之一是它的橫向動態擴展能力。

  3. 3. 配置多個 DbLedgerStorage 目錄併為每個目錄掛載一個單獨的卷。這會將文件 IO 分散到多個捲上。

  4. 4. 如果你使用的是硬盤驅動器,請嘗試切換到高性能 SSD。

如果有緩存抖動,請檢查以下一項或多項:

  1. 1. 增加 bookie 的直接內存(其中 25% 將用於讀取緩存)。

  2. 2. 專門將讀取緩存內存設置為更高的值(dbStorage_readAHeadCacheMaxSizeMb)。

  3. 3. 減少預讀批量大小,以便能夠在不同的位置/主題(dbStorage_readAheadCacheBatchSize)容納更多 Pulsar 消費者。

指標盲點

我們無法通過指標快速找到以下問題的答案:

  • • 與寫入一樣,我們無法快速判斷讀取請求失敗的原因是由於錯誤還是讀取被拒絕。你必須檢查錯誤日誌,看看是否能找到關鍵的錯誤信息以瞭解原因。

  • • 在多個 Ledger 存儲配置當中,我們無法知道是否存在一個錯誤的 DbLedgerStorage 實例。出問題的可能是卷或 RocksDB 實例,但所有指標數據是所有實例的彙總結果。

  • • 讀取速度慢是因為 RocksDB 位置索引、從 entry 日誌文件中讀取的初始條目還是預讀操作?當前的指標沒有將這些分開。

  • • 當失敗請求時,我們認為實際是請求被拒絕,並且我們還看到線程池的時間利用率小於 100%,由此可知一個或多個讀線程已飽和,但是我們不知道具體是哪些讀線程以及它們的負載分佈。

為了回答其中的一些問題,我們需要使用其他方法,例如火焰圖等。

系列總結

本文是這個解讀各項指標系列博客的最後一篇文章。我們已經介紹了很多,總結如下:

  • • 我們往往需要先查看利用率和飽和度指標以瞭解 BookKeeper 服務器是否是 Pulsar 中的瓶頸。本系列文章已經涵蓋了 4.14 版本中現在可用的所有內容。

  • • 本系列文章已經涵蓋了幾乎所有關於讀寫的可用指標,並進行了直觀的解釋。

  • • 雖然還有一些盲點,但在未來的 BookKeeper 版本中我們應該可以解決這些問題。

另外一個我們還沒有涉及的重要內容是 Pulsar 的相關指標。BookKeeper 不能孤立地工作,通常診斷性能問題需要更全面的方法。例如,BookKeeper 施加的背壓可以一直沿鏈路向上傳遞到 Pulsar 客户端。

BookKeeper 複雜的性能診斷

背壓或更高的寫入延遲可能會導致 broker 和客户端降低其寫入速率。當這種情況發生並且 BookKeeper 是瓶頸時,BookKeeper 本身可能不會出現過強的過載信號。在這些情況下,利用率仍然可能偏高,但飽和度則不一定, 這恰好也是我們可以使用 Pulsar 和 Pulsar 客户端指標進行分析的地方。希望將來我們會寫一個系列,以與研究 BookKeeper 服務器相同的方式來研究 Pulsar broker。

本系列博客中的所有示例僅供參考。根據硬件、特定負載模式等的不同,你可能會看到各種模式。希望大家能從本系列博客中學習到必要的知識,以便能更專業地研究特定的雪花數倉性能(snowflake performance)問題。

讀取磁盤與讀取操作指標的説明

(sum(rate(bookie_readahead_batch_count_count[1m])) by (pod) + sum(rate(bookie_readahead_batch_count_sum[1m])) by (pod)) / sum(rate(bookie_read_entry_count[1m])) by (pod)

我們需要用預讀操作中讀取的 entry 總和(bookie_readahead_batch_count_sum)加上正常 entry 讀取的數量。當發生緩存未命中時,將從磁盤讀取該條目,然後執行預讀。所以正常讀取的數量 = 預讀操作的數量(bookie_readahead_batch_count_count)。將它們加在一起可以得到讀取到磁盤的 entry 數,然後 bookie_read_entry_count 給出讀取操作的數量。

系列博客

▼  關注「 Apache Pulsar 」,獲取乾貨與動態  ▼

:point_down|type_1_2: 掃碼回覆  BookKeeper ,加入  Pulsar_Storage  :point_down|type_1_2: