从选型理由到落地步骤:为什么用 OTel 而不是厂商 SDK、Java/Node 等自动埋点零改代码、业务逻辑内部耗时用自定义 Span 补齐、trace_id 打进日志串起追踪,附排错清单。
接入可观测系统,第一个决定是"用谁家的 SDK"。自研或绑定某家厂商的 SDK,意味着以后换后端要重写埋点。OpenTelemetry(OTel)是 CNCF 的标准项目,一套 API 打天下:埋一次点,数据可以同时发给 OBSERVE、Jaeger、Prometheus 多个后端。OBSERVE 原生支持 OTel 协议(OTLP),这是接入成本最低、也最不容易被绑死的一条路。
Java、Node、Python、Go 都有 OTel 的自动埋点 Agent,原理是字节码注入或猴子补丁,在框架的收口处(HTTP 入口、DB 驱动、消息队列客户端)自动创建 Span,应用代码一行不改。
Java 举例,启动参数加一个 javaagent:
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.exporter.otlp.endpoint=https://ob.jjhub.cn/ingest/otlp \
-Dotel.service.name=order-service \
-jar order-service.jar
起来之后,HTTP 请求、JDBC 查询、Redis 调用会自动产生 Span 并上报。先跑自动埋点,能覆盖 80% 的常见场景,剩下的 20% 是业务逻辑内部的耗时,要靠自定义 Span。
自动埋点看不到业务函数内部的耗时,比如"这个函数里有一段循环算优惠券,跑了 800ms"。这时需要手动埋点:
Span span = tracer.spanBuilder("calc-coupon")
.setAttribute("coupon.count", 5)
.startSpan();
try (Scope scope = span.makeCurrent()) {
calculateCoupons(order);
} finally {
span.end();
}
命名要有意义、能直接回答"这是什么操作",别叫 span1、span2。给 Span 加属性时,注意别把用户手机号、身份证这类敏感数据当属性打进去——属性会被存储和检索,等于把敏感数据写进了追踪库。
链路追踪和日志要串起来,最实用的做法是在日志里带上 trace_id。用 OTel 的日志桥接或直接在日志 pattern 里加 %X{trace_id}(Logback MDC),之后在 OBSERVE 里看到一条报错日志,就能用它的 trace_id 反查整条链路。
自动埋点会有性能开销,一般每请求增加 1-5% 的 CPU,网络上是每个 Span 一次小包。生产环境建议:核心服务采样率 100%(配合尾采样),边缘服务 10%-30%;Agent 用异步批量上报,避免同步阻塞业务线程。