4、必选Tag清单(上):span.kind、service.name、operation.name的定义与使用场景

在 Jaeger 的 Span 标签体系中,必选 Tag 是构成一条可观测数据的最小骨架。缺少其中任何一个,链路都无法被正确索引、聚合或展示。本章聚焦三个最核心的必选标签:span.kind、service.name 与 operation.name,深入剖析其定义、取值规范及典型使用场景。

4.1 三标签全景:链路数据的“身份证”

这三个标签共同决定了 Span 在分布式追踪中的“身份”与“位置”:

标签名 语义 作用域 是否可空
span.kind Span 的角色类型(客户端/服务端/内部等) 单个 Span 否
service.name 产生该 Span 的微服务名称 进程级(通常由 Tracer 自动注入) 否
operation.name Span 代表的具体操作(如 HTTP 路由、RPC 方法) 单个 Span 否
规范要点: 这三个标签必须在 Span 创建时立即赋值,不允许延迟注入或留空。Jaeger UI 的“服务”下拉框、拓扑图节点、Trace 列表页均依赖 service.name 进行聚合。

4.2 span.kind:定义 Span 的通信角色

span.kind 描述了 Span 在分布式调用中所扮演的通信角色。OpenTelemetry 规范定义了以下五种取值:

  • CLIENT — 发起请求的一方(如 HTTP 客户端、gRPC 调用方)
  • SERVER — 接收请求并处理的一方(如 HTTP 服务端、gRPC 处理器)
  • PRODUCER — 消息队列中的生产者(如 Kafka 发布者)
  • CONSUMER — 消息队列中的消费者(如 Kafka 订阅者)
  • INTERNAL — 内部操作,不涉及跨进程通信(如本地函数调用、定时任务)

以下 SVG 展示了在一次典型 HTTP 调用中,span.kind 如何标识不同角色的 Span:

span.kind 角色标识示例 span.kind 角色标识示例 CLIENT HTTP 客户端 SERVER HTTP 服务端 INTERNAL 本地业务逻辑 关键规则 CLIENT 与 SERVER 必须成对出现,构成一次完整的 RPC 调用。 INTERNAL 不产生网络通信,通常用于函数级追踪。 PRODUCER / CONSUMER 用于异步消息场景,需配合消息上下文传播。
避坑指南: 不要将 span.kind 设置为 CLIENT 或 SERVER 后却未实现对应的网络传播上下文。例如,一个标记为 SERVER 的 Span 必须从上游提取 traceparent 或 uber-trace-id,否则链路将断裂。

4.3 service.name:微服务的“身份证号”

service.name 是 Jaeger 数据模型中最高层级的聚合键。它通常由 Tracer 初始化时通过 --jaeger-agent 参数或环境变量 JAEGER_SERVICE_NAME 注入,不应在单个 Span 中手动覆盖。

注入方式 示例 优先级
环境变量 JAEGER_SERVICE_NAME=order-service 最高
代码配置 new Configuration("order-service") 中
启动参数 --jaeger.service.name=order-service 低
命名规范: 使用小写字母 + 连字符(kebab-case),如 payment-api、user-srv。禁止包含空格、下划线或中文,否则 Jaeger UI 的拓扑图可能出现乱码或聚合异常。

4.4 operation.name:Span 的“操作名片”

operation.name 描述 Span 代表的具体操作。它必须具有可读性和可聚合性,通常采用 HTTP_METHOD /path 或 RPC_SERVICE/METHOD 的格式。

以下表格对比了好的与差的 operation.name 命名:

场景 差的命名 好的命名 原因
HTTP GET 订单 /api/v1/orders/12345 GET /api/v1/orders/{id} 包含具体 ID 会导致每个请求生成唯一 operation.name,无法聚合
gRPC 调用 GetUserProfile user.UserService/GetProfile 应包含包名和服务名,避免不同服务间方法名冲突
数据库查询 SELECT * FROM orders WHERE id=? DB.Orders.SelectById 避免暴露完整 SQL,使用语义化简写

4.5 三标签协同:构建可搜索的 Trace 骨架

当三个标签正确赋值后,Jaeger 后端可以高效地完成以下操作:

  1. 服务拓扑构建 — 通过 service.name 聚合节点,span.kind 判断调用方向。
  2. 操作维度分析 — 在“服务”页面下,按 operation.name 展示延迟、错误率、吞吐量。
  3. 链路搜索 — 用户可在 Jaeger UI 中按 service.name + operation.name 组合过滤 Trace。

以下 SVG 展示了这三个标签在 Jaeger 数据模型中的协作关系:

三标签协作关系图 三标签协作:构建可搜索 Trace 骨架 service.name 微服务身份 span.kind 通信角色 operation.name 具体操作 聚合层级 service.name → 服务拓扑 & 服务列表 service.name + operation.name → 操作级指标 & Trace 搜索
生产建议: 在微服务框架(如 Spring Boot、Go kit)的中间件中自动注入 span.kind 和 operation.name,避免业务开发人员手动设置。例如,HTTP 框架拦截器可根据请求方法和路由模板自动生成 GET /api/v1/orders/{id}。

4.6 常见错误与排查

错误现象 根因 修复方案
Jaeger UI 服务列表为空 service.name 未设置或为空字符串 检查 Tracer 初始化配置,确保 JAEGER_SERVICE_NAME 已设置
Trace 中 Span 显示为“未知操作” operation.name 未赋值或为 null 在创建 Span 时显式调用 setOperationName()
拓扑图连线方向错误 span.kind 被错误设置为 CLIENT 或 SERVER 根据实际调用方向修正 span.kind,客户端为 CLIENT,服务端为 SERVER
同一操作产生大量不同 operation.name 使用了带具体参数的 URL 路径 使用路由模板替换具体 ID,如 /orders/{id}
复盘检查清单:
  • 每个 Span 是否都包含 span.kind?
  • service.name 是否在进程级别全局唯一且稳定?
  • operation.name 是否使用模板而非具体值?
  • 跨进程调用中,CLIENT 与 SERVER 的 span.kind 是否成对出现?