用 OpenTelemetry 自动埋点,不改业务代码即可接入链路追踪。本文以 Java、Python 为例给出完整配置,覆盖生产采样、容器化部署,附验证步骤与常见问题排查。
分布式链路追踪最大的阻力不是技术,是埋点成本。手动在业务代码里加 span,要改代码、要评审、要回归,很多团队卡在这一步就放弃了。OpenTelemetry 的自动埋点(auto-instrumentation)把这件事做到了"不改一行代码"。
自动埋点的原理是运行时注入:Java 靠 Agent 在类加载时改写字节码,Python 靠 monkey patch 替换标准库和框架的调用入口。它拦截的是中间件和客户端的边界,而不是你的业务逻辑,所以对代码零侵入,同时还能拿到跨进程的 trace 上下文。
本文假设你已经有炬鲸 OBSERVE 的接入地址和 token,没有的话先到控制台的"接入向导"里创建一个项目。
自动埋点靠的是 Java Agent。下载 OTel Java Agent 的 jar 包,然后在启动命令里加一行:
java -javaagent:/opt/otel/opentelemetry-javaagent.jar -Dotel.service.name=order-service -Dotel.traces.exporter=otlp -Dotel.exporter.otlp.endpoint=https://otlp.jjhub.cn:4317 -Dotel.exporter.otlp.headers="Authorization=Bearer <token>" -jar app.jar
四个参数说清楚:service.name 是服务名,用于在链路拓扑里分组;traces.exporter 指定导出器;otlp.endpoint 指向 OBSERVE 的 OTLP 接收端;headers 带上鉴权。Agent 会拦截 Spring MVC、MySQL 驱动、Redis、Kafka、HTTP Client 等常见组件的调用,自动生成 span。
原理一致,只是载体不同:
go.opentelemetry.io/contrib/instrumentation 里现成的中间件包,net/http、gin、gRPC 都有,改一行 import 即可。opentelemetry-instrument 命令启动,Flask、Django、Celery 等框架零改动。@opentelemetry/auto-instrumentations-node 一行 require 搞定。以 Python 为例:
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
OTEL_SERVICE_NAME=user-service OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.jjhub.cn:4317 opentelemetry-instrument python app.py
自动埋点默认全量采集,直接上生产会带来两笔开销:一是 span 数据量暴增、存储成本上升;二是部分高频组件(如每次 DB 查询都打 span)会拖慢请求。建议两件事一起做:
调采样率。在 Agent 参数里加:
-Dotel.traces.sampler=parentbased_traceidratio -Dotel.traces.sampler.arg=0.1
上面是保留 10% 的链路。父 span 被采样的请求,整条链路都保留,不会出现"半条链路"。
容器化部署。Kubernetes 环境里推荐用 initContainer 把 Agent jar 挂进 Pod,而不是打进镜像,升级 Agent 不用重新构建镜像。核心是加一个共享 volume,把 agent 目录挂到主容器的 /opt/otel。
链路通了之后,建议顺便把日志和指标也走 OTel 协议统一上报,避免链路、日志、指标各用一套采集器。以 Java Agent 为例,加两个参数:
-Dotel.logs.exporter=otlp -Dotel.metrics.exporter=otlp
加上之后,同一份 Agent 同时上报三种信号,service.name 保持一致,在 OBSERVE 里点开一个 span 就能直接跳到对应的日志和指标面板,排查时不用在三套系统之间来回切换。
接上不代表生效,按这三步确认:
四个高频问题。一是 exporter 版本和 OTLP 协议不匹配,报 unimplemented,把 endpoint 从 4318(HTTP)换成 4317(gRPC)或反过来试试。二是容器里忘了把 OTLP 端口在防火墙、安全组放通。三是 service.name 没设,所有服务都叫 unknown_service,拓扑图会挤成一团。四是主机时间不同步,跨服务的 span 时间轴错乱、父子关系看起来"倒挂"——分布式链路对时钟很敏感,所有主机务必用 NTP 校时。
自动埋点覆盖不到的私有协议或自研 RPC,再用手动埋点补齐即可。先自动、后手动,这个顺序能让你在第一天就看到完整链路。