资源和实体
建模指南
要定义一个实体,请创建一个新的语义约定模型文件,其组类型为entity,例如:
model/{my_domain}/entities.yaml:
groups:
- id: entity.my_entity
type: entity
stability: development
name: my_entity
brief: >
A description of my_entity here.
attributes:
- ref: some.attribute
role: identifying
- ref: some.other_attribute
role: descriptive
...
在此,attributes 字段包含实体的所有属性。每个属性的role决定了它是标识性还是描述性的。有关这些含义的详细信息,请参阅如何定义标识属性?。
注意:目前尚不支持声明实体关系。
声明信号之间的关联
您可以声明哪些实体应与特定的可观察性信号一起使用。例如,进程指标应与进程实体一起使用,以便指标与已知进程相关联。要声明此项,请在信号上使用entity_associations字段,并按名称引用另一个资源组。
model/{my_domain}/metrics.yaml:
groups:
- id: metric.some_metric
type: metric
...
entity_associations:
- my_entity
注意
- 您不能从稳定信号对不稳定资源声明关联。
- 您可以声明多个关联。这些形成一个“一或多”的集合,其中一个或多个命名实体可以与指标相关联。没有要求一个信号只附加一个实体。
扩展实体
虽然不推荐在语义约定中使用,但您可以定义一个实体的“新视图”,其中包含附加的描述性属性。要做到这一点,请在组上使用extends字段。
model/{my_other_domain}/entities.yaml:
groups:
- id: entity.my_entity_2
type: entity
extends: entity.my_entity
attributes:
- ref: new.attribute.name
requirement_level: opt_in
role: descriptive
注意
- 您不能更改新实体的
name或type字段。 - 您不能更改标识属性集。
常见问题
何时定义新实体?
应定义实体的两种情况:
- 当您正在生成新的信号(日志、指标、span 等),并且没有现有实体可以作为“源”。
- (未来)当您需要描述某个记录系统中的实体层次结构时(例如,Kubernetes 中的资源,云中的资产)。
例如,如果定义了一个新的集群解决方案(例如 HashiCorp 的 Nomad),而现有的基于容器的实体不足以满足需求,则应定义新实体。
什么是“is-a”关系?
OpenTelemetry 作为一个开放的生态系统,无法理解和建模世界上所有可能的实体。相反,我们允许跨域进行重叠定义。例如,存在container和k8s.container实体,并且通常每个k8s.container都是一个container,但并非所有container都在 Kubernetes 中运行。
“is-a”关系表示一个实体正在描述另一个实体所描述的完全相同的系统组件,但来自不同的域。在上面的例子中,k8s.container对 Kubernetes 域中的容器进行建模,而container是对容器的通用模型,无论它们如何运行(例如,Podman、Docker、Kubernetes、FAAS 等)。
“is-a”关系在实体中表示这种关系,允许 OpenTelemetry 完全建模实体子集(例如,所有已知的k8s资源作为实体),同时仍允许扩展的生态系统随着新实体的出现而增长和发展。
何时定义“is-a”关系而不是扩展描述性属性?
有两个关键规则:
- 默认情况下,引入具有清晰的“is a”(或类似)关系的单独实体。
- 仅当以下条件满足时,才扩展实体以添加新的描述性属性:
- 扩展实体本身不能与任何遥测数据相关联。
- 示例 1:添加
windows.process实体时,您不期望创建任何特定于windows.process的进程指标或日志,而是所有数据仍针对process实体报告。 - 示例 2:添加
docker.container实体时,您不期望创建任何特定的容器信号,而是日志、指标和 span 将针对container实体报告。
- 示例 1:添加
- 扩展实体没有其他可以逻辑上只与其关联的实体。注意:这仅适用于具有关系的实体。
- 扩展实体本身不能与任何遥测数据相关联。
这可以避免子类型化和属性使用模糊性带来的复杂性。
如何定义标识属性?
标识属性应尽可能少地足以在发现该实体的上下文内识别该实体。例如,在发现 Kubernetes 实体(如k8s.pod、k8s.deployment)时,标识属性应足以在 Kubernetes 集群范围内(或更具体地说,在实体发现所在的 Kubernetes API 服务器)识别这些实体。
通常,遥测生产者可以轻松地获得实体的多个可用属性来组合身份。在可用的属性中,实体 ID 应包括足以唯一标识该实体的最少属性集。例如,主机上的进程可以通过(process.pid、process.creation.time)属性唯一标识。添加例如process.executable.name属性到身份是不必要的,并且违反了具有最小充分 ID的规则。
标识属性通常构成了实体的生命周期。这对于写入实体的指标尤其重要。生命周期决定了时间序列在报告点之间是否保持“连接”,或者是否突然出现下降。建议选择一个身份,以保持对重要警报和监控用例的“稳定”生命周期。
在实体的生命周期内,标识属性*不得*更改。
多观察者指南
选择标识属性时,应注意确保多个观察者能够为同一个实体找到相同的标识属性。通常,实体可以在 OpenTelemetry SDK 和 Collector 中被发现,并应利用这些信号提供者之间相同的标识属性。
例如,service.instance.id在 SDK 外部和内部一致检测可能会有问题。通常,只有当某个外部源将service.instance.id值注入到 SDK 中并且该值可从外部看到时,才能实现这一点。另一种方法是让 SDK 提供service.instance.id与另一个外部可见的实体之间的关系。在建模实体时应谨慎,以尽可能避免此问题。
对于大多数建模的实体,service.instance.id的选择应该是例外,而不是规则。服务实例化是 OpenTelemetry 的一个基本功能,我们认为它是一个关键的“后备”身份。当有一个生成器共享所有观察者时,它效果最好。然而,在实践中,这在以下情况下是困难的或“非标准的”:
- Prometheus 拉取指标,它希望
instance标签与基于推送的 OTLP 数据上的service.instance.id匹配。 - 读取来自
k8s.node的容器日志,其中我们知道容器名称和部署,但无法查看 SDK 以了解所选的实例 ID。
OpenTelemetry Operator 以及 Kubernetes 的入门指南,例如,利用机制来确保service.instance.id可以向下推送到 SDK 和外部观察者,从而缓解 Kubernetes 的这种摩擦。
如何为实体创建命名空间?
实体(类型和属性)应围绕用于标识实体的首选机制进行命名空间。例如,Kubernetes 实体使用k8s命名空间,并且主要通过 Kubernetes API 或在 Kubernetes 中工作来发现。
有关整体语义约定命名空间规则,请参阅通用命名指南。
背景:资源和实体
在 OpenTelemetry 中,每个信号都与一个资源相关联。根据规范,这是:
资源是对生成遥测数据的实体的表示。在 OpenTelemetry 中,所有信号都与一个资源相关联,从而能够从同一源对数据进行上下文关联。例如,如果我在 span 中看到高延迟,我需要在观察到延迟时检查产生该 span 的相同实体的指标。
资源为可观察性提供了两个重要方面:
- 它*必须*识别生成遥测数据的实体。
- 它*应该*允许用户确定该实体位于其基础设施的何处。
所有资源都由实体组成。实体被指定为:
实体代表与生成的遥测数据相关的对象:跟踪、指标、日志、配置文件等。
虽然实体和资源的定义存在重叠,但两者之间有几个关键区别:
- 实体具有已知的“类型”,例如
service、k8s.pod、host等。 - 实体可以区分*标识*属性和*描述性*属性。
- 标识属性可用于在某个系统中识别实体(请参阅最小充分 ID)。例如,
k8s.pod.uid将被视为 Kubernetes 中 Pod 的标识属性。 - 描述性属性可用于为实体提供其他标签,但不是唯一标识实体的必要条件。
- 标识属性可用于在某个系统中识别实体(请参阅最小充分 ID)。例如,
- 资源由*多个*实体组成。
- 资源中的每个实体都被认为“贡献”了该遥测数据。
- 例如,今天,大多数 SDK 都包含服务实体,但也包含另一个实体,如
k8s.container、host等。
- 实体可能在概念上与其他实体相似(我们称之为“is-a”关系)。
- 例如,
k8s.cluster实体通用地表示 Kubernetes 集群,而aws.eks.cluster实体将表示 AWS 特定概念的 Elastic Kubernetes 集群。 - 在这种情况下,来自 EKS 的资源可以同时包含
aws.eks.cluster实体和k8s.cluster实体。
- 例如,
对于 OpenTelemetry 中的实体和资源,有两个关键原则很重要:
- 开放扩展:允许 OpenTelemetry 外部的用户在系统中提供实体定义和关系。
- 望远镜式身份:允许对可观察性数据进行灵活的反规范化,以优化关键查询(例如,警报、仪表板等)。
开放扩展
OpenTelemetry 被设计为一个开放系统。在定义系统中的核心实体和关系集时,它需要保持对这些实体和可能的关系的开放性。任何用户拥有的系统都应能够与现有的 OpenTelemetry 语义约定进行建模和参与。这通过两个关键方面实现:
- 命名空间
- “is-a”关系
在 OpenTelemetry 语义约定中定义一套新的实体时,它们应该按照语义约定命名策略进行命名空间化。这清楚地表明了哪些概念彼此明确相关。例如,k8s 命名空间将定义与 Kubernetes 相关的实体及其关系。用户会知道在 Kubernetes 之上建模概念时创建一个新的命名空间。
对现有概念的扩展通过“is-a”关系进行。这些关系是指一个实体被认为代表另一个实体所代表的相同概念,但位于某个新的作用域上下文中。例如,aws.eks.cluster是k8s.cluster,但并非所有k8s.cluster实体都是aws.eks.cluster实体。
望远镜式身份
在 OpenTelemetry 中,我们希望为用户提供灵活性,让他们决定*随*可观察性信号发送哪些信息,以及哪些信息可以稍后加入。我们称之为“望远镜式身份”,用户可以决定在网络上传输的 OpenTelemetry 资源的*大小*(相应地,根据存储解决方案,数据点在存储时可能的大小)。
例如,在极端情况下,OpenTelemetry 可以为每个生成遥测数据的系统合成一个 UUID。资源和实体的所有标识属性都可以通过侧信道发送,并与此 UUID 具有已知关系。虽然这可以优化遥测数据的运行时生成和发送,但其代价是下游存储系统需要在摄取时或查询时将数据连接回。对于高性能用例(例如警报),这些连接可能会很昂贵。
在实践中,用户通过 SDK 和 Collector 中的资源检测配置来控制资源身份。希望最小化身份的用户可能会将资源检测限制为仅service.instance.id。一些用户高度定制资源检测,并附加了许多概念。
OpenTelemetry 应提供一套良好的“开箱即用”的资源检测,为大多数用户做出适当的反规范化权衡,但允许用户微调系统以满足他们的需求。