
去年年底我们内部做了一轮 APM 选型。链路追踪的数据量涨得太快商业产品的账单一个月比一个月难看老板给的方向就一句话看看开源可观测栈能不能把这块顶住。于是我把 Prometheus Grafana Tempo 这组组合从头到尾搭了一遍指标、链路、统一可视化全部跑过生产流量。今天这篇选型报告就是把那时候踩过的坑和得出的结论整理出来重点回答一个问题这个开源可观测栈到底能不能替掉商业 APM以及哪些场景下替不了。先说我的总体判断能替但替换的并不是“商业 APM 的完整功能”而是“80% 的核心监控诉求”。剩下 20% 的体验性功能、低延迟检索、服务拓扑自动发现、以及开箱即用的联动分析开源栈要么需要自己拼要么效果只能算“够用”。这篇文章不打算吹开源免费也不打算给商业产品唱赞歌。我把两者的能力边界、成本结构、落地难点一条条列出来看完你心里应该能有一个比较清晰的答案。1. 先搞清楚商业 APM 到底在卖什么1.1 商业 APM 的典型能力清单以前我对商业 APM 的印象就是“链路追踪工具”部署个 Agent能在界面上看到每个请求经过哪些服务。后来自己上手配置和深度使用之后才发现商业产品真正贵的地方远不止链路追踪。一个主流的商业 APM 产品通常包含这么几块能力指标采集与展示、分布式链路追踪、错误捕获与堆栈分析、服务拓扑自动发现、慢查询分析、代码级剖析Profiling、告警与通知以及和日志系统的联动。有些做 To C 场景的产品还带 RUM真实用户监控能统计页面性能、JS 报错、请求成功率。这每一块单独拿出来都有对应的开源组件但商业 APM 把它们整合在一个界面里并且打通了数据之间的关联关系。这一整套下来你得到的不是一个监控工具而是一个“排障工作台”。收到告警 - 点开服务拓扑 - 看到某个接口变慢 - 点击进入单条 Trace - 看到某次数据库查询耗时再配合日志上下文整个过程都在同一个产品里完成。这种体验说实话开源栈目前默认组合还差一点。1.2 商业产品最值钱的“隐藏功能”很多技术选型文档不会强调但用过才知道商业 APM 最值钱的不是采集和存储而是“低运维负担”和“跨团队普及度”。低运维负担很好理解。SaaS 化的 APM 产品Agent 挂上之后就能在后台录入数据不需要你自己养护存储集群和查询引擎。指标存多久、Trace 采样多少、怎么扩容这些机器和索引的事平台都帮你处理了。对只有两三个后端同学、前端运营还要兼顾监控的中小团队来说省下的人力成本是很可观的。跨团队普及度则体现在协作上。商业 APM 的界面足够友好领导要看系统健康度点开大盘一目了然运维要排查网络问题可以直接看服务调用关系开发定位代码问题有堆栈、有日志、有参数。一套界面满足所有人的表述需求。这种体验要求开源可观测栈的搭建者本身有比较强的“产品思维”否则做出来往往只有自己能看懂。1.3 商业 APM 让人又爱又恨的三个原因既然商业产品体验这么好为什么要考虑替代我这边归纳了三个现实原因。第一个是成本不可控。链路数据是最容易爆炸的数据类型。一个 O(n^2) 的服务调用矩阵加上高并发业务每天产生的 Span 数量能轻松上亿。商业 APM 按 Span 计费、按节点计费的方式在这类流量下账单增长会非常快。我们当时统计过某商业 APM 每月成本接近 8 万而且这个数字还在随业务增长直线上升。第二个是数据孤岛问题。商业 APM 管应用内指标和调用链但它通常不愿意管基础设施。你的 Prometheus 已经有了机器负载、网络流量、中间件指标商业 APM 里的数据和应用指标默认是两边分开的。结果就是排障时要在两套系统之间来回切换很容易漏掉关联信息。第三个是技术绑定。商业 APM 的 SDK 或 Agent 用的是私有协议一旦接进去换平台等于重新埋点。这个绑定成本很多人选型时没考虑等数据量大了想搬迁才发现很被动。开源可观测栈走的是 Prometheus 指标体系和 OpenTelemetry 标准数据格式和企业自己的技术栈绑定不跟特定厂商绑定。2. 拆开 Prometheus Grafana Tempo 的底牌2.1 先别急着动手这三个组件到底谁管什么很多人一听“Prometheus Grafana Tempo”就以为是三个开源项目拼凑的简易监控组合。实际上这套组合的分工非常清晰和商业 APM 的功能模块是一一对应的。Prometheus 负责指标采集、存储和告警对应 APM 里的 metrics 模块。它通过 HTTP 定时抓取服务暴露的 /metrics 端点把指标时序数据存到本地 TSDB同时通过 Alertmanager 做告警路由和通知。Grafana 负责可视化连接 Prometheus、Tempo、Loki 等数据源统一展示指标面板和告警。Tempo 是一个分布式链路追踪后端接收 OpenTelemetry 等标准协议写入的 Trace 数据并基于 traceId 查询完整的调用链。这三者的组合就等于商业 APM 里的“指标 展示 链路”三大核心模块。再往后加一个 Loki 或 ClickHouse 管日志一个 OpenTelemetry Collector 管采集接入一套完整的开源可观测栈就算成型了。注意这三个组件并不是替代关系而是各管一段通过 Grafana 这个“统一入口”把体验拼起来。2.2 Prometheus 的强项和软肋监控面广高基数要命我用了六年 Prometheus说实话它的设计哲学我非常认可指标拉取模型简单、服务发现能力强、告警规则灵活。你能监控的不只是应用还有 Linux 机器、MySQL、Redis、Kafka、Nginx、交换机等一切能暴露指标的对象。之前有同行分享用 Prometheus 监控交换机端口流量配合 Grafana 导入 vCenter 告警做虚拟化监控这些场景都是商业 APM 覆盖不到的。但它有两个软肋选型时必须心里有数。第一是高基数问题。Prometheus 的每条时间序列由“指标名 一组标签”唯一确定如果标签中有像用户 ID、订单 ID、请求 ID 这种高基数维度序列数量会暴涨最终拖垮 TSDB 内存。很多团队第一次用 Prometheus习惯性把业务维度塞进标签里结果一个月后查询开始卡顿两个月的机器内存就不够了。这是一个很常见的坑后面实操部分我会专门讲怎么控制。第二是查询能力偏指标侧。PromQL 适合做聚合计算但你别指望靠它快速找到某条具体请求。如果只靠 Prometheus遇到“某个用户订单失败”这种问题你根本没有检索入口。所以它必须和其它组件配合典型做法是用 exemplar 把 metric 关联到 traceId再用 Grafana 跳转到 Tempo才能补上排障链条上的关键环节。2.3 为什么选 Tempo而不是 Jaeger 或 Zipkin链路追踪后端的主流选择有好几个Jaeger、Zipkin、Tempo甚至自建 ClickHouse 存 Span。我在选型时毫不犹豫先排除了 Zipkin它在功能上是早期标准但后续发展相对慢查询和存储能力都比较弱。Jaeger 功能完整、社区大支持多种存储后端但它在和 Grafana 生态、Prometheus 数据关联上需要额外配置。Tempo 最大的优势是“原生融合”。它和 Grafana 同为 Grafana Labs 出品Grafana 内置了对 Tempo 的一等数据源支持包括 TraceQL 查询语言、Trace to Logs、Trace to Metrics 这些关联能力都会为单独配置。当然这个理由听起来有点像“全家桶”信仰下面我讲三个更实际的选型依据。第一个是存储抽象。Tempo 可以对接 S3、GCS、Azure Blob 等对象存储你不需要专门维护一套 ES 集群。对象存储便宜、扩容方便对自建团队更友好。第二个是 TraceQL。Tempo 2.0 开始支持 TraceQL可以在链路数据里按“服务名、耗时、状态码、span 属性”等条件做结构化查询比单纯的 traceId 检索实用得多。第三个是查询依赖的标记机制。Tempo 本身不做索引外的重度聚合它的理念是“存原始 span 必要索引查询时用 TraceQL 扫描”这让存储成本比 Elasticsearch 方案低不少。当然 Tempo 也有明显短板不带服务拓扑自动发现。Jarger 可以通过 UI 生成依赖关系图Tempo 需要自己用 Grafana Node Graph 组装基础数据拓扑图的美观度和联动分析能力明显弱于商业 APM。这一点我在第 3 章的对比表格里会细讲。2.4 三个组件如何配合指标、链路、日志的三维联动单看组件能力这套栈似乎还是“三个孤岛”。真正让它们产生化学反应的是 Grafana 提供的 Datasource 关联功能。你可以把 Prometheus、Tempo、Loki 三个数据源配置在同一张面板里再通过 Trace to Metrics、Trace to Logs 功能建立关联。举个例子。你在 Grafana 上看一版 Prometheus 的接口错误率发现 order-service 的 500 错误突然升高。点一下面板里的关联链接Grafana 会自动打开 Tempo按相同时间范围和 service.name 列出对应的 Trace。点进某一条 Trace能看到完整调用链、每层耗时和异常信息。如果你还配了 Trace to Logs还能直接跳到这条 trace 关联的应用日志。一整套下来从指标告警到 Root Cause基本不需要在三个系统间手动切换。这套联动机制非常吃配置和规范比如必须统一维护 service.name 标签、时间戳格式、traceId 与日志的注入规范。如果团队规模小、数据标准比较乱体验会打折。但只要你愿意把规范做起来它并不复杂后面第 4 章我会给一份我实际用过的完整配置。3. 七个维度硬碰硬到底能不能替3.1 一张表看懂开源组合与商业 APM 的核心差异我用一个表格把这套开源可观测栈和商业 APM 在七个关键维度上的表现列出来这是选型决策最常用的参照表。对比维度Prometheus Grafana Tempo商业 APM标杆产品部署运维自建三大组件需自行处理高可用、存储、升级SaaS 免运维或私有化一次性交付数据采集标准OpenTelemetry、Prometheus 协议生态开放厂商私有 Agent绑定较强指标监控范围覆盖应用基础设施中间件网络设备极广主要以应用为核心基础设施覆盖少链路检索体验TraceQL 可用但默认界面和检索流畅度一般界面友好多维检索和时序对比极强服务拓扑图需要自行组装 Node Graph无自动发现自动生成秒级展示服务依赖关系告警能力PromQL 规则极灵活Alertmanager 路由能力强能力齐全但规则灵活性相对弱增量成本服务器成本 人工维护成本主要弹性来自硬件按节点/月或按 Span 计费随业务规模线性上涨这张表最值得关注的是第一行和第四行。第一行说明开源栈有运维成本这一点能劝退很多人第四行则说明在排障体验上商业 APM 依然有优势。其余的比如告警灵活性和监控范围开源栈反而是赢家。3.2 哪些场景闭眼换哪些场景要慎重经过这张表对比结论就比较清晰了。如果你的业务特征符合下面这几类那开源栈替换商业 APM 的风险很低。第一类数据量特别大的场景。高并发的 To C 业务尤其是网关、交易、订单这类核心链路每天产生海量 Trace。自建对象存储和 Prometheus 的本地存储成本远低于按 Span 计费这时候开源方案的成本优势是压倒性的。第二类基础设施链路多、应用监控需求相对简单的场景。比如你有一堆交换机、虚拟机、数据库要盯商业 APM 只管应用这部分你还是需要 Prometheus 和 Grafana。与其两套体系并行不如直接用开源组合统一监控顺便把应用链路也接进来。第三类有较强的可观测性工程能力并且愿意投入标准化建设的团队。这类团队本身就在推 OpenTelemetry 和统一标签规范开源栈能把能力发挥到极致甚至比商业 APM 更贴合自己的业务。反过来说适合继续用商业 APM 的场景也很典型。缺少专职 SRE 和可观测性团队的小组直接上开源组合很容易变成无人维护的“僵尸监控”。业务稳定性要求极高、出问题必须在秒级定位的团队商业 APM 的服务拓扑和统一检索体验现在还是比开源组合顺手。还需要 RUM、代码级 Profiling 这类深度分析能力的场景开源栈目前没有等价的默认方案硬凑的话需要拼凑多个组件投入会很大。4. 从零落地的关键路径一套可以直接参考的搭建流程4.1 架构设计与组件选型如果你决定自己动手我建议架构如下每个服务集成 OpenTelemetry SDK把 traces 和 metrics 发送到 OpenTelemetry CollectorCollector 做一次统一处理把 trace 导出到 Tempo把 metrics 导出到 Prometheus或者直接让服务暴露 /metrics 端点给 Prometheus 抓取。组件上我推荐部署 Prometheus Grafana Tempo OpenTelemetry Collector。日志这部分如果预算和运维精力有限可以先用 Loki 顶着后续需要再做长周期存储。Alloy 是 Grafana 新一代采集器如果你已经用了 Alloy那 Promtail 可以不用装了它支持收集 Loki 日志并自动关联 traceId。我当时的部署方式是 Kubernetes 里用 Helm 安装Tempo 的存储直接配置 S3。物理机上直接部署的架构和这套类似只是把服务发现换成静态配置或 Consul逻辑上没有区别。4.2 服务接入一个 Agent 搞定 Trace 和 Metrics服务侧接入最省事的方式是使用 OpenTelemetry Java Agent 做自动埋点。它通过字节码注入自动采集常见框架的请求、HTTP、数据库、消息队列等 Span不需要改业务代码。我的做法是给每个服务定义环境变量并追加 javaagent 启动参数OTEL_SERVICE_NAMEorder-service OTEL_TRACES_EXPORTERotlp OTEL_METRICS_EXPORTERotlp OTEL_EXPORTER_OTLP_ENDPOINThttp://otel-collector:4317 java -javaagent:path/to/opentelemetry-javaagent.jar -jar order-service.jar如果你用别的主流语言比如 Python、Go、Node.js也都有对应的 SDK。Python 最贴近“无侵入”的用法是 opentelemetry-instrument 命令它和 Java Agent 的思路一样通过导入 hook 自动埋点。Go 那边则需要自己在关键入口手动埋点因为 Go 没有字节码注入机制。这一步最容易踩的坑是接入后发现 Trace 没有产生排查时优先检查三件事一是 OTLP endpoint 是否可访问二是服务名和环境变量是否配置正确三是版本号必须匹配OpenTelemetry SDK 和 Collector 的 API 兼容性偶尔会出问题。另外如果你的服务已经在用 Spring Cloud Sleuth 或 SkyWalking 这类组件注意先移除旧探针依赖避免重复采集和 Id 冲突。4.3 存储选型Tempo 配置 S3 和保留策略Tempo 的架构是全后端默认支持内存、本地磁盘和对象存储。生产环境一定不要用本地磁盘否则扩容和备份都很难受。我直接配置 S3设置一个存储桶生命周期策略让旧数据自动过期。Tempo 服务端配置里最关键的是trace数据的存储路径确认、接收的协议端口以及查询相关配置。OpenTelemetry Collector 用 gRPC 发送数据默认端口是 4317需要在 Tempo 里开启 otlp 接收器。一个极简的 Tempo 配置长这样storage: trace: backend: s3 s3: bucket: my-tempo-data endpoint: s3.amazonaws.com access_key: ... secret_key: ... block: version: vParquet3 server: http_listen_port: 3200 distributor: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317关于保留周期Tempo 不像 Prometheus 那样按“多少天”简单清数据它是把一段时间的数据切成 blockblock 到期后由 Compactor 合并整理。你可以通过限制后端对象的生命周期比如 S3 生命周期策略里设置 15 天过期到期后旧 block 自动删除。我说下自己的经验Trace 数据保留 7 天足够覆盖绝大多数排障场景超过 15 天的链路数据很少有人会去回溯能省不少存储成本。4.4 Prometheus 抓取配置和告警规则示例Prometheus 的配置核心是 scrape_configs。如果服务直接用 OTLP 输出Prometheus 没法直接抓取我建议架构中保留两类采集方式并存一类直接抓取服务暴露的 /metrics另一类从 OpenTelemetry Collector 接收 OTLP metrics再通过 Collector 的 prometheus exporter 转出来。直接抓取远程的配置大概长这样scrape_configs: - job_name: order-service metrics_path: /metrics static_configs: - targets: [order-service:8080] labels: service_name: order-service告警规则方面我不建议一开始就把告警规则写得很复杂。先把基础四件套做对接口错误率、接口 P95 延迟、实例存活、队列积压量。一条简洁的错误率告警规则如下groups: - name: order-alerts rules: - alert: 接口5xx错误率过高 expr: | sum(rate(http_server_requests_seconds_count{status~5..}[5m])) / sum(rate(http_server_requests_seconds_count[5m])) 0.05 for: 10m labels: severity: warning annotations: summary: 接口 5xx 错误率超过 5%注意一个很常见的坑直接用 rate 与 0.05 比较如果业务量很低比如 5 分钟内只有 4 个请求挂了 1 个也算 25% 的错误率会产生误报警。我一般会加一个 min 条件比如“至少 10 个请求基础上错误率超过 5%”这样能过滤掉低流量抖动。4.5 Grafana 关联配置Trace 到 Metrics、Trace 到 Logs最后一步就是把 Grafana 变成排障前台。在 Grafana 的 Data Sources 里添加 Prometheus、Tempo 和 Loki 三个数据源然后做两层关联。第一层是 Trace to Metrics。在 Tempo 数据源配置的 Trace to metrics 区域填写对应 Prometheus 数据源以及一个按 service.name 过滤的时间序列查询。这么配好之后你在 Tempo 的 Trace 详情页可以直接点击“查看服务指标”跳转到对应服务的 Prometheus 面板。我当时的查询是这样sum(rate(http_server_requests_seconds_count{service_name$__tags.service.name}[5m])) by (service_name)第二层是 Trace to Logs。在 Tempo 数据源配置里打开 Trace to logs指定 Loki 作为日志源并配置 tag map把 Trace 里的 service.name、traceId 映射到日志的对应标签。这需要应用日志打印时有 traceId 字段如果用 OpenTelemetry JavaAgent配置一条日志 pattern 把 traceId 加进去最简单的方式是直接在 logging 配置里引用属性。pattern%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %X{trace_id} - %msg%n/pattern到这里Grafana 的整体体验已经非常接近商业 APM 了。你在 Prometheus 面板点一下可以跳到 Tempo 看 Trace再看 Trace 时又能跳到 Loki 看日志。整条链路说白了就取决于你数据源关联配置和标签规范是否一致。5. 上线之后最容易踩的坑问题排查与优化实录5.1 链路数据太多Tempo 存储持续膨胀这是替换商业 APM 之后第一个爆发的痛点。业务代码什么都不改Agent 一上Tempo 的写入流量是以 GB 计算的。一上来全量存S3 存储费用可能压不住选择退而求其次就是做采样策略。服务端龙头采样优先推荐 tail-based sampling。它整体流程是让每个采样器决策器在一段时间内积累同一 traceId 的 span完整 Trace 结束后再根据条件决定是否保留。配置时重点保留三类错误链路、慢调用链路、核心接口的完整链路。OpenTelemetry Collector 配置 tail_sampling一个最常用的策略是“有错误必须保留标记为慢请求的也保留其余按比例 10%”processors: tail_sampling: decision_wait: 10s policies: - name: error-policy type: status_code status_code: {status_codes: [ERROR]} - name: slow-policy type: latency latency: {threshold_ms: 500} - name: random-policy type: probablistic probablistic: {sampling_percentage: 10}我做压测之后建议核心交易链路采样率不低于 50%其他边缘接口 5%~10%错误和慢请求 100% 保留。这样存储成本能压到原来的四分之一左右而且排障时最需要看的错误 Trace 一条都不会丢。5.2 Prometheus 高基数爆炸标签设计规范必须前置Prometheus 的高基数问题几乎每半年就坑我一次最典型的是有人把 request_id、user_id 放进标签里。这类标签基数可能是百万、千万级别Prometheus 的内存根本扛不住。排查手段很简单直接在 Prometheus 的 TSDB 状态页看 head 序列数量或者执行一条查询看最大基数序列topk(10, count by (__name__)({__name__~.}))解决思路只有一个标签只能放低基数维度比如 service_name、instance、status_code、method、env 这类。业务维度要想做多维分析就别全走 metrics应该直接进日志或 Trace 的 span attribute。这一步变相印证了为什么可观测性一定要“指标、日志、链路”三者打通不同数据用不同存储各干各擅长的活。5.3 Trace 查询慢排查 Trace 检索效率有段时间我们在 Grafana 查一条 Trace耗时十几秒甚至几十秒体验远不如商业 APM。后来发现是两个原因叠加。第一个原因是大量 Span 只依赖 traceId 索引但索引未按追加时间切片。Tempo 支持在 traceId 后追加时间范围如果查询时时间范围跨度太大扫描的 block 数量会很多。解决方法是把 Grafana 里的 Tempo 查询尽量缩小起始时间范围前面版本的 UI 有“最近 15 分钟”这种默认选项但手动改到准确时间段能显著提速。第二个原因是块压缩周期配置不合理。Tempo 的 compactor 配置可以调整 block 的合并节奏如果 block 太多太小查询时要命中多个对象。我把它配置成压缩出稍大的 block查询效率立刻上来了。这块配置参数每个环境不一样建议直接看 Tempo 文档里的 Compactor 调优章节不需要全文背下来。5.4 指标与日志对不上时间戳和时区问题有一次查问题指标和日志明明来自同一个请求但时间差了几秒导致 Grafana 里的关联跳转总是落在错误的位置。后来发现是服务日志用的是服务器本地时区Grafana 用的是 UTC中间隔了 8 个小时。规范统一时间处理是所有可观测性建设的第一步。指标、日志、Trace 全部统一为 UTC 存储展示层由 Grafana 按浏览器时区渲染。日志生产时不要格式化成本地时间字符串直接用 UTC ISO8601。这个习惯小团队可能觉得无所谓但只要你做跨区域部署或多团队协作坑马上就会出现。5.5 常见问题速查表现象可能原因排查方向接入了 Agent但 Tempo 没有收到 TraceOTLP endpoint 不通或 Agent 版本兼容问题先检查 Collector 日志再用 grpcurl 测试 4317 端口日志里没有 traceId日志框架没有配置 traceId 映射打开 OpenTelemetry 的 MDC 集成开关Prometheus 经常 OOM高基数标签增长查 TSDB 状态限制标签维度Grafana 面板数据不刷新数据源 token 过期或网络隔离看 Grafana 日志测试数据源健康状态Trace 详情页点击“服务指标”无反应Trace to Metrics 查询参数错误确认模板变量使用了 $__tags.service.name 且标签名一致告警重复轰炸Alertmanager 分组粒度太细按 severity service 分组设置 repeat_interval6. 最终权衡什么条件下这套组合能直接上位到了这一步选型结论其实取决于你团队的可观测性成熟度而不是纯粹的技术能力。我把判断标准简化成一个决策树按顺序回答三个问题就能有答案。第一个问题你的业务对链路追踪的“低查询延迟”有硬性要求吗如果每次排障都要求秒级跳转那我建议保留商业 APM。Tempo 的 TraceQL 足够好用但它的查询链路是对象存储 扫描比商业 APM 的预聚合索引慢一个量级。对大多数团队来说慢 5 秒能接受但对那种“用户投诉了必须马上看数据”的在线服务这个差异很影响体验。第二个问题你的团队能拿出一个人持续维护这套开源栈吗这里说的维护不是修一个 bug而是持续关注存储水位、扩容、升级版本、调优 Compactor、推进业务侧埋点规范。如果没有这个人开源栈上线半年后大概率变成“数据在跑、没人看”的状态。有这个精力投入替换商业 APM 的成本优势才能真正释放出来。第三个问题你是否承担得起数据量爆发时的基础设施成本商业 APM 的计费是增量线性的开源栈的存储成本更像一个阶梯。但注意阶梯的另一边是硬件采购和人员时间。如果业务增长非常快你需要在预算模型里同时算清楚机器扩容和人工值班成本而不是简单说“开源免费”。从我个人实际踩过的坑来看这套开源可观测栈在“中等规模、核心数据量大、有一定运维能力”的团队里完全可以替代商业 APM。替换的收益不是省下那十来万软件费而是让每一份数据都在自己手里指标覆盖范围更广、告警规则完全可控、数据格式标准化不再被厂商锁定。如果你所在的团队情况符合这几个条件我愿意给你一个比较大胆的建议找一个边缘业务先接 OpenTelemetry用 Prometheus Grafana Tempo 跑一个月和商业 APM 平行对比看效果。等熟悉了这套链路再把核心业务逐步切过去。如果暂时不具备条件也不要硬上。商业 APM 买单的不全是功能而是“不给自己找事”的确定性。开源栈给你的是控制权代价是责任。两者没有绝对的优劣只有合不合适。最后再分享一个小技巧无论你最终选哪条路务必把 OpenTelemetry 作为统一接入标准去推进。只要数据层标准化你随时可以在商业和开源之间切换不用再经历一遍被供应商绑架的痛苦。