文章

搭可观测性平台,为什么是 LGTM 拼出来的,不是一个 all-in-one

可观测性平台不是选一个"最强工具"就能搭起来的,日志、指标、告警、采集这几层每一层的取舍标准都不一样。这篇讲清楚为什么放弃 all-in-one 方案改用 LGTM 拼装、为什么指标选 VictoriaMetrics、告警为什么要拆成两套、OTel Collector 的采集层怎么分工。

搭可观测性平台,为什么是 LGTM 拼出来的,不是一个 all-in-one

搭可观测性平台,最开始会被”要不要选一个大而全的方案”这个问题绊住——市面上确实有把日志、指标、链路一锅端的产品,看起来能省掉拼装几个组件的麻烦。但真正落地之后发现,日志、指标、告警、采集这几层各自的取舍标准完全不一样,硬塞进一个方案里,早晚要在某一层上吃亏。

整体架构大致是这样,从上到下走一遍数据流转:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 Pod stdout/stderr   Pod 持久化文件日志   K8s API / Events   应用 Traces (OTLP)
        │                    │                  │                  │
        ▼                    ▼                  ▼                  │
 Node Collector          fluent-bit       Cluster Collector        │
 (DaemonSet, Helm)           |             (Deployment, Helm)      │
 主机指标 / 日志              |              集群事件 / 集群级指标   │
        │                    │                  │                  │
        └────────────────────┴──────────────────┴──────────────────┘
                                     │
                                     ▼
                          OTel Gateway (CRD)
                     采样 / 脱敏 / 路由 / 凭证收敛
                                     │
                 ┌───────────────────┼───────────────────┐
                 ▼                   ▼                   ▼
               Loki           VictoriaMetrics           Tempo
              (日志)              (指标)               (链路追踪)
                 │                   │                   │
                 └───────────────────┼───────────────────┘
                                     ▼
                                 Grafana

Node Collector 和 Cluster Collector 是平级的两个采集器,分别对应节点级和集群级两类数据,都用 Helm Chart 部署;Pod 自己写到磁盘上的持久化日志文件另有一条路径,走 fluent-bit 采集;应用产生的链路追踪数据走 OTLP 直接上报。这几路数据最终都汇总到 Gateway 这一层,再由 Gateway 分流到 Loki、VictoriaMetrics 和 Tempo。

为什么选 OTel 做采集层

先要说清楚一点:OTel 和 LGTM 不是二选一,两个不在同一层。LGTM 是存储和查询层,OTel 是采集和传输层,架构上是”OTel 采集 → LGTM 存储”,两个都用了,而且 Loki/VictoriaMetrics/Tempo 现在都原生接收 OTLP,OTLP 本身就是 LGTM 的入口协议。真正要决策的是采集层用什么,不是要不要 LGTM。

采集层选 OTel 而不是给每个后端配一个专用采集器(Promtail 配 Loki、vmagent 配 VictoriaMetrics),核心考量是:后端换起来容易,重新接一份数据、Grafana 改个数据源就行,业务侧无感;采集层换起来是灾难,它散布在每个节点的 DaemonSet、每个 Pod 的 sidecar、每个应用的插桩代码里。用专用采集器就等于把后端和采集层焊在一起,后端一换,所有节点的配置都要跟着改。OTel 作为厂商中立的标准协议,采集层和后端解耦,换后端不用动采集这一层。这跟下面选 LGTM 拼装、不选 all-in-one 是同一个判断标准,只是这次用在了采集层上。

为什么是 LGTM,不是 all-in-one

选型阶段对比过几个 all-in-one 方案:

方案优势短板
OpenObserveRust 实现,性能好、资源占用低,支持 SQL 语法查询,日志/指标/链路/看板/告警这些基础功能开源版本身是齐全的RBAC、SSO 这类多租户权限能力开源版不支持(所有用户拥有全部权限),要用得靠自托管 Enterprise 版,且免费额度有用量上限
SigNozGo 后端 + React 前端,功能齐全强绑 ClickHouse,等于把平台稳定性又绑到另一个重型组件上
SkyWalking + BanyanDB概念上简单不通用也不成熟,实际部署过程中一直报错没能跑起来;BanyanDB 到现在还没发布 1.0,社区原计划的 GA 时间也已经推迟,生产用还太早

最后选的是 LGTM 拼装方案,各组件分工:

组件管什么
Loki日志,压缩率高
Grafana统一可视化
Tempo链路追踪
M(VictoriaMetrics)指标

拼装的代价是多一层组件间的对接工作,换来的是每个组件在自己的领域里都是经过大规模验证的成熟方案,不用担心某个小众组件在生产里掉链子。这跟”选一个够用的独立组件,比选一个大而全但某一块不够硬的方案更稳”是同一个判断标准。

指标为什么选 VictoriaMetrics,不是 Prometheus 或 Mimir

三者都能存指标、跑 PromQL,但适用场景不一样:

 PrometheusMimirVictoriaMetrics(集群版)
定位单机时序数据库,原生不支持长期存储和透明的水平扩展(federation、分片这些手段存在,但用起来麻烦)在 Prometheus 生态上做了长期存储和水平扩展,支持 monolithic 单进程模式(-target=all),也能横向部署多个该模式实例做扩展,不强制走全套微服务拆分独立实现的时序数据库,天生支持集群模式
多租户不支持,一套实例对应一套数据支持,按租户隔离开源版支持基础隔离,读写都带 accountID;但按租户设不同保留期、按租户限流这类更精细的多租户能力是 Enterprise 功能
协议/许可Apache 2.0AGPL-3.0,商业化上有额外限制,选型时要单独评估集群版 Apache 2.0 开源
生态兼容PromQL 生态的源头,兼容性最好兼容 PromQL,接口对齐 Prometheus兼容 PromQL 和 Prometheus 的 remote_write/HTTP API,迁移成本低
部署复杂度简单,单体即可monolithic 模式下不比 VictoriaMetrics 复杂,但要用到 store-gateway/compactor 这类长期存储能力时会趋向微服务拆分中等,读写分离,组件数量比 Mimir 全量微服务模式少

选 VictoriaMetrics 的核心权衡是:比 Prometheus 多了长期存储和多租户能力,又不用为了拿到 Mimir 那种水平扩展能力而承担 AGPL-3.0 的许可限制。读写路径是分离的,写入压力大的时候不会拖累查询,查询复杂的时候也不会拖累写入,两条链路互不干扰。多租户在开源版里也是原生支持的,上报和查询都带一个 accountID,不同业务线的指标从物理上就是隔离的,不需要在应用层自己拼前缀去区分——如果诉求进一步到”不同业务线要设不同保留期”或”按租户限流”,那部分能力目前只在 Enterprise 版里。

告警为什么拆成两套,而不是一套管到底

告警没有走”一个系统管所有规则”的路子,按告警的性质拆成了两层:

 vmalertGrafana Alerting
管什么机器 CPU/内存/磁盘、K8s 节点状态、Grafana 自身存活检测错误日志数量、接口响应变慢、业务订单量下跌
改动频率低,配置好基本不用再动高,业务变化时需要开发自己调整
设计目标跟 UI 解耦,保命协作方便,规则迭代快
依赖部署位置独立于被监控对象——vmalert 只做规则求值,通知交给 Alertmanager,链路不经过 Grafana,Grafana 挂了不影响这条链路依赖 Grafana 的 UI 做规则维护

拆开的核心逻辑是:谁该稳定、谁该灵活,不是同一套标准。保命的告警链路要尽量少依赖可视化层,追求的是可靠;业务告警改动频率高,需要开发自己上手改,追求的是好用。需要说清楚的是,vmalert 这条链路也不是零依赖——它查询的数据本身来自 VictoriaMetrics,如果磁盘满到连 VictoriaMetrics 都写不进去,vmalert 一样会查不到数据、跟着哑掉,”保命”说的是不依赖 Grafana 这层可视化,不是不依赖任何组件。把这两种诉求塞进同一套告警系统里,要么牺牲可靠性,要么牺牲协作效率。

OTel Collector:Agent 层和 Gateway 层为什么用不同工具管

采集层用的是 OpenTelemetry Collector,分 Agent 和 Gateway 两层部署,这两层选的部署工具也不一样:

 Agent 层Gateway 层
部署工具Helm ChartOperator CRD
职责采集,细分两个采集器:一个 DaemonSet,每个节点一份,采主机指标和日志;一个单副本 Deployment,采集群级别的 metrics 和事件集中做采样、脱敏、路由
选型理由preset 把常见的 K8s 采集场景封装成了开箱即用的配置项,DaemonSet 那份靠 preset 采主机指标、日志,Deployment 那份靠 preset 采集群事件和集群级 metrics,两者都不用从零手写 receiver 和权限配置弹性伸缩和配置变更是声明式托管的,贴合这层”规则本身会经常调整”的特点,同时把往后端写数据用的认证凭证收敛到这一层集中管理——不然认证方式一变,所有节点上的 Collector 配置都要跟着改一遍

Agent 层内部按”节点级”和”集群级”拆成了两个采集器,是因为这两类数据的采集方式本来就不一样:主机指标、日志是每个节点各采各的,天然适合 DaemonSet;集群事件、集群级 metrics 只需要采一份,起一个 Deployment 单副本就够,起多份反而会重复采集。这两个采集器都是标准化程度很高的场景,用 Helm Chart 的 preset 覆盖就够了。

同一个 OpenTelemetry 生态,Agent 层和 Gateway 层选了两种部署工具,依据不是谁更先进,是两层各自要解决的问题不一样:一层要的是标准化采集的现成能力,一层要的是配置常变时的弹性和凭证集中管理。

小结

从日志/指标/链路选 LGTM 拼装,到指标选 VictoriaMetrics 的读写分离,到告警拆成保命层和业务层两套,再到采集层 Agent/Gateway 用不同工具管——每一层的选型标准都不一样,共同点是没有哪一层是照抄一份”最佳实践”配置就定下来的,都是先看清楚这一层真正要解决什么问题,再决定用什么工具、用什么架构去管它。

这篇讲的是集群侧怎么把数据采起来、送到哪,应用自己那一侧要怎么配合——日志该走 stdout 还是显式挂卷、链路追踪怎么接入 SDK——是另一个问题,留给下一篇讲应用侧的采集选型和方案。

本文由作者按照 CC BY 4.0 进行授权