Prometheus TSDB 第一次接觸
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 的作用
持久化保證:先寫入磁碟,確保數據安全
崩潰恢復:重啟時重建 Head Block
順序寫入:高效的磁碟 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 0 | 2 小時 | 從 Head Block 轉換 |
| Level 1 | 4-6 小時 | 合併 2 個 Level 0 |
| Level 2 | 12-24 小時 | 合併多個 Level 1 |
| Level 3+ | 24+ 小時 | 長期歷史數據 |
🎯 Block 特性
不可變:一旦創建就不會修改
時間範圍固定:每個 Block 覆蓋固定時間
高壓縮率:~84% 空間節省
快速查詢:通過 index 加速
6. Chunks (數據塊)
📦 功能定位
實際存儲時間序列樣本的地方,使用高效壓縮算法。
🗜️ 壓縮效率
| 類型 | 大小 | 說明 |
| 原始數據 | 16 bytes/sample | timestamp (8) + value (8) |
| 壓縮後 | 1.3 bytes/sample | XOR + 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
↓ ↓ ↓ ↓ ↓
持久化 快速查詢 加速重啟 長期存儲 高壓縮
關鍵要點
WAL:預寫日誌,確保數據持久性
Head Block:記憶體中的活躍數據
Checkpoint:WAL 快照,加速重啟
Persistent Block:壓縮的歷史數據
Chunks:實際數據存儲,高效壓縮
故障影響範圍
| 組件 | 損壞影響 | 恢復難度 |
| WAL | 丟失 2-3 小時數據 | 容易 |
| Head Block | 丟失 2-3 小時數據 | 容易 |
| Checkpoint | 重啟較慢 | 容易 |
| Persistent Block | 丟失該 Block 時間範圍數據 | 困難 |






