Skip to main content

Command Palette

Search for a command to run...

Prometheus TSDB 第一次接觸

Published
7 min readView as Markdown

1. 架構總覽

🏗️ 核心架構流程

🔑 核心概念:Prometheus 使用多層級的儲存架構,用來確保數據的持久性高效查詢儲存空間優化的保證。

2. WAL (Write-Ahead Log)

📝 功能定位

WAL是所有新數據的第一站,類似資料庫的 transaction log,確保數據不會因系統崩潰而遺失。

📁 檔案結構

/data/wal/
         ├── 00000000  # 128MB segment
         ├── 00000001  # 128MB segment
         ├── 00000002  # 活躍寫入
        └── checkpoint.00000001/

⚙️ 特性

特性說明
大小每個 segment 128MB
順序必須連續編號
保留2-3 小時數據
格式二進制

🔄 WAL 工作流程

✅ WAL 的作用

  1. 持久化保證:先寫入磁碟,確保數據安全

  2. 崩潰恢復:重啟時重建 Head Block

  3. 順序寫入:高效的磁碟 I/O


3. Head Block (記憶體區塊)

💾 功能定位

存放在記憶體中的活躍數據,提供最快的查詢速度。

🏗️ 結構組成

📊 關鍵特性

  • 數據範圍:通常 2-3 小時

  • 查詢速度:極快(直接從記憶體)

  • 壓縮算法:XOR + Delta-of-Delta

  • 更新頻率:即時


4. Checkpoint (檢查點)

✅ 功能定位

WAL 的快照,加速 Prometheus 重啟,減少需要重放的 WAL 數量。

📸 Checkpoint 機制

✨ 優點

  • ✅ 重啟更快(不需要重放所有 WAL)

  • ✅ 減少磁碟使用(可刪除舊 WAL)

  • ✅ 每 2 小時自動創建

🔧 工作原理

1.2 小時創建一次 checkpoint
2. Checkpoint 包含 00000000-00000002 的數據
3. 舊的 WAL segments 可以安全刪除
4. 重啟時:
   → 讀取最新 checkpoint
   → 重放之後的 WAL segments

5. Persistent Block (持久化區塊)

💿 功能定位

壓縮後的歷史數據,不可變(immutable),存儲在磁碟上。

📦 Block 結構

/data/01K9TJBMDM5BC097TAG3HETHDZ/  ← Block ULID
├── chunks/
│   └── 000001              # 壓縮的時間序列數據
├── index                   # 倒排索引(快速查詢)
├── meta.json               # 元數據(時間範圍、統計)
└── tombstones              # 刪除標記

🔄 Block 壓縮層級

📊 壓縮層級說明

層級時間範圍來源
Level 02 小時從 Head Block 轉換
Level 14-6 小時合併 2 個 Level 0
Level 212-24 小時合併多個 Level 1
Level 3+24+ 小時長期歷史數據

🎯 Block 特性

  • 不可變:一旦創建就不會修改

  • 時間範圍固定:每個 Block 覆蓋固定時間

  • 高壓縮率:~84% 空間節省

  • 快速查詢:通過 index 加速


6. Chunks (數據塊)

📦 功能定位

實際存儲時間序列樣本的地方,使用高效壓縮算法。

🗜️ 壓縮效率

類型大小說明
原始數據16 bytes/sampletimestamp (8) + value (8)
壓縮後1.3 bytes/sampleXOR + Delta-of-Delta
壓縮率84%節省空間

🔧 壓縮技術

📊 Chunk 組織

一個時間序列:metric{label="value"}

├── Chunk 1 (0-2小時)
│   ├── timestamp: 1763445600
│   ├── value: 42.5
│   ├── timestamp: 1763445615
│   └── value: 43.1
│   
├── Chunk 2 (2-4小時)
└── Chunk 3 (4-6小時)

7. 數據生命週期

🔄 完整流程

① 數據寫入階段

Scrape Target
    ↓
寫入 WAL (磁碟) ← 崩潰恢復保證
    ↓
寫入 Head Block (記憶體) ← 快速查詢
    ↓
定期創建 Checkpoint ← 加速重啟

② 數據壓縮階段(每 2 小時)

Head Block (記憶體)
    ↓
持久化為 Block (磁碟)
    ↓
Chunks 壓縮存儲
    ↓
創建 Index (快速查詢)
    ↓
舊 WAL 可刪除

③ 數據查詢階段

Query
    ↓
├── 查詢 Head Block (最近 2 小時) ← 記憶體,最快
└── 查詢 Persistent Blocks ← 磁碟,較慢
    ├── 讀取 Index (找到相關 Chunks)
    └── 讀取 Chunks (解壓縮數據)

📊 時間軸示意

時間: 0h    2h    4h    6h    8h    10h   12h
      ├─────┼─────┼─────┼─────┼─────┼─────┤
WAL:  [====活躍數據====]
      └────────┘
      轉換為 Block

Head: [====記憶體====]

Blocks:    [B1] [B2] [B3] [B4] [B5] ...
           └──┬──┘   └──┬──┘
              [B6]      [B7]  ← Level 1 壓縮
              └────┬────┘
                  [B8]       ← Level 2 壓縮

8. 問題診斷與解決

❌ 常見錯誤

opening storage failed: get segment range: segments are not sequential

🔍 錯誤原因

WAL segments 的編號不連續:

✗ 錯誤情況:
/data/wal/
├── 00000000
├── 00000001
- ├── 00000003  ← 缺少 00000002!
└── 00000004

✓ 正確情況:
/data/wal/
├── 00000000
├── 00000001
+ ├── 00000002  ← 連續!
└── 00000003

🎯 情況分析

/data/wal/
├── 00000              ⚠️ 不該存在!
├── checkpoint.00587/  ✓ 正常
├── 00588              ✓ 正常
└── 00589              ✓ 正常

診斷結果

  • ⚠️ 00000 是孤立的舊 segment

  • ✅ Checkpoint 機制正常運作

  • ✅ 新的 segments (00588, 00589) 正常

原因

  • Pod 異常重啟時創建了 00000

  • 但舊的 checkpoint 和 segments 還保留著

  • 導致 WAL 結構不一致


🛠️ 解決方案

方案對比

方案影響適用場景操作複雜度
方案 1:刪除異常 segment🟢 最小單一 segment 損壞簡單
方案 2:刪除整個 WAL🟡 中等多個 segment 損壞中等
方案 3:完全重置🔴 最大測試環境/嚴重損壞複雜

✅ 推薦方案:刪除異常 00000

步驟 1:驗證問題

kubectl exec -n kubecost kubecost-prometheus-server-7dd5f595d6-4k8h6 \
  -c prometheus-server -- ls -lh /data/wal/00000

步驟 2:備份(可選)

kubectl exec -n kubecost kubecost-prometheus-server-7dd5f595d6-4k8h6 \
  -c prometheus-server -- cp /data/wal/00000 /tmp/wal_00000_backup

步驟 3:刪除異常檔案

kubectl exec -n kubecost kubecost-prometheus-server-7dd5f595d6-4k8h6 \
  -c prometheus-server -- rm /data/wal/00000

步驟 4:重啟 Pod

kubectl delete pod -n kubecost kubecost-prometheus-server-7dd5f595d6-4k8h6

步驟 5:驗證恢復

# 監控新 Pod 啟動
kubectl get pods -n kubecost -w

# 查看日誌
kubectl logs -n kubecost <new-pod-name> -c prometheus-server -f

# 應該看到:
# ✅ "Server is ready to receive web requests"

步驟 6:檢查 WAL 結構

kubectl exec -n kubecost <new-pod-name> -c prometheus-server -- \
  ls -lh /data/wal/

# 預期結果:
# checkpoint.00587/
# 00588
# 00589
# 00590 (新創建)

🔄 備選方案 2:刪除整個 WAL

如果方案 1 失敗,使用此方案:

# 進入 Pod
kubectl exec -it -n kubecost <pod-name> -c prometheus-server -- sh

# 刪除 WAL 和 chunks_head
rm -rf /data/wal/*
rm -rf /data/chunks_head/*

# 退出並重啟
exit
kubectl delete pod -n kubecost <pod-name>

影響

  • ❌ 丟失最近 2-3 小時數據

  • ✅ 保留所有歷史 Blocks


🔄 備選方案 3:完全重置

僅用於測試環境或嚴重損壞!

# 1. 縮減副本
kubectl scale deployment kubecost-prometheus-server -n kubecost --replicas=0

# 2. 刪除 PVC(會刪除所有數據!)
kubectl delete pvc -n kubecost -l app=prometheus

# 3. 重新啟動
kubectl scale deployment kubecost-prometheus-server -n kubecost --replicas=1

影響

  • 丟失所有歷史數據

  • ✅ 全新乾淨的資料庫


📊 預防措施

1. 監控指標

# WAL segment 數量
prometheus_tsdb_wal_segment_current

# WAL 損壞次數
prometheus_tsdb_wal_corruptions_total

# Checkpoint 失敗次數
prometheus_tsdb_checkpoint_creations_failed_total

# TSDB Head 大小
prometheus_tsdb_head_series

2. 資源配置建議

# Prometheus 配置
resources:
  limits:
    memory: 4Gi        # 足夠的記憶體
    cpu: 2000m
  requests:
    memory: 2Gi
    cpu: 1000m

# 存儲配置
storage:
  tsdb:
    retention.time: 15d
    retention.size: 50GB
    wal-compression: true  # 啟用 WAL 壓縮

3. 定期檢查清單

  • [ ] 每週檢查 WAL 結構

  • [ ] 監控磁碟使用率(> 80% 告警)

  • [ ] 定期使用 promtool 驗證

  • [ ] 檢查 Prometheus 日誌中的錯誤

  • [ ] 監控 Pod 記憶體使用(避免 OOM)

4. 使用 Promtool 驗證

# 檢查 TSDB 健康度
kubectl exec -n kubecost <pod> -c prometheus-server -- \
  promtool tsdb analyze /data

# 檢查 WAL 完整性
kubectl exec -n kubecost <pod> -c prometheus-server -- \
  promtool tsdb check wal /data/wal

# 列出所有 Blocks
kubectl exec -n kubecost <pod> -c prometheus-server -- \
  promtool tsdb list /data

📚 總結

核心概念回顧

數據流向:
Scrape → WAL → Head Block → Checkpoint → Persistent Block → Chunks
         ↓      ↓            ↓            ↓                 ↓
      持久化  快速查詢    加速重啟     長期存儲         高壓縮

關鍵要點

  1. WAL:預寫日誌,確保數據持久性

  2. Head Block:記憶體中的活躍數據

  3. Checkpoint:WAL 快照,加速重啟

  4. Persistent Block:壓縮的歷史數據

  5. Chunks:實際數據存儲,高效壓縮

故障影響範圍

組件損壞影響恢復難度
WAL丟失 2-3 小時數據容易
Head Block丟失 2-3 小時數據容易
Checkpoint重啟較慢容易
Persistent Block丟失該 Block 時間範圍數據困難

🔗 參考資源

145 views

More from this blog

Get Your Hands Dirty on Clean Architecture CH5 Use Case

書本連結 前言 會挑這本書看的人,應該都是關心自己負責專案的軟體架構的人。不只希望開發的軟體能滿足客戶的明確需求,也希望能滿足可維護性(maintainability)的隱性需求,以及自己對結構與美觀習慣的要求。 要能滿足上述這些要求很難,因為專案通常不會按照計畫進行。可能變因有 deadline,最後的 API 與承諾的不同,又或者我們的設計無法很好的貼合需求的變化所需。。因此完美的架構只有在一

Jul 2, 20264 min read26
Get Your Hands Dirty on Clean Architecture CH5 Use Case

Claude Code 監控秘錄:OpenTelemetry(OTel/OTLP)實戰指南

稟告主公:此乃司馬懿進呈之兵書,詳解如何以 OpenTelemetry 陣法,令臥龍神算之一舉一動盡在掌握,知糧草消耗、察兵器效能、辨戰報異常,使主公運籌帷幄於大帳之中。 為何需要斥候情報? 司馬懿稟告主公: 臥龍神算(Claude Code)乃當世利器,然若無斥候回報,主公便如蒙眼行軍——兵器耗損幾何、糧草消費幾許、哪路斥候出了差錯,一概不知。臣以為,此乃兵家大忌。 無情報之弊,有四: 軍

Feb 19, 202610 min read241
Claude Code 監控秘錄:OpenTelemetry(OTel/OTLP)實戰指南
M

MicroFIRE

74 posts