2. OpenTelemetry 核心概念:信号、跨度、链路、上下文、资源与插桩
在深入值班机器人的链路追踪与告警聚合设计之前,必须建立对 OpenTelemetry 核心数据模型的统一认知。这六个概念构成了可观测性数据的骨架,理解它们之间的层次关系是后续实现分布式追踪、指标采集和日志关联的基础。
2.1 六大核心概念总览
OpenTelemetry 将可观测性数据抽象为 Signal(信号),而每个信号的具体承载单元则通过 Span(跨度)、Trace(链路)、Context(上下文)、Resource(资源) 和 Instrumentation(插桩) 来定义和传递。下表从定义、作用与典型场景三个维度进行对比:
| 概念 | 定义 | 核心作用 | 值班机器人场景示例 |
|---|---|---|---|
| Signal(信号) | 可观测性数据的三大类别:Traces、Metrics、Logs | 区分数据类型,决定采集与处理方式 | 告警触发时同时产生 Trace 和 Metric 信号 |
| Span(跨度) | 一次操作的最小记录单元,包含名称、时间、属性、状态 | 记录单个操作的耗时与元数据 | “查询告警规则”是一个 Span |
| Trace(链路) | 由多个 Span 组成的树状结构,代表一次完整请求 | 串联跨服务的调用路径 | 从“接收告警”到“发送通知”的完整流程 |
| Context(上下文) | 携带 Trace ID、Span ID 等传播信息的对象 | 跨进程传递追踪状态 | HTTP 头中传递 traceparent |
| Resource(资源) | 描述产生数据的实体属性(服务名、版本、主机) | 标识数据来源,支持多维过滤 | service.name="值班机器人", host.id="node-01" |
| Instrumentation(插桩) | 自动或手动在代码中嵌入观测代码的机制 | 降低接入成本,标准化数据采集 | 通过装饰器自动追踪每个 API 端点 |
2.2 Signal(信号)—— 可观测性的三大支柱
OpenTelemetry 将可观测性数据统一为三种信号类型,值班机器人在运行时需要同时处理这三种信号才能实现完整的告警聚合分析:
- Traces(链路):记录请求在分布式系统中的完整路径,用于定位故障点。
- Metrics(指标):聚合后的数值数据,如告警延迟 P99、通知成功率。
- Logs(日志):带时间戳的文本记录,用于补充链路和指标的细节。
2.3 Span(跨度)与 Trace(链路)
Span 是链路追踪的最小工作单元,而 Trace 是由多个 Span 组成的树状结构。每个 Span 必须包含以下关键字段:
| 字段 | 说明 | 值班机器人示例值 |
|---|---|---|
| Span ID | 16 字节唯一标识 | a1b2c3d4e5f6g7h8 |
| Trace ID | 32 字节全局唯一标识 | 0af7651916cd43dd8448eb211c80319c |
| Parent Span ID | 父 Span 的 ID,根 Span 为空 | null 或 9i8h7g6f5e4d3c2b |
| Name | 操作名称 | process_alert |
| Start / End Time | 纳秒级时间戳 | 1710000000000000000 |
| Status | Unset / Ok / Error | Error(告警处理失败时) |
| Attributes | 键值对元数据 | alert_id=123, severity=critical |
下面通过一个内联 SVG 展示值班机器人处理一次告警时,Span 与 Trace 的树状关系:
2.4 Context(上下文)—— 跨进程传播的纽带
Context 是 OpenTelemetry 实现分布式追踪的核心机制。它通过 W3C Trace Context 标准协议,在服务之间传递追踪状态。Context 主要包含两个关键字段:
- traceparent:格式为
00-{trace_id}-{span_id}-{trace_flags},例如00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01。 - tracestate:用于携带厂商自定义的键值对,例如
vendor=otel,tenant=prod。
2.5 Resource(资源)—— 数据来源的身份证
Resource 用于描述产生可观测性数据的实体,通常包含服务名称、版本、主机信息、云环境等。OpenTelemetry 定义了标准的资源语义约定:
| 资源属性 | 说明 | 值班机器人示例 |
|---|---|---|
service.name |
服务名称 | alert-bot |
service.version |
服务版本 | 2.1.0 |
host.id |
主机唯一标识 | i-0abcd1234efgh5678 |
deployment.environment |
部署环境 | production |
cloud.region |
云区域 | cn-north-1 |
Resource 在告警聚合中的价值在于:当多个值班机器人实例同时运行时,可以通过 Resource 属性区分不同实例产生的数据,实现按服务、环境或主机维度的告警聚合分析。
2.6 Instrumentation(插桩)—— 自动化观测的入口
Instrumentation 是 OpenTelemetry 提供的标准化接入方式,分为 自动插桩 和 手动插桩 两种模式。在值班机器人项目中,推荐采用混合策略:
- 自动插桩:通过 Python Agent 或库的自动补丁(monkey-patch)拦截 HTTP 请求、数据库调用、消息队列等常见操作,零代码生成基础 Span。
- 手动插桩:在关键业务逻辑(如告警规则匹配、通知发送策略)中显式创建 Span,添加业务属性,实现精细化追踪。
下面通过一个内联 SVG 展示自动插桩与手动插桩在值班机器人中的协作关系:
2.7 核心概念在值班机器人中的协作流程
为了更直观地理解这六个概念如何协同工作,下面给出一个完整的 Python 代码示例,展示值班机器人在处理告警时如何创建 Span、传递 Context 并附加 Resource:
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# 1. 定义 Resource(资源)
resource = Resource.create({
"service.name": "alert-bot",
"service.version": "2.1.0",
"deployment.environment": "production"
})
# 2. 配置 TracerProvider
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4317"))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
# 3. 手动插桩:创建根 Span
with tracer.start_as_current_span("handle_alert") as root_span:
root_span.set_attribute("alert_id", "alert-12345")
root_span.set_attribute("severity", "critical")
# 自动插桩会在此 Span 下自动创建 HTTP 子 Span
# 手动插桩:创建业务子 Span
with tracer.start_as_current_span("query_alert_rules") as child_span:
child_span.set_attribute("rule_count", 5)
# 执行数据库查询(自动插桩会拦截)
with tracer.start_as_current_span("send_notification") as child_span2:
child_span2.set_attribute("channel", "wechat")
# 调用通知 API(自动插桩会拦截并传递 Context)
# 4. 模拟错误场景
root_span.set_status(trace.Status(trace.StatusCode.ERROR, "通知发送超时"))
set_status 会导致错误 Span 无法被正确识别;Resource 属性必须在 TracerProvider 初始化时设置,后续无法修改;Context 传递依赖 HTTP 头或 gRPC 元数据,如果使用异步消息队列(如 Kafka),需要手动注入和提取 Context。