2. 数据模型与语义约定:Span、Metric、Log 的数据结构,Resource 与 Attribute,语义约定规范

在 OpenTelemetry 体系中,数据模型定义了可观测性数据的标准结构,而语义约定则规定了如何命名和描述这些数据。理解这两者是进行高效数据传输与性能调优的基础。本章将深入剖析 Span、Metric、Log 三大信号的数据结构,解析 Resource 与 Attribute 的关联关系,并梳理关键的语义约定规范。

2.1 三大信号的数据结构

OpenTelemetry 将可观测性数据抽象为三种核心信号:Traces(追踪)、Metrics(指标) 和 Logs(日志)。每种信号都有其特定的数据结构,用于承载不同的信息维度。

2.1.1 Span 数据结构

Span 是 Trace 的基本构建块,代表一个工作单元。其核心数据结构包含以下字段:

字段 类型 描述
TraceId 16 字节数组 全局唯一标识一条完整的 Trace 链路。
SpanId 8 字节数组 唯一标识当前 Span。
ParentSpanId 8 字节数组 父 Span 的 ID,用于构建 Span 之间的父子关系。
Name 字符串 Span 的描述性名称,例如 HTTP GET /api/users。
Kind 枚举 Span 的角色:CLIENT、SERVER、INTERNAL、PRODUCER、CONSUMER。
StartTime 时间戳 Span 开始的时间。
EndTime 时间戳 Span 结束的时间。
Status 对象 执行结果:Unset、Ok、Error,并附带描述信息。
Attributes 键值对列表 附加的元数据,如 HTTP 状态码、数据库语句等。
Events 事件列表 Span 生命周期内发生的带时间戳的注解事件。
Links 链接列表 关联到其他 Trace 中的 Span,用于跨系统关联。
Resource 对象 描述生成此 Span 的资源实体(如主机、容器、服务)。
性能调优要点: Span 的 Attributes 和 Events 是数据量的主要来源。在生产环境中,应避免添加高基数(High Cardinality)的 Attribute(如用户 ID、Session ID),这会显著增加存储和传输开销。建议将高基数数据通过 Log 或单独的事件系统传递。

2.1.2 Metric 数据结构

Metric 用于聚合和测量系统行为。OpenTelemetry 定义了三种主要的 Metric 类型,每种都有其特定的数据结构:

  • Counter(计数器):只增不减的累加值,用于记录请求总数、错误次数等。
  • Histogram(直方图):对观测值进行采样并分桶统计,用于计算请求延迟的 P50、P99 等。
  • Gauge(仪表盘):可任意增减的瞬时值,用于记录当前内存使用量、CPU 利用率等。

所有 Metric 共享以下核心字段:

字段 类型 描述
Name 字符串 指标名称,遵循语义约定,如 http.server.request.duration。
Description 字符串 指标含义的简要说明。
Unit 字符串 单位,如 ms、bytes、count。
Attributes 键值对列表 描述指标的维度,如 http.method、http.status_code。
Data Points 数据点列表 包含时间戳和具体数值(Counter 为 AsDouble,Histogram 为桶和计数,Gauge 为瞬时值)。
Resource 对象 描述生成此 Metric 的资源实体。
最佳实践: 对于 Histogram,合理设置桶边界(Bucket Boundaries)至关重要。桶边界过密会增加数据量,过疏则影响百分位计算的精度。建议根据业务场景的典型延迟分布来动态调整桶边界。

2.1.3 Log 数据结构

Log 是带时间戳的文本记录,用于记录离散事件。OpenTelemetry 的 Log 数据模型旨在与现有日志标准(如 Syslog、JSON 格式)兼容,并统一纳入可观测性体系。

字段 类型 描述
Timestamp 时间戳 日志事件发生的时间。
ObservedTimestamp 时间戳 日志被观测系统捕获的时间。
SeverityText 字符串 严重程度的文本表示,如 ERROR、WARN。
SeverityNumber 整数 严重程度的数值表示,便于排序和过滤。
Body 任意类型 日志的正文内容,可以是字符串、结构化 JSON 等。
Attributes 键值对列表 附加的结构化上下文信息。
TraceId 16 字节数组 关联的 Trace ID,实现 Log 与 Trace 的关联。
SpanId 8 字节数组 关联的 Span ID,实现 Log 与 Span 的关联。
Resource 对象 描述生成此 Log 的资源实体。
注意: 日志的 Body 字段如果包含大量非结构化文本,会显著增加传输和存储成本。建议优先使用结构化日志,将关键信息提取到 Attributes 中,Body 仅保留核心消息。

2.2 Resource 与 Attribute

Resource 和 Attribute 是 OpenTelemetry 数据模型中两个关键的元数据概念,它们共同为数据提供丰富的上下文。

  • Resource(资源):描述生成可观测性数据的实体,通常是基础设施或服务实例。它是全局的,附加到该资源产生的所有 Span、Metric 和 Log 上。例如,一个 Kubernetes Pod 的 Resource 可能包含 service.name、k8s.pod.uid、host.name。
  • Attribute(属性):附加到单个数据点(如一个 Span、一个 Metric 数据点、一条 Log)上的键值对,用于描述该数据点的具体特征。例如,一个 HTTP 请求 Span 的 Attribute 可能包含 http.method、http.url。

两者的关系是:Resource 提供全局上下文,Attribute 提供局部上下文。在数据传输和存储时,Resource 信息通常会被压缩或共享,以减少冗余。

性能调优要点: 合理划分 Resource 和 Attribute 的职责。将变化频率低、范围广的信息(如集群名称、区域)放在 Resource 中;将变化频率高、范围窄的信息(如请求 ID、用户 IP)放在 Attribute 中。这有助于后端系统进行高效的数据分片和索引。

2.3 语义约定规范

语义约定(Semantic Conventions)是 OpenTelemetry 社区定义的命名规范,旨在确保不同服务和工具生成的数据具有一致的语义,从而实现互操作性。它涵盖了命名空间、属性名称、指标名称和日志字段的标准化。

2.3.1 命名空间与属性命名

语义约定采用点分隔的命名空间,例如:

  • http:用于 HTTP 相关的属性,如 http.method、http.status_code。
  • db:用于数据库相关的属性,如 db.system、db.statement。
  • messaging:用于消息系统相关的属性,如 messaging.system、messaging.destination。

属性名称使用小写字母和下划线,例如 http.request.method、server.address。

2.3.2 关键语义约定示例

以下是一些常用的语义约定示例:

信号 命名空间 属性示例 描述
Trace http http.request.method HTTP 请求方法,如 GET、POST。
Trace http http.response.status_code HTTP 响应状态码,如 200、404。
Metric http http.server.request.duration HTTP 服务端请求延迟指标。
Metric db db.client.connections.usage 数据库客户端连接使用率指标。
Log log log.severity 日志严重程度。
Resource service service.name 服务名称。
Resource host host.name 主机名。

2.3.3 遵循语义约定的好处

  • 互操作性:不同语言、不同框架的组件可以无缝集成。
  • 可分析性:后端分析工具(如 Jaeger、Prometheus)可以基于标准属性进行自动关联和可视化。
  • 可维护性:团队之间可以共享通用的查询和告警规则。
实践建议: 在开发自定义 Instrumentation 时,务必查阅最新的 OpenTelemetry 语义约定文档。优先使用标准属性,仅在标准属性无法满足需求时,才使用自定义属性(建议使用 mycompany.* 前缀以避免冲突)。

2.4 数据模型与语义约定关系图

下图展示了 Span、Metric、Log 三大信号如何通过 Resource 和 Attribute 进行关联,并遵循统一的语义约定规范。

OpenTelemetry 数据模型与语义约定关系图 Traces (Span) 工作单元,链路追踪 TraceId, SpanId, Name, Kind Metrics 聚合测量,性能指标 Counter, Histogram, Gauge Logs 离散事件,文本记录 Timestamp, Body, Severity Attribute(属性) 键值对,描述数据点特征(如 http.method, db.statement) Resource(资源) 描述实体(如 service.name, host.name, k8s.pod.uid) 语义约定规范(Semantic Conventions)

2.5 数据传输与性能调优要点

理解数据模型和语义约定后,可以从以下角度进行性能调优:

  1. 减少 Attribute 数量:每个 Span/Metric/Log 携带的 Attribute 数量直接影响序列化和传输开销。建议将每个数据点的 Attribute 数量控制在 10 个以内。
  2. 避免高基数 Attribute:如 user.id、session.id 等取值无限的 Attribute 会导致后端存储索引膨胀,查询性能下降。应将其通过 Log 或独立的事件系统传递。
  3. 利用 Resource 压缩:由于 Resource 是全局共享的,传输协议(如 OTLP)会对其进行压缩,避免重复传输。确保将公共信息放在 Resource 中。
  4. 遵循语义约定:使用标准属性名称可以触发后端系统的自动优化路径(如自动索引、预聚合),避免因自定义属性导致的额外处理开销。
  5. 采样策略:对于 Trace,结合语义约定中的 http.status_code 等属性,实现基于错误或延迟的智能采样,减少不必要的数据传输。
总结: 数据模型是 OpenTelemetry 的骨架,语义约定是血肉。只有深刻理解 Span、Metric、Log 的结构,合理运用 Resource 和 Attribute,并严格遵循语义约定,才能构建出高性能、可互操作的可观测性体系。在后续章节中,我们将深入探讨如何通过 SDK 配置和协议优化来进一步提升数据传输效率。