VictoriaMetrics 1.146.0 源码【左扬精讲】------ 开篇总览
这是 VictoriaMetrics 深度技术系列的开篇索引文章。
如果你正在寻找一个高性能、节省资源的时序数据库(TSDB)解决方案?
如果你想知道 Prometheus 的 **"增强版"**到底强在哪里?
如果你渴望深入理解 MergeSet 存储引擎、LSM-less 设计、7x RAM 节省背后的工程原理 ------ 那么这个系列将带你从源码层面彻底读懂 VictoriaMetrics。
本系列基于 VictoriaMetrics v1.146.0 LTS 版本(Long-Term Support),共规划 200 篇正文 + 10 篇附录,覆盖架构设计、组件原理、存储引擎、查询引擎、工具链、运维实践、排障调优等 14 个维度。每一篇都从源码出发,兼顾理论深度和实战落地。
VictoriaMetrics 时序数据库 Prometheus MergeSet 云原生监控 Go 存储引擎 v1.146.0 LTS
学习重点提示
系列核心价值(必须掌握)
- 架构设计哲学:理解 VM 为什么能做到比 Prometheus 省 7x RAM(MergeSet vs TSDB、LSM-less 设计)
- 存储引擎原理:MergeSet 只合并不分层的 LSM-less 设计,commonPrefix 压缩,NearestDelta 编码
- 完整组件体系:vminsert/vmselect/vmstorage 三层架构,12 种协议接入,Cluster 模式
- 性能优化方法论:TSIDCache 37% 策略、blockCache 三层设计、rawItemsShards 分片
系列扩展知识(了解即可)
- VictoriaLogs 日志一体化监控
- Enterprise vs OpenSource 功能差异
- vmagent/vmalert/vmauth/vmbackup 工具链
- 与其他 TSDB(InfluxDB/Thanos/Mimir)的对比
文章目录
- [一、VictoriaMetrics 是什么?为什么它是 Prometheus 的"超级增强版"?](#一、VictoriaMetrics 是什么?为什么它是 Prometheus 的"超级增强版"?)
- [二、200 篇系列全景导航:14 个维度速览](#二、200 篇系列全景导航:14 个维度速览)
- [三、组件体系全貌:从 HTTP 入口到 Part 文件的全链路](#三、组件体系全貌:从 HTTP 入口到 Part 文件的全链路)
- [四、核心性能优势:为什么 VM 能做到省 7x RAM?](#四、核心性能优势:为什么 VM 能做到省 7x RAM?)
- [五、典型应用场景:谁在使用 VictoriaMetrics?](#五、典型应用场景:谁在使用 VictoriaMetrics?)
- 六、学习路线图:如何高效阅读这个系列
- 七、FAQ:常见疑问
- 八、Roadmap:后续预告
一、VictoriaMetrics 是什么?为什么它是 Prometheus 的"超级增强版"?
思考记忆提示 --- 本节是系列的"入口"------弄清楚 VM 是什么、解决了什么问题,才能理解后面每篇的定位
- VictoriaMetrics 是一个高性能、低资源占用的时序数据库,兼容 Prometheus 生态
- 核心优势:比 Prometheus 省 7x RAM、支持集群模式、无限 cardinality、长期存储
- 面试高频提问:VictoriaMetrics 和 Prometheus 的区别是什么?什么时候选择 VM 而不是 Prometheus?
VictoriaMetrics(简称 VM)是一个开源的时序数据库(Time Series Database, TSDB),专门为云原生监控场景设计。它与 Prometheus 完全兼容,支持 Prometheus remote_write 协议、Grafana 数据源、以及 PromQL 查询语言。但 VM 的野心不止于"兼容"------它要做的是在保持兼容性的同时,大幅超越 Prometheus 的性能和资源效率。
我的理解的意思是说
可以把 VictoriaMetrics 想象成一个超级版 Prometheus:
- Prometheus 是单机版数据库------数据存在本地,不能水平扩展,内存受限于单机
- VictoriaMetrics 是分布式版 Prometheus------支持集群模式,可以横向扩展,同时内存占用还更少
- 类比:如果 Prometheus 是"一台服务器",VictoriaMetrics 就是"一个服务器集群",但消耗的电力(资源)反而更少
VictoriaMetrics 由 Aliaksandr Valialkin 于 2019 年创建,最初是为了解决 Promscale(InfluxDB on PostgreSQL)的性能和存储成本问题。经过多年发展,VM 已经成为 CNCF 生态中最受欢迎的时序数据库之一,GitHub 超过 17.2k stars,被 Spotify、Roblox、Grammarly、DoorDash 等知名公司采用。
1.1 VictoriaMetrics 的四大核心优势
为什么选择 VictoriaMetrics 而不是 Prometheus 原生?以下四个优势是 VM 脱颖而出的关键:
设计精髓
VictoriaMetrics 的设计哲学是:在不牺牲兼容性的前提下,用更少的资源做更多的事。这体现在四个维度:存储效率(MergeSet 压缩)、内存效率(LSM-less + 缓存策略)、查询性能(并行 k-way 归并)、扩展性(Cluster 模式)。
| 维度 | Prometheus | VictoriaMetrics | 提升幅度 |
|---|---|---|---|
| RAM 占用 | 全量数据常驻内存 | TSIDCache 37% + blockCache 分层 | 省 7x |
| 水平扩展 | 不支持(单机) | Cluster 模式支持 | 无限扩展 |
| 长期存储 | 需要 Thanos/Mimir | 内置 retention | 原生支持 |
| Cardinality | 有限制 | BloomFilter 动态调整 | 更高上限 |
1.2 与 Prometheus 的关系:不是替代,是增强
理解 VictoriaMetrics 和 Prometheus 的关系非常重要:VM 不是要替代 Prometheus,而是要解决 Prometheus 的局限性 。Prometheus 仍然是一个优秀的抓取和告警工具,但它的本地存储不适合大规模长期存储。VictoriaMetrics 提供了两种集成方式:
- 方式一:Prometheus 远程写入 VM (推荐)
Prometheus 继续负责抓取和告警评估,数据通过 remote_write 协议写入 VictoriaMetrics。VM 作为长期存储和高效查询的后端。 - 方式二:vmagent 替代 Prometheus
使用 vmagent(VM 原生的轻量级抓取代理)替代 Prometheus,负责抓取和远程写入。
注意
VictoriaMetrics 不是 Prometheus 的 fork,而是一个完全独立的实现。VM 使用了完全不同的存储引擎(MergeSet vs Prometheus TSDB),但通过完整实现 Prometheus 的 API(/api/v1/*)和协议(remote_write)来实现兼容性。
必记闭环逻辑(核心考点)
VictoriaMetrics 是一个与 Prometheus 完全兼容的时序数据库,通过 MergeSet 存储引擎和 LSM-less 设计实现比 Prometheus 省 7x RAM,同时支持 Cluster 模式无限水平扩展。它不是 Prometheus 的替代品,而是 Prometheus 的"超级增强版后端"。
二、200 篇系列全景导航:14 个维度速览
思考记忆提示 --- 本节是系列的"地图"------快速定位你需要的文章,避免迷失在 200 篇的海洋里
- 系列按 14 个维度组织,总计 200 篇正文 + 10 篇附录
- 每个维度有明确的定位:理论深度 vs 实战落地
- 面试高频提问:这个系列覆盖了 VM 的哪些方面?如何快速找到我需要的文章?
200 篇听起来很多,但通过 14 个维度的组织,每一篇都有清晰的定位。以下是每个维度的定位和推荐阅读顺序:
2.1 维度速览表
| 维度 | 篇数 | 定位 | 推荐阅读 |
|---|---|---|---|
| A. 架构设计篇 | 15 | 全局架构、设计哲学、组件关系 | #01-#15 必读(建立全局认知) |
| B. 组件深潜篇 | 25 | 按组件垂直深挖源码实现 | #16-#40(深入理解核心组件) |
| C. 存储引擎篇 | 15 | storage/mergeset/encoding/cache | #41-#55 核心(理解性能基础) |
| D. 查询引擎篇 | 15 | promql/metricsql/netstorage | #56-#70(查询优化必读) |
| E. 工具链篇 | 20 | vmagent/vmalert/vmauth/vmbackup | #71-#90(运维必备) |
| F. 集成生态篇 | 10 | Grafana/k8s/Prometheus Operator | #91-#100(快速上手) |
| G. 排障调优篇 | 15 | 慢查询/cardinality/OOM/写入瓶颈 | #101-#115 实操(问题诊断) |
| H. 进阶专题篇 | 15 | decimal/bytesutil/fastcache/fs | #116-#130(深入理解) |
| I. 运维实践篇 | 15 | 迁移/k8s 部署/容量规划 | #131-#145(生产环境) |
| J. 生产极限篇 | 15 | 10 亿 series/百万 samples-s | #146-#160(大规模场景) |
| K. 源码追踪篇 | 15 | 完整链路追踪:HTTP 到 Part 文件 | #161-#175 硬核(源码阅读) |
| L. VictoriaLogs 协同篇 | 10 | LogQL/指标日志关联 | #176-#185(一体化可观测性) |
| M. 压轴总结篇 | 15 | PromQL 深潜/性能极限/工程哲学 | #186-#200(收尾升华) |
| N. 附录篇 | 10 | 速查地图/API 端点/错误码 | A1-A10 工具书(日常参考) |
我的理解的意思是说
200 篇系列就像一本**《VictoriaMetrics 源代码专题研究》**:
- A 架构设计篇 = 书的"前言和概述",告诉你 VM 是什么、为什么设计成这样
- B 组件深潜 + C 存储引擎 = 书的"核心技术章节",深入每个组件的源码
- G 排障调优 + I 运维实践 = 书的"实战案例章节",告诉你怎么用
- K 源码追踪 = 书的"深入研究章节",完整追踪一条数据的旅程
- N 附录 = 书的"工具书部分",快速查阅 API、错误码等
建议先读 A 架构设计篇(建立全局认知),再按需深入其他章节。
2.2 推荐阅读路径
根据不同的学习目标,这里提供三条推荐阅读路径:
- 路径一:快速入门(5 篇,约 3 小时)
#01 设计哲学 → #02 全局架构 → #04 整体数据流 → #11 开源生态 → #12 源码阅读路线图 - 路径二:深度理解(20 篇,约 2 天)
完成路径一后,继续 #41 MergeSet vs LSM Tree → #51 压缩算法 → #54 TSIDCache → #64 并发控制 → #77-78 vmalert 架构 - 路径三:生产专家(50+ 篇,约 1 周)
完成路径二后,系统阅读 #101-#160 排障调优和运维实践,#161-#175 源码追踪
必记闭环逻辑(核心考点)
200 篇系列按 14 个维度组织,覆盖理论深度(A-M)和实战落地(G/I)。推荐从 A 架构设计篇开始(建立全局认知),按需深入组件原理(#16-#55)和源码追踪(#161-#175),附录(A1-A10)作为日常工具书参考。
三、组件体系全貌:从 HTTP 入口到 Part 文件的全链路
思考记忆提示 --- 本节是系列的"骨架"------理解组件体系,后续各篇才有上下文
- VM 分为三层:vminsert(写入)→ vmstorage(存储)→ vmselect(查询)
- Single-Node 模式三合一,Cluster 模式可分离部署
- 面试高频提问:VictoriaMetrics 的组件有哪些?Cluster 模式下各组件如何协作?
VictoriaMetrics 的组件体系非常清晰。无论你是使用 Single-Node 模式还是 Cluster 模式,理解这三级架构都是理解 VM 的基础。
3.1 三层架构概述
text
VictoriaMetrics 架构分层
│
├── [1] 应用层 (app/)
│ ├── vminsert --- 写入接入层(Prometheus/InfluxDB/DataDog/OTel 等 12+ 协议)
│ ├── vmselect --- 查询执行层(PromQL/MetricsQL/GraphiteQL + 查询调度)
│ └── vmstorage --- 数据存储层(Cluster 模式核心)
│
├── [2] 存储核心层 (lib/storage/)
│ ├── Storage --- 全局协调器:分区/缓存/基数限制
│ ├── Table --- 表级抽象:按月分区生命周期
│ ├── Partition --- 分区级抽象:In-Memory/Small/Big Parts + indexDB
│ └── indexDB --- 倒排索引引擎:8 种索引前缀
│
├── [3] MergeSet 存储引擎 (lib/mergeset/)
│ ├── Table --- 分片/合并调度/刷盘策略
│ ├── Part --- metaindex + index + items + lens 四文件
│ └── InmemoryPart --- 内存未排序 Part,1 秒刷新
│
└── [4] 压缩编码层 (lib/encoding/)
├── MarshalType --- 6 种压缩类型
└── NearestDelta 算法 --- Counter/Gauge 自适应差分编码 + ZSTD
3.2 Cluster 集群架构:核心重点
设计精髓
VictoriaMetrics Cluster 是生产环境的标准部署模式 :三层分离(vminsert/vmstorage/vmselect),每层都可以独立水平扩展。通过 -cluster.mode 开启,支持 accountID/projectID 多租户隔离,支撑 100 万到 10 亿级 series 规模。Single-Node 模式仅用于快速验证和小型场景,集群模式才是 VM 的"主战场"。
以下是 VictoriaMetrics Cluster 的典型架构图(生产环境标准部署):
| 特性 | Single-Node | Cluster |
|---|---|---|
| 进程数 | 1 个进程 | 3 种角色:vminsert、vmstorage、vmselect |
| 扩展方式 | 垂直扩展(加 CPU/内存/磁盘) | 水平扩展(增加 vmstorage/vmselect 节点) |
| 适用规模 | < 100 万 series | 100 万 ~ 10 亿 series |
| 推荐场景 | 本地开发、测试、小型监控 | 生产环境、中大型监控平台 |
小贴士
Single-Node 模式用一行命令即可启动,非常适合本地验证和测试。但生产环境必须使用 Cluster 模式------因为单机无法水平扩展,也无法支撑多租户场景。
3.3 写入与查询全链路:vminsert → vmstorage → vmselect
VictoriaMetrics 的数据流分为写入链路 和查询链路两条完整路径。以下是详细的关键方法/函数追踪:
text
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ VictoriaMetrics 数据流全景图 │
│ (写入 ←→ 查询) │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ═══════════════════════════════════════════ 写 入 链 路 ═══════════════════════════════════════════ │
│ │
│ ┌─────────────┐ ┌─────────────────────────────────────────────────────┐ │
│ │ 数据来源 │ │ vminsert (写入接入层) │ │
│ │ (12+ 协议) │ │ app/vminsert/main.go │ │
│ └──────┬──────┘ │ │ │
│ │ │ RequestHandler() ─── HTTP 路由分发 │ │
│ │ │ │ │ │
│ ▼ │ ├── /api/v1/write ──► promremotewrite.InsertHandler() │
│ ┌─────────────┐ │ │ │ │ │
│ │ Prometheus │────► /api/v1/write │ ├── /influx/write ──► influx.InsertHandlerForHTTP() │
│ │ (remote_ │ │ │ │ │ │
│ │ write) │ │ ├── /datadog/api/v1/series ──► datadogv1.InsertHandlerForHTTP() │
│ └─────────────┘ │ │ │ │ │
│ ┌─────────────┐ │ ├── /datadog/api/v2/series ──► datadogv2.InsertHandlerForHTTP() │
│ │ InfluxDB │────► /influx/write │ │ │ │ │
│ │ (line │ │ ├── /opentelemetry/v1/metrics ──► opentelemetry.InsertHandler() │
│ │ protocol) │ │ │ │ │ │
│ └─────────────┘ │ ├── /api/v1/import ──► vmimport.InsertHandler() │
│ ┌─────────────┐ │ │ │ │ │
│ │ DataDog │────► /datadog/api/v1/series │ └── /zabbixconnector ──► zabbixconnector.InsertHandlerForHTTP() │
│ └─────────────┘ │ │ │ │
│ ┌─────────────┐ │ ▼ │ │
│ │ OpenTelemetry│────► /opentelemetry/v1/... │ ┌─────────────────────────────────────┐ │ │
│ └─────────────┘ │ │ lib/storage/storage.go │ │ │
│ ┌─────────────┐ │ │ │ │ │
│ │ Graphite │────► :2003 TCP/UDP │ │ Storage.AddRows() │ │ │
│ └─────────────┘ │ │ │ │ │ │
│ │ │ ├── TSIDCache 37% 查询/创建 │ │ │
│ │ │ │ (metricName → TSID) │ │ │
│ │ │ │ │ │ │
│ │ │ └── rawItemsShards.Cell.AddRow() │ │ │
│ │ │ │ (按 CPU 分片并行) │ │ │
│ │ └─────────────┬───────────────────────────┘ │ │
│ │ │ │ │
│ └──────────────────────────┼────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ vmstorage (存储层) │ │
│ │ lib/storage/ │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ InMemoryPart (内存缓冲区) │ │ │
│ │ │ • 每 1 秒刷新到磁盘 │ │ │
│ │ │ • rawItemsShards 合并 │ │ │
│ │ │ • 转换为 Small Part │ │ │
│ │ └───────────────────────┬───────────────────────┘ │ │
│ │ │ (1秒刷盘) │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ Part 文件 (四文件结构) │ │ │
│ │ │ • metaindex.bin (元数据索引) │ │ │
│ │ │ • index.bin (倒排索引) │ │ │
│ │ │ • items.bin (数据块) │ │ │
│ │ │ • lens.bin (块长度) │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ═══════════════════════════════════════════ 查 询 链 路 ═══════════════════════════════════════════ │
│ │
│ ┌─────────────┐ ┌─────────────────────────────────────────────────────┐ │
│ │ 查询客户端 │ │ vmselect (查询层) │ │
│ │ │ │ app/vmselect/main.go │ │
│ │ • Grafana │ │ │ │
│ │ • PromQL │ │ RequestHandler() ─── HTTP 路由分发 │ │
│ │ • API │ │ │ │ │
│ └──────┬──────┘ │ ├── /api/v1/query ──► prometheus.QueryHandler() │
│ │ │ │ │ (即时查询 /promQL eval) │ │
│ │ │ │ ▼ │ │
│ │ │ ├── /api/v1/query_range ──► prometheus.QueryRangeHandler() │
│ │ │ │ │ (范围查询) │ │
│ │ │ │ ▼ │ │
│ ▼ │ ├── /api/v1/series ──► prometheus.SeriesHandler() │
│ ┌─────────────┐ │ │ │ (获取序列列表) │ │
│ │ /api/v1/ │ │ │ ▼ │ │
│ │ query │────► 即时查询 │ ├── /api/v1/labels ──► prometheus.LabelsHandler() │
│ │ │ │ │ │ (获取标签列表) │ │
│ │ 场景: │ │ │ ▼ │ │
│ │ PromQL │ │ ├── /api/v1/label/{name}/values ──► prometheus.LabelValuesHandler() │
│ │ 即时求值 │ │ │ │ (获取标签值) │ │
│ └─────────────┘ │ │ ▼ │ │
│ ┌─────────────┐ │ ├── /api/v1/export ──► prometheus.ExportHandler() │
│ │ /api/v1/ │ │ │ │ (导出原始数据) │ │
│ │ query_range │────► 范围查询 │ │ ▼ │ │
│ │ │ │ ├── /render ──► graphite.RenderHandler() │
│ │ 场景: │ │ │ │ (Graphite Render API) │ │
│ │ 仪表盘 │ │ │ ▼ │ │
│ │ 时间范围 │ │ └── /vmui/* ──► vmui 文件服务 │
│ └─────────────┘ │ │ (Web UI) │
│ ┌─────────────┐ │ ▼ │
│ │ /api/v1/ │ │ ┌─────────────────────────────────────────────────────┐ │
│ │ series │────► 系列查询 │ │ lib/promql/ │ │
│ │ │ │ │ │ │
│ │ 场景: │ │ │ PromQL.Parse() ──── PromQL 语法解析 │ │
│ │ 查找指标 │ │ │ │ │ │
│ └─────────────┘ │ │ ▼ │ │
│ ┌─────────────┐ │ │ PromQL.Exec() ──── 查询执行 │ │
│ │ /api/v1/ │ │ │ │ │ │
│ │ labels │────► 标签查询 │ │ ├── 索引查询 (indexDB.Search) │ │
│ └─────────────┘ │ │ │ │ (根据 Tag 找 TSID) │ │
│ │ │ │ ▼ │ │
│ │ │ ├── 数据获取 (netstorage.Search) │ │
│ │ │ │ │ (从 Parts 读取数据块) │ │
│ │ │ │ ▼ │ │
│ │ │ └── k-way Merge ──── 并行归并排序 │ │
│ │ │ │ │
│ │ │ app/vmselect/netstorage/ │ │
│ │ │ • netstorage.Search() ── 查询入口 │ │
│ │ │ • netstorage.SearchTagKeys() ── Tag Key 查询 │ │
│ │ │ • netstorage.SearchTagValues() ── Tag Value 查询 │ │
│ │ └─────────────────────────────────────────────────────┘ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
我的理解的意思是说
数据流可以想象成现代化物流分拣中心(以集群模式为例):
- vminsert = 前台接待 + 分拣台 :多个 vminsert 节点接收各种格式的"快递"(Prometheus/InfluxDB/DataDog),按 CPU 核心分到不同的分拣台(rawItemsShards)。集群模式下可水平扩展
- vmstorage = 仓库管理 :多个 vmstorage 节点各自管理数据分片(Shard)。InMemoryPart 是"临时货架"(每 1 秒打包),Part 是"正式货架"(四文件结构)。数据分片,分布式存储
- vmselect = 取货员 :多个 vmselect 节点并行工作。Grafana/PromQL 发出"取货单"(查询请求),取货员先查索引(在哪),再从多个货架并行取货,最后归并排序返回。查询并行,结果归并
- 负载均衡器(LB) :在 vminsert 和 vmselect 前端,通常部署 Nginx/vmauth 做流量分发。统一入口,透明扩容
关键设计点:
- 写入:CPU 分片并行(rawItemsShards)+ 节点级扩展(多 vminsert)
- 存储:数据分片(按 metric 路由到不同 vmstorage)+ 副本/一致性
- 查询:k-way 归并(多个 Part 并行读取后归并)+ 节点级扩展(多 vmselect)
设计精髓:为什么这样分层?
VictoriaMetrics 的三层架构(vminsert/vmstorage/vmselect)设计有以下考量:
- 协议解耦:vminsert 负责适配 12+ 种协议,统一转换为内部格式
- 存储抽象:vmstorage 屏蔽了 MergeSet 存储引擎的复杂性,对上提供统一接口
- 查询优化:vmselect 独立出来后可以单独扩展,应对查询密集型场景
- Cluster 支持:三层分离后可以独立扩缩容,Cluster 模式下分别部署
必记闭环逻辑(核心考点)
VictoriaMetrics 的三层架构(vminsert/vmstorage/vmselect)可以分离部署(Cluster 模式)也可以合一(Single-Node 模式)。写入链路 :HTTP → RequestHandler() 路由 → 各协议 InsertHandler() → Storage.AddRows() → rawItemsShards 分片 → InMemoryPart 1秒刷盘 → Part 四文件。查询链路:HTTP → QueryHandler() → PromQL.Parse() 解析 → indexDB.Search() 索引查询 → netstorage.Search() 数据获取 → k-way Merge 归并排序。
四、核心性能优势:为什么 VM 能做到省 7x RAM?
思考记忆提示 --- 本节是系列的"亮点"------理解 VM 的核心优势,为后续深入理解存储引擎做铺垫
- 省 RAM 的三个关键设计:MergeSet(LSM-less)+ TSIDCache 37% + blockCache 分层
- 这些设计是相互配合的,不是孤立的优化
- 面试高频提问:VictoriaMetrics 为什么能比 Prometheus 省这么多内存?TSIDCache 37% 是怎么来的?
"比 Prometheus 省 7x RAM"是 VictoriaMetrics 最广为人知的优势。但这不是单一优化点,而是多个设计决策协同工作的结果。
4.1 三大核心设计
设计精髓
VictoriaMetrics 省 RAM 的核心哲学是:数据按需加载,而非全量常驻。Prometheus 把所有数据块加载到内存(mmap),而 VM 只把热点数据(通过 TSIDCache 和 blockCache)保留在内存,冷数据放在磁盘按需读取。这是典型的"内存-磁盘分层"设计,比 Prometheus 的"内存优先"更节省资源。
设计一:MergeSet vs LSM Tree(LSM-less 设计)
传统的 LSM Tree(如 RocksDB)采用分层合并 策略:L0 → L1 → L2 → ... 每层大小呈指数增长,合并时需要同时读取多层数据,内存压力大。VictoriaMetrics 的 MergeSet 采用了只合并不分层的 LSM-less 设计:
- 新数据先写入内存(InMemoryPart,每 1 秒刷新到磁盘成为 Small Part)
- 多个 Small Part 合并成 Big Part(但不会合并到更大的层)
- 查询时只需读取最新的 Big Part + 最近的 Small Part,不需要遍历所有层级
设计二:TSIDCache 37% 策略
VictoriaMetrics 把 -memory.allowedDataPointers 的 37% 用于 TSIDCache。TSIDCache 是 metricName → TSID 的映射缓存:
- 写入时:先查 TSIDCache,有则直接用,无则创建新 TSID
- 查询时:根据 metricName 查 TSIDCache,快速定位时间序列
- 37% 是一个经验值:经过大量测试发现这个比例能最大化缓存命中率
设计三:blockCache 三层设计
blockCache 分为三层,每层缓存不同类型的数据:
| 层级 | 缓存内容 | 内存占比 |
|---|---|---|
| ibCache | 数据块内容(items.bin) | 25% |
| idxbCache | 索引块内容(index.bin) | 10% |
| ibSparseCache | ibCache 的稀疏访问优化 | 5% |
4.2 与 Prometheus TSDB 的对比
注意
Prometheus 的内存占用主要来自两个方面:(1) 索引块(Index)全量 mmap 到内存;(2) 数据块(Chunks)按时间窗口预加载。而 VictoriaMetrics 通过 TSIDCache 只缓存热点索引,通过 blockCache 只缓存热点数据块,显著降低了内存占用。
| 对比维度 | Prometheus TSDB | VictoriaMetrics MergeSet |
|---|---|---|
| 索引存储 | Index 段文件全量 mmap | 倒排索引 + TSIDCache 热缓存 |
| 数据存储 | Chunks 按时间窗口预加载 | Parts 按需加载到 blockCache |
| 内存策略 | 内存优先,尽量放内存 | 分层缓存,热数据在内存 |
| 磁盘空间 | 标准压缩 | commonPrefix + NearestDelta + ZSTD |
我的理解的意思是说
两种内存策略可以类比为图书馆管理:
- Prometheus = 把整本书放在桌上:一本书(一个时间序列)要么全在内存,要么不在。书桌上的书越来越多,内存就满了。
- VictoriaMetrics = 图书馆借阅系统:只有正在看的书(热点数据)在桌上,其他书在书架上(磁盘)。书架上有很多书(TSIDCache 的索引),但桌子只需要放当前在看的章节(blockCache 的数据块)。
TSIDCache 37% 就像是"书的目录卡片抽屉"------虽然书不在桌上,但根据卡片(metricName → TSID)可以快速找到书在哪。
必记闭环逻辑(核心考点)
VictoriaMetrics 省 7x RAM 来自三大设计的协同:(1) MergeSet LSM-less 只合并不分层,减少遍历开销;(2) TSIDCache 37% 策略优先缓存 metricName → TSID 映射;(3) blockCache 三层(ibCache 25% + idxbCache 10% + ibSparseCache 5%)按需缓存数据块。
五、典型应用场景:谁在使用 VictoriaMetrics?
思考记忆提示 --- 本节帮助你理解 VM 的适用场景,避免"锤子思维"------把所有问题都当作钉子
- VM 适合:大规模长期监控、多租户环境、Grafana 集成
- VM 不适合:超低延迟交易系统、需要强事务的场景
- 面试高频提问:什么场景适合用 VictoriaMetrics?它和 InfluxDB/Thanos 怎么选?
VictoriaMetrics 已经在生产环境中被多家知名公司使用。以下是典型的应用场景:
5.1 适用场景
- 大规模 Prometheus 长期存储:当 Prometheus 的本地存储无法满足长期数据保留需求时,VM 作为 remote_write 后端提供无限存储。
- 高 Cardinality 环境:如 Kubernetes 监控、Service Mesh 可观测性,标签值众多导致 Prometheus OOM,VM 通过 BloomFilter 动态调整基数限制。
- 多租户监控平台:通过 accountID/projectID 实现资源隔离,适合 SaaS 或内部监控平台。
- Grafana 集成:原生支持 Prometheus 数据源,Grafana 用户零成本迁移。
5.2 知名用户案例
| 公司 | 使用规模 | 使用场景 |
|---|---|---|
| Spotify | 数十亿 series | 音频流媒体基础设施监控 |
| Roblox | 数百万 series | 游戏平台实时监控 |
| Grammarly | 中等规模 | 写作工具基础设施监控 |
| DoorDash | 大规模 | 外卖平台配送监控 |
小贴士
如果你正在使用 Prometheus + Thanos/Mimir,并且遇到了扩展性或成本问题,VictoriaMetrics 是一个值得评估的替代方案。VM 的存储效率通常比 Thanos + Prometheus 高 5-10 倍。
必记闭环逻辑(核心考点)
VictoriaMetrics 的最佳场景是大规模 Prometheus 长期存储(> 100 万 series)、高 Cardinality 环境和多租户监控平台。它不适合需要强事务或超低延迟的交易系统。Spotify、Roblox、Grammarly、DoorDash 等公司已在生产环境验证了 VM 的能力。
六、学习路线图:如何高效阅读这个系列
思考记忆提示 --- 本节提供学习路径建议,帮助你高效利用这个系列
- 建议从 **A 架构设计篇(#01-#15)**开始,建立全局认知
- 按需深入 C 存储引擎篇(#41-#55),理解性能基础
- 面试高频提问:如何快速理解 VictoriaMetrics?如何阅读它的源码?
200 篇系列内容很多,如何高效学习?以下是推荐的学习路径:
6.1 第一阶段:建立全局认知(#01-#15,约 1 周)
这一阶段的目标是理解 VictoriaMetrics 是什么、整体架构是怎样的、为什么能省 7x RAM。重点文章:
- #01 设计哲学:理解 VM 的核心优势来源
- #02 全局架构:Single-Node vs Cluster 模式
- #04 整体数据流:数据从写入到存储的全链路
- #05 版本演进:了解 1.146.0 LTS 的重大变化
- #09 性能模型:理解性能常数的来源
6.2 第二阶段:深入核心原理(#41-#70,约 2 周)
这一阶段的目标是理解 MergeSet 存储引擎和查询引擎的内部原理。重点文章:
- #41 MergeSet vs LSM Tree:理解 VM 的核心存储设计
- #47 commonPrefix 压缩:存储空间减少 30-50% 的原理
- #51 6 种压缩算法:NearestDelta 是核心
- #56 PromQL 执行引擎:查询如何执行
- #77-78 vmalert 架构:告警评估的完整链路
6.3 第三阶段:实战运维能力(#101-#145,约 2 周)
这一阶段的目标是具备生产环境的故障诊断和运维能力。重点文章:
- #104 Cardinality 爆炸:最常见的 OOM 原因
- #105 slow query 诊断:querytracer 使用
- #107 内存调优:memory.Allowed() 计算
- #131 从 Prometheus 迁移:vmctl 使用
- #135 容量规划:硬件选型参考
6.4 第四阶段:源码追踪(#161-#175,约 2 周)
这一阶段的目标是具备独立阅读和理解源码的能力。重点文章:
- #161 HTTP 到 Part 文件:完整写入链路追踪
- #162 PromQL 到结果:完整查询链路追踪
- #163 Part 四文件结构:二进制格式详解
- #165 indexDB 8 种索引前缀:Tag 查询完整路径
- #170 TSIDCache 37% 计算:内存分配逻辑
我的理解的意思是说
学习 VictoriaMetrics 就像学习一门武功:
- 第一阶段(#01-#15) = 看武功秘籍的"总纲",了解整套武功的框架和精髓
- 第二阶段(#41-#70) = 修炼"内功心法"(存储引擎)和"招式"(查询引擎)
- 第三阶段(#101-#145) = 下山历练,解决实际问题
- 第四阶段(#161-#175) = 回山闭关,亲手推导武功秘籍
不要跳阶段!没有全局认知,直接看源码会迷失;没有实战经验,直接追踪源码会缺乏上下文。
必记闭环逻辑(核心考点)
高效学习路径:先用 A 架构设计篇建立全局认知(#01-#15),再用 C 存储引擎篇理解性能基础(#41-#55),接着通过 G/I 排障调优和运维实践培养实战能力(#101-#145),最后用 K 源码追踪深入理解内部原理(#161-#175)。
七、FAQ:常见疑问
思考记忆提示 --- FAQ 是全系列的"临考前速背"模块,覆盖最常见的问题
- Q1-Q4 围绕基础认知:VM 是什么、和 Prometheus 的关系
- Q5-Q10 围绕架构设计:Cluster 模式、多租户、存储引擎
- Q11-Q15 围绕性能优化:内存调优、查询优化、cardinality
- Q16-Q20 围绕运维实践:部署、迁移、监控
Q1. VictoriaMetrics 和 Prometheus 是什么关系?
**VM 是 Prometheus 的长期存储后端,不是替代品。**Prometheus 仍然负责抓取(scraping)和告警评估(alerting),数据通过 remote_write 协议写入 VictoriaMetrics。VM 提供了比 Prometheus 原生存储更高的扩展性和更低的资源占用。
Q2. 为什么 VictoriaMetrics 能比 Prometheus 省 7x RAM?
**来自三大设计的协同:MergeSet LSM-less + TSIDCache 37% + blockCache 三层。**Prometheus 把所有索引和数据块 mmap 到内存,而 VM 只把热点数据(TSIDCache + blockCache)保留在内存,冷数据放在磁盘按需读取。
Q3. Single-Node 和 Cluster 模式有什么区别?什么时候用哪个?
**生产用 Cluster(支撑 100 万~10 亿 series),Single-Node 仅用于快速验证。**Single-Node 是单进程,部署简单;Cluster 模式把 vminsert/vmstorage/vmselect 分离部署,支持水平扩展和多租户。
Q4. VictoriaMetrics 支持多租户吗?
**Cluster 模式原生支持多租户,通过 accountID/projectID 实现隔离。**每个租户的数据在存储层完全隔离,适合 SaaS 或内部多业务线监控平台。
Q5. MergeSet 和 LSM Tree 有什么区别?
**MergeSet 采用 LSM-less 设计:只合并不分层。**LSM Tree(如 RocksDB)有 L0→L1→L2→... 多层合并,开销大;MergeSet 只有 Small Parts 和 Big Parts 两类,查询时只需读最新的 Big Part + 最近的 Small Parts。
Q6. 什么是 commonPrefix 压缩?为什么能节省 30-50% 空间?
commonPrefix 压缩利用标签值的共同前缀来减少存储。 例如:metric{job="prometheus",instance="localhost:9090"} 和 metric{job="prometheus",instance="localhost:9091"} 共享 metric{job="prometheus",instance="localhost:909"} 前缀,只需存储一次。
Q7. TSIDCache 37% 是怎么来的?
**37% 是经验值,经过大量测试发现这个比例能最大化缓存命中率。**TSIDCache 缓存 metricName → TSID 映射,是写入和查询的关键路径。37% 的比例在 cache hit rate 和 memory usage 之间取得了最优平衡。
Q8. BloomFilter 在 VictoriaMetrics 中起什么作用?
**BloomFilter 用于基数限制(cardinality limiting),防止高 cardinality 数据打爆 VM。**每个小时和每天的 BloomFilter 会记录见过的 metricIDs,如果某小时 metricID 数量超过限制,会拒绝写入。
Q9. VictoriaMetrics 有 WAL(Write-Ahead Log)吗?
**没有!这是 VM 的设计选择。**Prometheus TSDB 使用 WAL 来保证崩溃恢复,但 WAL 会增加写入延迟。VM 通过 InMemoryPart 每秒刷盘的设计,在保证数据安全的同时避免了 WAL 的开销。
Q10. InMemoryPart 刷盘失败会丢数据吗?
**正常情况下不会丢数据。**InMemoryPart 在内存中维护多个副本,刷盘时会先写临时文件再原子重命名。如果进程崩溃,正在刷盘的数据可能丢失,但这是 Prometheus remote_write 协议允许的"最多一次"语义范围内。
Q11. Cardinality 爆炸的根本原因是什么?
高 cardinality 来自标签值组合过多。 例如:metric{job="foo",instance="ip-1"}、metric{job="foo",instance="ip-2"}... 每个 instance 都是一个唯一的 time series。如果有 1 万个 instance,就是 1 万个 series。
Q12. 如何诊断 slow query?
**使用 QueryTracer 分析查询各阶段耗时。**VM 的 QueryTracer 会在查询的每个阶段记录耗时:parse → plan → execution → merge。打开 debug 日志可以看到详细的阶段信息。
Q13. blockCache 三层(ibCache/idxbCache/ibSparseCache)分别缓存什么?
**ibCache 缓存数据块(items.bin),idxbCache 缓存索引块(index.bin),ibSparseCache 是 ibCache 的稀疏访问优化。**三者合计占用 memory.allowedDataPointers 的 40%。
Q14. 如何规划 VictoriaMetrics 的内存容量?
**内存规划公式:TSIDCache(37%) + blockCache(40%) + 工作内存(23%) ≈ memory.allowed。**对于 100 万 series,建议预留 4GB+ 内存;500 万 series 建议 16GB+;1000 万 series 建议 32GB+。
Q15. retention 设置后数据会立即删除吗?
**不会立即删除,数据会在后台慢慢清理。**VM 每小时检查一次是否有过期数据,清理过程是异步的。磁盘空间释放可能有延迟,这是正常行为。
Q16. 如何从 Prometheus 迁移到 VictoriaMetrics?
**使用 vmctl prometheus 命令迁移。**vmctl 可以从 Prometheus 的 TSDB 快照中读取数据,批量写入 VictoriaMetrics。迁移过程中 Prometheus 可以继续运行,迁移完成后切换 remote_write 目标。
Q17. vmagent 和 Prometheus 抓取有什么区别?
**vmagent 更轻量、更高效,但功能比 Prometheus 少。**vmagent 是 VM 官方推荐的抓取代理,支持 relabel 和 service discovery,但不支持告警评估(那是 vmalert 的职责)。
Q18. VictoriaMetrics 的 /metrics 端点有哪些关键指标?
**重点关注:vm_rows_inserted_total、vm_cache_size_bytes、vm_merges_total、vm_parts_automerge。**这些指标可以监控写入吞吐、缓存效率和合并状态。
Q19. vmalert 和 Prometheus AlertManager 怎么配合?
**vmalert 执行告警评估,AlertManager 处理告警路由和通知。**vmalert 评估规则后生成告警,发送给配置的 AlertManager(可以是 Prometheus AlertManager 或 vmalert 内置的通知器)。
Q20. 如何在 Kubernetes 中部署 VictoriaMetrics?
**推荐使用 Helm Chart 或 VictoriaMetrics Operator。**官方 Helm Chart 提供了完整的配置选项;VictoriaMetrics Operator 可以通过 CRD 管理 VM 资源,与 Prometheus Operator 配合使用。
全篇必记总纲
VictoriaMetrics 是 Prometheus 的超级增强版:通过 MergeSet LSM-less 设计、TSIDCache 37% 策略、blockCache 三层缓存实现比 Prometheus 省 7x RAM。Single-Node 适合中小规模,Cluster 支持无限水平扩展和多租户。200 篇系列覆盖架构设计、存储引擎、查询引擎、运维实践全维度。
八、Roadmap:后续预告
思考记忆提示 --- 后续预告帮助读者规划学习路径
- 按顺序阅读:先 A 架构设计篇,再深入其他维度
- 附录(A1-A10)是日常工具书,不需要按顺序阅读
本篇是 VictoriaMetrics 深度技术系列的开篇索引,接下来我们将按以下顺序展开:
- A. 架构设计篇(#01-#15):设计哲学、全局架构、存储引擎对比、性能模型
- B. 组件深潜篇(#16-#40):协议接入、写入核心链路、倒排索引
- C. 存储引擎篇(#41-#55):MergeSet 原理、Part 结构、压缩算法
- D. 查询引擎篇(#56-#70):PromQL、MetricsQL、查询优化
- E. 工具链篇(#71-#90):vmagent、vmalert、vmbackup、vmctl
- F. 集成生态篇(#91-#100):Grafana、k8s、Prometheus Operator
- G. 排障调优篇(#101-#115):慢查询、OOM、cardinality、内存调优
- H-M 进阶专题:decimal、bytesutil、persistentqueue、源码追踪
- N. 附录篇(A1-A10):速查地图、API 端点、错误码
本文参考与源码链接:
• VictoriaMetrics 官方 GitHub 仓库
VictoriaMetrics 源码【左扬精讲】· 开篇总览 · 版本:v1.146.0 LTS