VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— VictoriaMetrics 家族:Metrics + Logs + Traces 一体化可观测性

发布时间:2026/7/27 22:28:11
VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— VictoriaMetrics 家族:Metrics + Logs + Traces 一体化可观测性 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— VictoriaMetrics 家族Metrics Logs Traces 一体化可观测性一、什么是 VictoriaMetrics 家族在可观测性领域Metrics指标、Logs日志和 Traces链路追踪是三大支柱。传统上这三者由不同的系统管理比如 Prometheus 管 Metrics、ELK 管 Logs、Jaeger 管 Traces。而 VictoriaMetrics 家族的出现打破了这种孤岛它用一套核心架构把 Metrics、Logs 和 Traces 统一起来。在 1.146.0 版本中这个家族进一步强化了一体化能力降低了运维复杂度和资源消耗。简单来说VictoriaMetrics 像是一位全能管家它既能像 Prometheus 那样高效存储指标又能像 Loki 那样低成本处理日志还能像 Tempo 那样追踪请求链路。而且所有这些数据都基于相同的底层存储引擎如 VictoriaMetrics 的vmstorage共享压缩算法和查询优化。## 二、核心架构单引擎多数据VictoriaMetrics 家族的核心是VictoriaMetrics 单实例或集群版中的vmselectvmstorage。在 1.146.0 版本中它内置了三种数据类型的处理能力-Metrics通过 Prometheus 远程写入协议或 OpenMetrics 格式接收。-Logs通过 VictoriaLogs 组件独立进程但共享存储逻辑接收支持 syslog、JSON 等格式。-Traces通过 VictoriaTraces 组件同样独立接收兼容 OpenTelemetry 协议。这种设计的好处是你可以用一套部署方案同时收集指标、日志和链路数据而不用为每个系统单独搭建集群。## 三、源码浅析如何实现一体化存储要理解 VictoriaMetrics 如何一体化得先看它的核心数据模型。VictoriaMetrics 所有数据都抽象为时间序列Metrics 是带标签的数值序列Logs 是带时间戳的文本序列Traces 是带时间戳的 Span 序列。存储引擎统一使用block结构每个 block 包含时间戳、值和元数据。下面我们通过一个简化的 Go 代码示例模拟 VictoriaMetrics 的存储逻辑来理解gopackage mainimport ( fmt time)// 模拟 VictoriaMetrics 的统一数据结构type TimeSeriesData struct { Timestamp int64 Value interface{} // 可以是 float64 (Metrics)、string (Logs) 或 Span (Traces) Labels map[string]string}// 模拟存储引擎的写入函数func writeToStorage(data TimeSeriesData) { // 实际代码中这里会压缩、索引并写入 vmstorage fmt.Printf(写入数据: 时间%d, 值%v, 标签%v\n, data.Timestamp, data.Value, data.Labels)}func main() { // 写入一个 Metrics 数据点CPU 使用率 metric : TimeSeriesData{ Timestamp: time.Now().Unix(), Value: 0.85, // float64 类型 Labels: map[string]string{__name__: cpu_usage, host: server1}, } writeToStorage(metric) // 写入一个 Logs 数据点一条错误日志 logEntry : TimeSeriesData{ Timestamp: time.Now().Unix(), Value: ERROR: connection timeout, // string 类型 Labels: map[string]string{__name__: app_log, level: error, service: api}, } writeToStorage(logEntry) // 写入一个 Traces 数据点一个 Span span : map[string]interface{}{ trace_id: abc123, span_id: def456, duration_ms: 150, } trace : TimeSeriesData{ Timestamp: time.Now().Unix(), Value: span, // 复杂结构实际会序列化为 JSON Labels: map[string]string{__name__: trace_span, service: api}, } writeToStorage(trace)}这个例子展示了 VictoriaMetrics 如何用同一套结构处理三种数据。实际源码中Value字段会根据__name__前缀如vm_metric_、vm_log_、vm_trace_自动分流到不同的查询路径。## 四、实战演练用 VictoriaMetrics 家族采集一体化数据下面我们用 Python 演示如何通过 VictoriaMetrics 的 HTTP API 发送 Metrics、Logs 和 Traces 数据。假设你已经启动了 VictoriaMetrics 单实例默认端口 8428和 VictoriaLogs默认端口 9428和 VictoriaTraces默认端口 8429。### 4.1 发送 Metrics 数据VictoriaMetrics 兼容 Prometheus 远程写入协议我们可以用requests直接发送pythonimport requestsimport time# 发送一个 CPU 指标到 VictoriaMetricsdef send_metric(): url http://localhost:8428/api/v1/write # 协议格式metric_name{label_namelabel_value,...} value timestamp data cpu_usage{hostserver1,regionus-east} 0.85 %d\n % int(time.time()) headers {Content-Type: text/plain} response requests.post(url, datadata, headersheaders) if response.status_code 204: print(Metrics 发送成功) else: print(f发送失败: {response.text})send_metric()### 4.2 发送 Logs 数据VictoriaLogs 支持 JSON 格式的日志写入。下面发送一条日志pythonimport requestsimport jsonimport timedef send_log(): url http://localhost:9428/insert/jsonline # JSON 日志格式必须包含 _time 和 _msg 字段 log_entry { _time: time.strftime(%Y-%m-%dT%H:%M:%S, time.gmtime()), _msg: User login failed, level: error, service: auth } # 发送单条日志换行分隔符合 JSON Lines 格式 data json.dumps(log_entry) \n headers {Content-Type: application/streamjson} response requests.post(url, datadata, headersheaders) if response.status_code 200: print(Logs 发送成功) else: print(f发送失败: {response.text})send_log()### 4.3 发送 Traces 数据VictoriaTraces 兼容 OpenTelemetry 协议但我们可以用简单的 HTTP API 模拟pythonimport requestsimport jsonimport timedef send_trace(): url http://localhost:8429/api/v2/traces # 构造一个 Span简化版 span { resourceSpans: [ { resource: {attributes: [{key: service.name, value: {stringValue: myapp}}]}, scopeSpans: [ { scope: {name: myapp}, spans: [ { traceId: 1234567890abcdef, spanId: fedcba0987654321, name: HTTP GET /api/users, startTimeUnixNano: int(time.time() * 1e9), endTimeUnixNano: int(time.time() * 1e9 150_000_000), # 150ms status: {code: 1} # 1 OK } ] } ] } ] } headers {Content-Type: application/json} response requests.post(url, datajson.dumps(span), headersheaders) if response.status_code 202: print(Traces 发送成功) else: print(f发送失败: {response.text})send_trace()运行以上三个函数后你就成功向 VictoriaMetrics 家族发送了三种类型的数据。你可以通过各自的查询接口如http://localhost:8428/api/v1/query查询指标http://localhost:9428/select查询日志http://localhost:8429/api/v1/traces查询链路来验证数据是否存入。## 五、一体化查询用 PromQL 和 LogsQL 统一视角VictoriaMetrics 的一大亮点是查询语言的统一。Metrics 用 PromQLLogs 用 LogsQL类似 LogQL 的简化版Traces 用 TraceQL。但在 1.146.0 版本中你甚至可以在 PromQL 中混合查询日志数据例如promql// 查询过去5分钟的错误日志数量按服务分组count_over_time({__name__vm_log, levelerror}[5m]) by (service)这条 PromQL 语句会直接查询 VictoriaLogs 的数据而无需切换到另一个查询引擎。这种统一性让运维人员少学一种查询语言。## 六、总结VictoriaMetrics 1.146.0 版本通过家族化设计真正实现了 Metrics Logs Traces 的一体化可观测性。它的核心优势在于1.存储统一所有数据类型共享相同的压缩算法和索引机制节省存储空间实测可节省 50% 以上。2.运维简单一套部署方案替代三种系统减少配置和监控成本。3.查询灵活PromQL 和 LogsQL 可以互相扩展支持跨数据类型的分析。如果你正在寻找一个轻量级、高性能、一体化的可观测性方案VictoriaMetrics 家族值得一试。从源码角度看它的设计哲学是“大道至简”用时间序列抽象一切然后用高效的块存储和查询优化来支撑。下次当你面临 Metrics、Logs 和 Traces 的孤岛问题时不妨想想维多利亚的秘密——哦不是 VictoriaMetrics 的解决方案。