云原生可观测性落地:用 OpenTelemetry 把指标、日志、链路一次打通

举报
yd_292302676 发表于 2026/11/01 09:25:05 2026/11/01
【摘要】 从"三个系统各查一遍"到"一条 trace 定位问题":OpenTelemetry 自动埋点与业务属性补全、Collector 三层管道与尾部采样配置、黄金信号指标控基数、Grafana 单面板下钻设计,附四个真实踩坑。

问题不是"没有监控",而是"三个系统各查一遍"

很多团队上云之后并不缺监控:主机有基础监控,应用打了 Prometheus 指标,日志进了 LTS,链路有 APM。但真出故障时,值班的人还是要开着四五个页面来回对照——先在告警里看到 P99 飙高,再去日志里搜报错,最后靠猜去翻链路。一次排查半小时,其中二十分钟花在"对齐时间戳和找同一个请求"上。

根因不是工具不够,而是三份数据之间没有共同的锚点。指标告诉你"哪里慢了",日志告诉你"报了什么错",链路告诉你"慢在哪一跳",只有三者能通过同一个 trace ID 串起来,排查才会从"翻找"变成"顺着走"。

这篇记录一次实际改造:一个跑在 CCE 上的 Java 服务,用 OpenTelemetry 统一埋点,Collector 做汇聚,指标进 Prometheus,日志带上 trace ID,最后在 Grafana 上做成一个能下钻的面板。

先想清楚三类数据各自回答什么问题

改造前最容易犯的错,是把三类数据当成"都要有",结果每类都采了一点,每类都不好用。它们的定位其实很清楚:

数据类型 回答的问题 成本特征 采样策略
指标 Metrics 系统现在健康吗,趋势往哪走 低,可按时间聚合长期保留 全量,但要控标签基数
日志 Logs 这一刻具体发生了什么错 高,随流量线性增长 全量采错误,正常日志分级
链路 Traces 这个请求慢在哪一跳 很高,随调用深度放大 头部采样 + 错误全采

记住这个分工,就不会出现"用日志算 QPS"或者"用链路做容量规划"这类事倍功半的做法。

埋点:别手写,用 SDK 的自动注入打底

OpenTelemetry 的 Java Agent 能自动埋住常见框架(Spring MVC、JDBC、Redis、HTTP Client),零代码改动就能拿到 span。先让它跑起来,再考虑手动补关键业务属性:

java -javaagent:/opt/otel/opentelemetry-javaagent.jar \
  -Dotel.service.name=order-service \
  -Dotel.exporter.otlp.endpoint=http://otel-collector:4317 \
  -Dotel.resource.attributes=deployment.environment=prod,k8s.namespace.name=prod \
  -jar app.jar

自动埋点之后,业务上真正需要手写的只有一件事:把"这次请求是谁的、在做什么"写进 span。比如订单服务里补一条:

Span span = Span.current();
span.setAttribute("order.id", orderId);
span.setAttribute("order.channel", channel);
span.setAttribute("biz.result", result);

就这三个属性,让后面所有按订单号、按渠道的筛选成为可能。反过来,如果只加了 trace 却没有业务属性,链路图看着漂亮,实际问题来了还是定位不到具体哪类订单。

Collector 是整个方案里最值钱的一层

很多团队省掉 Collector,让应用直连后端。这在服务数量超过十个之后一定会出问题:每个服务都要配一遍导出地址、采样率、批处理参数,换后端等于全量改配置。Collector 的价值在于把"采集"和"发送"解耦:

receivers:
  otlp:
    protocols:
      grpc: {endpoint: 0.0.0.0:4317}
processors:
  batch: {}
  memory_limiter:
    check_interval: 1s
    limit_percentage: 75
  tail_sampling:
    decision_wait: 10s
    policies:
      - name: errors
        type: status_code
        status_code: {status_codes: [ERROR]}
      - name: slow
        type: latency
        latency: {threshold_ms: 500}
exporters:
  prometheus:
    endpoint: 0.0.0.0:8889
  otlphttp/logs:
    endpoint: https://lts.example.com/v3/ingest
service:
  pipelines:
    traces: {receivers: [otlp], processors: [memory_limiter, tail_sampling, batch], exporters: [otlphttp/logs]}

注意 tail_sampling:它要等整条 trace 结束才能判断,所以必须先于 batch 且 decision_wait 不能太短。这个位置放错,采样策略会静默失效——日志里不报错,只是错误链路莫名其妙被丢掉了。我们踩过一次,花了半天才定位到是 processor 顺序问题。

指标:黄金信号 + 严格控基数

指标最容易失控的不是数量,是标签。曾经有同事给 HTTP 指标加了 user_id 标签,一天之内 Prometheus 内存翻了三倍。经验是:任何可能取值为高基数的字段(用户 ID、订单号、URL 全路径、错误堆栈)一律不进标签,需要就用日志或 trace 去查。

真正值得建的指标就四类,对应四个黄金信号:延迟(P50/P95/P99 直方图)、流量(QPS)、错误(按状态码分组)、饱和度(线程池队列、连接池使用率、GC 停顿)。这四类做扎实,比堆几十个自定义指标有用得多。

面板:从"总览"一路下钻到"某一条 trace"

Grafana 上我们只做了一个主面板,纵向四段:顶部是服务级 QPS 与错误率折线;第二段是 P99 延迟热力图,能一眼看出是哪个时间窗异常;第三段是错误码分布,点某个错误码会带上时间范围跳转到日志查询;第四段是慢链路 Top N,点进去直接是 trace 详情。

关键是所有面板共享同一个时间范围和同一个变量(服务名、环境),点图下钻时筛选条件自动带上。这一步做完,值班同事的动作从"开五个页面找"变成"点三下",平均定位时间从半小时降到五分钟以内。

四个真实的坑

一是时钟漂移。容器节点之间差几秒,链路时间线就会错位,看着像"子调用早于父调用"。上线前统一开 NTP,并且在面板上标注时区。

二是日志没带 trace ID。日志和链路各自独立采集,如果没有把 trace ID 打进日志的 MDC,前面所有工作等于白做。改造成本很低,一行日志格式加 %X{trace_id} 就够。

三是采样率一刀切。开发环境 100% 采样没问题,生产环境按 10% 头部采样会漏掉长尾错误。用尾部采样按"错误 + 慢请求"保留,正常流量再降采样,成本能降一半以上而关键信息不丢。

四是把可观测性当成上线后再补的事。服务已经跑了半年再回头加埋点,业务属性往往补不全。新服务从第一天就带 trace 上下文,成本几乎为零。

小结

可观测性不是买几个产品,而是让三类数据共享一个锚点。落地顺序建议是:先上 Agent 自动埋点拿到链路骨架,再用 Collector 统一出口并配好尾部采样,然后把指标标签收紧到黄金信号,最后做一块能下钻的面板。这套东西不需要大改架构,一个服务半天能改完,但收益是长期的——故障来的时候,你不用再靠猜。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。