Dynamic Repartitioning for Time Series Workloads

原始來源與檔名:2026-06-09T094301+0800-Dynamic Repartitioning for Time Series Workloads.md


NAPKIN | 餐巾纸

餐巾纸公式

Dynamic Splitting = Read Detection + Async Planning + Bloom Filter Routing 在讀取時偵測過大分區,異步切分後透過 Bloom Filter 將讀取無縫路由至小分區集合。

一句话

Netflix 透過動態分區技術,解決了 Cassandra 中時序資料帶來的「寬分區」效能瓶頸,將長尾延遲從數秒降至毫秒級。

餐巾纸草图

[Client Read] ─> [Bloom Filter] ─(Hit)─> [Metadata Cache] ─> Read N small partitions in parallel

                   (Miss)

             [Read Original Wide Partition] ─(If bytes > Threshold)─> [Kafka Event] ─> [Async Splitter]

ROUND 1: SKELETON | 骨架掃描

“这本书在说什么”

章节骨架

  1. 背景與影響: Cassandra 適合時序資料,但寬分區會導致 GC 停頓、高 CPU 使用率與執行緒排隊。
  2. 時序分區策略: 將資料劃分為 Time Slices、Time Buckets 和 Event Buckets。
  3. 解決方案 1 (時間切片重分區): 透過監控直方圖,動態調整未來 Time Slices 的 bucket 大小。
  4. 解決方案 2 (動態分區 Pipeline): 在讀取路徑上偵測,異步切分特定 ID 的不可變分區,並透明地重定向讀取。
  5. 結果與驗證: 延遲大幅降低,並透過 Offline Spark job 等方式確保資料正確性。

ROUND 2: DISSECTION | 血肉解剖

“凭什么这么说”

论证链

過大的分區導致 Cassandra 讀取緩慢 --> 只有少數 ID 表現出超常流量 --> 在讀取時偵測這些極端 ID --> 將大分區切分為 N 個小分區並行讀取 --> 解決單點瓶頸

关键证据

  1. nodetool tablehistograms 顯示分區大小分佈,協助找出過度或不足分區的狀況。
  2. 平均讀取延遲從數秒降至兩位數毫秒,P99 尾部延遲降至 200ms 以下。
  3. 使用 Bloom filter 檢查是否需要路由,延遲僅在微秒級,對客戶端幾乎透明。

隐形假设与边界

ROUND 3: SOUL | 靈魂提取

“还能怎么用”

跨域映射


Dynamic Repartitioning for Time Series Workloads (Architectural Deep Dive)

前言/背景

Netflix 的 TimeSeries 抽象層使用 Cassandra 儲存 PB 級的時序資料。雖然時序資料通常容易寫入,但資料不均 (Data Outliers) 會產生巨大的「寬分區」(Wide Partitions)。這導致讀取時產生秒級的長尾延遲、GC 暫停與執行緒排隊。單純升級硬體並不划算,因此工程團隊開發了動態重分區機制。

章節詳細總結

時間切片重分區 (Time Slice Re-Partitioning)

透過分析 Cassandra 虛擬資料表中的 tablehistograms,系統背景 worker 能自動計算調整因子。如果發現分區小於設定目標 (例如 10MB),會自動修改後續 Time Slice 的 bucket size。

DynamicTimeSliceConfigWorker: 
namespace: my_dataset_1
Observed: TimeSlices have p99 partitions below configured target of 10MB. 
Proposed: time_bucket interval: 60s -> 604800s

基於 ID 的動態分區 Pipeline

對於少數爆發流量的 ID,Netflix 實作了異步的動態分區管線,包含三大階段:

  1. Detection (偵測): 每次讀取若超過位元組閾值,即觸發 Kafka 事件,標記該 time_series_id 的特定分區。
{
  "time_slice": "data_20260328",
  "time_series_id": "profileId:123",
  "immutable": true
}
  1. Planning & Splitting (規劃與切分):
    • Planner 讀取整個寬分區,計算並儲存 split checksum。
    • 根據策略 (例如 EventBucketPartitionSplitStrategy) 將資料切分至更多 event buckets,確保留有整體排序。
    • 切分完成後比對 post-split checksum,確認無誤才標記為完成。
  2. Serving Reads (讀取路由):
    • 時序伺服器將完成切分的 Partition Keys 載入記憶體中的 Bloom Filters (微秒級檢查)。
    • 若 Bloom Filter 命中,則透過 Read-Through Cache 查詢 wide_row metadata。
    • 將原本對 1 個大分區的讀取,轉換為委託給 PartitionReader 並行讀取 N 個小分區,最後合併結果。

總結與結論