Skip to main content

VictoriaMetrics 架構介紹

VictoriaMetrics 是從頭設計的 TSDB,不是 Prometheus 的擴充層。 它相容 Prometheus API,但自己的 storage engine(MergeTree 類似 ClickHouse)讓它在 RAM 和 CPU 效率上遠勝 Prometheus。


Single vs Cluster

VictoriaMetrics 有兩種部署形式:

Single(單節點)Cluster(叢集)
部署方式單一 binaryvminsert + vmselect + vmstorage 分離
水平擴展✅(各元件獨立擴展)
HA✅(replicationFactor)
適用場景單 Region、<1M series多 Region、>1M series、需 HA
適用場景說明各 Region 的本地 scraper(可用 VMAgent 替代)Central TSDB(選用)

Cluster 模式三元件

vminsert(寫入層,stateless)

職責:

  • 接收 Prometheus remote_write(HTTP,Influx line protocol 也支援)
  • 根據 consistent hashing 把資料分配給各 vmstorage 節點
  • 無狀態 — 任意重啟,任意擴展,不存資料
Prometheus ──remote_write──▶ vminsert-0
vminsert-1 ← HA,任一掛掉另一個繼續

consistent hash(按 metric name + labels)
│ │ │
vmstorage-0 vmstorage-1 vmstorage-2

vmstorage(儲存層,stateful)

職責:

  • 把時間序列資料存到本地磁碟(EBS gp3)
  • 接收 vminsert 的寫入請求
  • 回應 vmselect 的讀取請求
vmstorage-0: EBS gp3 (/vm-data/)
├── data/
│ ├── big/ ← 壓縮後的大 parts(類似 Thanos 的 S3 blocks)
│ └── small/ ← 最近寫入的小 parts(待合併)
└── indexdb/ ← 反向索引(metric name → series ID)

replicationFactor=2 的意思: 每筆資料寫到 2 個 vmstorage 節點。3 個節點時:

  • 正常:資料在 node-0 和 node-1(或任意 2 個)
  • node-0 掛掉:資料在 node-1 和 node-2,查詢正常
  • node-0 和 node-1 同時掛掉:只剩 node-2,資料不完整(但不會全失)

vmselect(查詢層,stateless)

職責:

  • 接收 Grafana 的 PromQL 查詢
  • 向所有 vmstorage 節點 fan-out 查詢(因為資料分散在各節點)
  • 合併結果、去重(replication 造成的重複),回傳給 Grafana
  • 有本地查詢快取(cacheMountPath
Grafana ──PromQL──▶ vmselect-0
vmselect-1 ← HA

fan-out 到所有 vmstorage 節點
│ │ │
vmstorage-0 vmstorage-1 vmstorage-2
│ │ │
└──────── 合併 + 去重 ─────────┘

回傳給 Grafana

完整資料流

寫入路徑(Write Path)

Region(每個):
Prometheus ──15s scrape──▶ local targets (pods)

└── remote_write (HTTPS, batch)

vmauth (TLS termination + bearer token 驗證)

vminsert × 2 (round-robin HA)

consistent hash sharding
┌────┴────┬────────┐
vmstorage-0 vmstorage-1 vmstorage-2
(replicationFactor=2: 每筆資料寫 2 個節點)

查詢路徑(Query Path)

Grafana ──HTTP GET /api/v1/query_range──▶ vmauth (bearer token 驗證)

vmselect × 2

fan-out to all vmstorage
│ │ │
vmstorage-0 vmstorage-1 vmstorage-2
│ │ │
└─── merge + deduplicate ───┘

Grafana panel 顯示

Alert 路徑

vmalert ──PromQL (定期 eval)──▶ vmselect ──▶ vmstorage

└── 觸發時 ──▶ Alertmanager ──▶ Slack / PagerDuty

vmauth — 認證路由層

vmauth 是 VictoriaMetrics 生態裡的 authenticated reverse proxy,負責:

  • TLS 終止(Prometheus ─HTTPS─▶ vmauth ─HTTP─▶ vminsert/vmselect)
  • Bearer token 驗證(每個 Region 一個獨立 token)
  • 路由規則:寫入走 vminsert,讀取走 vmselect
# VMUser CRD(每個 Region 一個)
# ⚠️ bearerToken inline 只適合從 Secrets Manager apply-time 讀取後注入
# 實際部署:token 由 Terraform 從 Secrets Manager 讀取,在 apply 時填入
# 不應手動把明文 token 寫在 YAML 檔裡
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMUser
metadata:
name: vmagent-region-sg
spec:
bearerToken: "<由 Terraform 從 Secrets Manager 注入>"
targetRefs:
- crd:
kind: VMCluster/vminsert
name: vmcluster-central
paths:
- "/insert/0/prometheus/.*" # 只允許寫入,不允許讀取

# Grafana 用的 VMUser(read-only)
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMUser
metadata:
name: grafana-reader
spec:
bearerToken: "<由 Terraform 從 Secrets Manager 注入>"
targetRefs:
- crd:
kind: VMCluster/vmselect
name: vmcluster-central
paths:
- "/select/0/prometheus/.*" # 只允許讀取

安全設計:

  • 各 Region token 相互隔離,一個 token 洩漏只影響那個 Region 的寫入
  • Token 來源:AWS Secrets Manager → Terraform data source → apply-time inline 注入 VMUser CRD
  • 不存在 K8s Secret(VM Operator v0.68.4 要求 inline bearerToken,非 bearerTokenSecret ref)
  • Write token 只能 /insert/...;Read token 只能 /select/...

VMAgent — Prometheus 的輕量替代

在各 Region,可以用 VMAgent 替換 Prometheus(或搭配 Prometheus 一起跑)。

PrometheusVMAgent
功能Scrape + TSDB + Query + Alert只做 Scrape + remote_write
RAM(1.6M series,SG)需 4-8Gi(現在 1Gi OOM 邊緣)~500Mi-1Gi
Config 格式scrape_configs:完全相同 — drop-in
Persistent queueWAL(2h 預設)可設定磁碟 queue,更長
CPU較高3-5x 較低

VMAgent 的職責:scrape targets,把資料用 remote_write 推到中央 VMCluster,自己不存。

各 Region(VMAgent 模式):
VMAgent ──scrape──▶ pods/nodes

└── remote_write(有持久化 queue,網路中斷不丟資料)

vmauth ──▶ vminsert ──▶ vmstorage

IaC 部署(VictoriaMetrics Operator)

我們用 Kubernetes Operator 管理 VMCluster,不直接操作 pod。

# VMCluster CRD — Operator 把它變成 vminsert×2、vmstorage×3、vmselect×2
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMCluster
metadata:
name: vmcluster-central
namespace: monitoring
spec:
retentionPeriod: "90d"
replicationFactor: 2

vmstorage:
replicaCount: 3
storage:
volumeClaimTemplate:
spec:
storageClassName: gp3
resources:
requests:
storage: 500Gi # 每個節點 500Gi EBS
resources:
requests:
memory: "8Gi"
cpu: "2"
limits:
memory: "16Gi"
cpu: "4"

vminsert:
replicaCount: 2
resources:
requests:
memory: "1Gi"
cpu: "1"

vmselect:
replicaCount: 2
resources:
requests:
memory: "4Gi"
cpu: "2"

Operator 監聽這個 CRD,自動建立對應的 Deployment、Service、PVC,並在 spec 改變時自動 rolling update。


vmalert — Alert 規則引擎

vmalert 是 VictoriaMetrics 生態的 alert 引擎,功能等同 Prometheus 的 built-in alerting,但獨立部署。

為什麼不用 Grafana Unified Alerting(GUA):

  • GUA 內建的 Alertmanager 無法被外部系統(如 vmalert)呼叫來路由告警 — GUA 只處理 Grafana 自己觸發的 alert
  • Standalone Alertmanager 支援 inhibit_rules(一個 critical 可抑制同 region 的所有 warning),GUA 不支援此功能
  • vmalert rule 格式與 Prometheus rule 格式 100% 相同 — 無遷移成本
  • Alert rule 以 YAML 存在 git — 滿足 IaC 要求
# vmalert rule 範例(格式與 Prometheus 完全相同)
groups:
- name: example.rules
rules:
- alert: HighErrorRate
expr: |
sum(rate(api_request_total{namespace="<your-namespace>",code=~"5.."}[5m]))
/ sum(rate(api_request_total{namespace="<your-namespace>"}[5m])) > 0.05
for: 5m
labels:
severity: warning
region: "{{ $labels.region }}"
annotations:
summary: "High error rate in {{ $labels.region }}"

MetricsQL 擴充

VictoriaMetrics 的查詢語言是 MetricsQL,100% 相容 PromQL,並額外支援:

擴充函數功能
with (...)定義共用的 label filter,避免重複
default operatormetric_a default metric_b — a 無值時用 b
keep_last_value()填補資料缺口(Prometheus 沒有)
any()group by 更靈活的聚合
top_k(k, expr)直接取前 k 個 series

注意: MetricsQL 的少數函數行為與 PromQL 不同(如 histogram_quantile 的邊界處理)。在從 Prometheus 遷移時,複雜的 alert rule 需要在 VMUI 驗證結果是否符合預期。