ISSUE链接
背景
随着可观测技术的能力构建逐步完善,需要对系统采集和上报的指标和跟踪统一定义和管理,防止定义冲突、含义不清等问题,确保可观测规范持续演进和社区共建共享。
决策点
- 新增可观测跟踪定义
- 新增可观测指标定义(RPC访问、持久化管理、微组件管理、硬件管理)
- 新增可观测指标描述
整体架构/方案(可选,文字/图描述接口设计背后的整体管理架构/方案)
可观测是基于openTelemetry规范构建的可视化能力,主要围绕系统中的可观测数据(包括指标、跟踪和日志),提供采集、上报以及与多种可视化工具集成的能力,帮助用户更好的监控系统性能,预测运行趋势、分析和定位系统故障
跟踪(Trace)
跟踪是一组事件,这些事件是由单个逻辑操作触发的,并通过应用程序的各个组件处理后最终整合在一起。跟踪可能包含跨越进程、网络和安全边界的事件,因此也被称为分布式跟踪,当有人按下按钮在网站上启动一个操作时,就可能会启动分布式跟踪。
具体来说,跟踪可以被认为是跨度(Span)的有向无环图 (DAG),其中跨度之间的边定义为父子关系。例如,以下是一个由6个跨度组成的跟踪示例:
[Span A] ←←←(the root span)
|
+------+------+
| |
[Span B] [Span C] ←←←(Span C is a `child` of Span A)
| |
[Span D] +---+-------+
| |
[Span E] [Span F]
使用时间轴来显示跟踪轨迹会更容易理解,如下图所示:
––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time
[Span A···················································]
[Span B··············································]
[Span D··········································]
[Span C········································]
[Span E·······] [Span F··]
跨度的组成
- 操作名称。
- 开始和结束时间戳。
- 属性:键值对列表。
- 事件:零个或多个事件的集合,每个事件本身都是一个元组(时间戳、名称、属性)。名称必须是字符串。
- 父级跨度标识符。
- 链接:指向零个或多个因果相关的跨度的链接(通过这些相关的跨度上下文)。
- 上下文:引用跨度所需的跨度上下文(Span Context)信息。
跨度的名称
跨度的名称简洁地标识了跨度所代表的工作,例如RPC方法名称、函数名称或更大计算中的子任务或阶段的名称。
跨度的类型
- SERVER 表示跨度涵盖了服务端处理的远程请求,而客户端等待响应。
- CLIENT 表示跨度描述了一个远程服务的请求,客户端等待响应。当 CLIENT 跨度的上下文被传播时,CLIENT 跨度通常会成为远程 SERVER 跨度的父级。
- PRODUCER 表示跨度描述了本地或远程操作的启动或调度。这个启动跨度通常在相关的 CONSUMER 跨度结束之前结束,甚至可能在 CONSUMER 跨度开始之前结束。 在具有批处理的消息传递场景中,跟踪单个消息需要为每条消息创建一个新的 PRODUCER 跨度。
- CONSUMER 表示跨度代表由生产者启动的操作的处理,生产者不等待结果。
- INTERNAL 默认值。表示跨度代表应用程序内的内部操作,而不是具有远程父级或子级的操作。
指标(Metric)
指标是是对系统行为、性能或状态的量化测量,可以是任何可测量的数值,例如CPU使用率、内存占用率、请求延迟、错误率等。记录测量值主要涉及计量仪(Meter)、仪表(Instrument)和测量值(Measurement):
- 计量器(Meter):主要负责创建和管理仪表(Instrument)。
- 仪表(Instrument):具有名称、类型、描述和单位等标识,主要用于捕捉和记录测量值。
- 测量值(Measurement):单次记录的原始值,包含键值对属性标签,用于标记和区分不同场景下的测量值。
+------------------+
| MeterProvider | +-----------------+ +--------------+
| Meter A | Measurements... | | Metrics... | |
| Instrument X +-----------------> In-memory state +-------------> MetricReader |
| Instrument Y | | | | |
| Meter B | +-----------------+ +--------------+
| Instrument Z |
| ... | +-----------------+ +--------------+
| ... | Measurements... | | Metrics... | |
| ... +-----------------> In-memory state +-------------> MetricReader |
| ... | | | | |
| ... | +-----------------+ +--------------+
+------------------+
指标的组成
- 指标由元数据和数据组成。
- 元数据部分包含多个属性:
- 指标名称。
- 属性 (维度,也被称为标签)。
- 值类型(整数、浮点等)。
- 计量单位。
- 数据是计数器、仪表、直方图等类型之一。
- 数据点包含时间戳、属性和值。
指标名称
- 它们不是空字符串。
- 它们是不区分大小写的 ASCII 字符串。
- 第一个字符必须是字母。后续字符必须是字母数字字符、“_”、“.”、“-”和“/”。
- 它们的最大长度为 255 个字符。
指标名称使用约定
指标名称不应复数化。
- limit - 一种测量某种已知总量的恒定值的工具应称为 entity.limit。例如,system.memory.limit 表示系统内存的总量。
- usage - 一种测量已知总量(限制)中已使用量的工具应称为 entity.usage。例如,system.memory.usage 带有属性 state = used | cached | free |… 表示每种状态下的内存量。在适当的情况下,所有属性值的总使用量应等于限制。
对无限资源或其限制不可知的资源消耗量的测量与使用量不同。例如,一个进程可能消耗的最大虚拟内存量可能会随时间波动,通常无法得知。 - utilization - 一种测量使用量相对于其限制的比例工具应称为 entity.utilization。例如,system.memory.utilization 表示正在使用的内存比例。利用率可以是相对于固定限制或软限制的。利用率值以比率表示,通常在范围 [0, 1] 内,但在超过软限制时可能超过 1。
- time - 一种测量时间流逝的工具应称为 entity.time。例如,system.cpu.time 带有属性 state = idle | user | system |… 时间测量不一定是墙钟时间,可能小于或大于测量之间的实际墙钟时间。
时间工具是使用量指标的特殊情况,其中限制通常可以计算为所有属性值的时间总和。时间工具的利用率可以通过使用指标事件时间戳自动推导。例如,system.cpu.utilization 定义为 system.cpu.time 测量值之间的差值除以经过的时间和 CPU 数量。 - io - 一种测量双向数据流的工具应称为 entity.io,并具有方向属性。例如,system.network.io。
属性
属性是一个键值对,必须具有以下属性:
- 属性键必须是一个非空的字符串。键的大小写敏感,大小写不同的键被视为不同的键。
- 属性值可以是:
一个原始类型:字符串、布尔值、双精度浮点数(IEEE 754-1985)或带符号的 64 位整数。
一个原始类型值的数组。数组必须是同质的,即它不能包含不同类型的值。 - 属性的最大个数128。
属性名称
以otel.开头的属性名称属于OpenTelemetry规范保留定义。
名称应遵循以下规则:
- 名称应为小写。
- 使用命名空间。使用点字符分隔命名空间。例如,service.version 表示服务版本,其中 service 是命名空间,version 是该命名空间中的一个属性。
- 命名空间可以嵌套。例如,telemetry.sdk 是顶级 telemetry 命名空间中的一个命名空间,而 telemetry.sdk.name 是 telemetry.sdk 命名空间中的一个属性。
在合适的情况下使用命名空间(和点分隔符)。例如,在引入表示某个对象属性的属性时,遵循 {object}.{property} 模式。如果该对象可能有其他属性,避免使用下划线({object}_{property})。 - 对于名称中每个多词的点分隔组件,使用下划线分隔单词(即使用 snake_case)。例如,http.response.status_code 表示 http 命名空间中的状态码。
仅在点(命名空间)的使用没有意义或改变名称的语义意义时使用下划线。例如,使用 rate_limiting 而不是 rate.limiting。 - 属性、事件、指标和其他名称应具有描述性和明确性。
在引入描述对象某个属性的名称时,包含属性名称。例如,使用 file.owner.name 而不是 file.owner,以及 system.network.packet.dropped 而不是 system.network.dropped。
避免引入在不同约定或工具中使用时含义不同的名称和命名空间。例如,使用 security_rule 而不是 rule。 - 在不影响清晰度的情况下使用更短的名称。在多词组件中删除不必要的命名空间组件或单词。例如,vcs.change.id 与 vcs.repository.change.id 一样精确地描述拉取请求 ID。
详细描述(必填,描述待评审接口的详细内容)
新增可观测跟踪定义
| 类型 | 应用场景 | 关键字段 | 使用规范 | 描述 | 示例 | 备注 | |
|---|---|---|---|---|---|---|---|
| Server | 服务端处理的接口远程请求 | span.name | <app_name>.server.request.<method_name/property_name> | 以组件名开头,明确标识收到请求的组件,后面跟对应请求的资源协作接口方法或属性 | hwproxy.dbus.Read | ||
| span.attributes | client.mc.name | 必选 | 请求发起方(客户端)的名称 | hwdiscovery | |||
| rpc.dbus.path | 必选 | 资源协作路径 | |||||
| rpc.dbus.interface | 必选 | 资源协作接口 | |||||
| rpc.dbus.method | 条件必选 | 资源协作方法 | |||||
| rpc.dbus.property | 条件必选 | 资源协作属性 | |||||
| Client | 客户端发起的远程请求 | span.name | <app_name>.client.request.<method_name/property_name> | 以组件名开头,明确标识发起请求的组件,后面跟对应请求的资源协作接口方法或属性 | |||
| span.attributes | server.mc.name | 必选 | 请求接收方(服务端)的名称 | ||||
| rpc.dbus.path | 必选 | 资源协作路径 | |||||
| rpc.dbus.interface | 必选 | 资源协作接口 | |||||
| rpc.dbus.method | 条件必选 | 资源协作方法 | |||||
| rpc.dbus.property | 条件必选 | 资源协作属性 | |||||
| Producer | 本地或远程操作的启动或调度 | span.name | <app_name>.producer.signal.<signal_name> | 以组件名开头,明确标识发送信号的组件,后面跟对应请求的资源协作接口信号名称 | |||
| span.attributes | producer.dbus.path | 必选 | 资源协作路径 | ||||
| producer.dbus.interface | 必选 | 资源协作接口 | |||||
| Consumer | 生产者启动的操作的处理 | span.name | <app_name>.consumer.signal.<signal_name> | 以组件名开头,明确标识接收信号的组件,后面跟对应请求的资源协作接口方法或属性 | |||
| span.attributes | producer.dbus.path | 必选 | 资源协作路径 | ||||
| producer.dbus.interface | 必选 | 资源协作接口 | |||||
| Internal | 应用程序内的内部操作 | span.name | <app_name>.<file_name>.<method_name> <app_name>.<file_name> <app_name>.<module_name>.<method_name> |
以组件名开头,明确标识当前处理的组件;后面紧跟模块名和方法名 | 1、支持应用层不指定名称,不指定时,默认采用该名称;应用层指定名称时,应当采用<app_name>.<module_name>.<opertion_name>的格式 2、进程名称已包含在resource头中,待补充进程id |
||
| span.attributes | service.name | 必选 | 服务名称。对于C/C++语言,线程名称;lua语言,skynet服务名称 | 保留属性名,应用框架填入 | |||
| service.id | 必选 | 服务id,对于C/C++语言,线程id;lua语言,skynet服务id | 保留属性名,应用框架填入 | ||||
| file.name | 条件必选 | 文件名。应用层不指定span.name时,可以不填。 | 保留属性名,应用框架填入 | ||||
| file.method | 条件必选 | 方法名。应用层不指定span.name时,可以不填;对于匿名场景,可以不填。 | 保留属性名,应用框架填入 | ||||
| file.lineno | 必选 | 文件行号 | 保留属性名,应用框架填入 | ||||
| table.name | 持久化表名 | 必选 |
新增可观测指标定义
指标类型:Counter(计数器)、UpDownCounter(增减计数器)、Guage(仪表盘)、Histogram(直方图)
属性要求:必选、条件必选、推荐、可选
| 分类 | 指标名称 | 指标类型 | 指标单位 | 属性列表 | 属性描述 | 属性要求 | 描述 | 标准定义 |
|---|---|---|---|---|---|---|---|---|
| 硬件管理 | bmc.hw.chip.io | counter | count(次) | hw.bus.name | 硬件总线的名称 | 必选 | 硬件器件IO指标 | 否,自定义指标 |
| hw.chip.name | 硬件器件的名称 | 必选 | ||||||
| hw.operation.name | 硬件操作的名称,包括write、read | 必选 | ||||||
| hw.operation.result | 硬件操作的结果,包括success、failed | 必选 | ||||||
| bmc.hw.chip.accessor | counter | count(次) | hw.bus.name | 硬件总线的名称 | 必选 | 硬件器件访问器指标 | 否,自定义指标 | |
| hw.chip.name | 硬件器件的名称 | 必选 | ||||||
| hw.chip.accessor.name | 硬件器件的访问器名称 | 必选 | ||||||
| hw.chip.accessor.direction | 硬件器件的访问器的访问方向,包括write, read | 必选 | ||||||
| hw.chip.accessor.result | 硬件器件的访问器的访问结果,包括success、failed、emitSignal | 必选 | ||||||
| bmc.hw.chip.scanner | counter | count(次) | hw.bus.name | 硬件总线的名称 | 必选 | 硬件器件扫描器指标 | 否,自定义指标 | |
| hw.chip.name | 硬件器件的名称 | 必选 | ||||||
| hw.chip.scanner.name | 硬件器件扫描器的名称 | 必选 | ||||||
| hw.chip.scanner.result | 硬件器件扫描器的扫描结果,包括success、failed、emitSignal | 必选 | ||||||
| 微组件管理 | bmc.mc.flash.io | counter | By(字节) | mc.name | 微组件名称 | 必选 | 微组件flash IO指标 | 否,自定义指标 |
| fs.file.name | 文件名称 | 条件必选,普通文件 | ||||||
| fs.file.type | 文件类型:日志文件 log、持久化文件 persistence、普通文件 regular | 必选 | ||||||
| flash.io.direction | flash IO操作方向 | 必选 | ||||||
| RPC访问 | bmc.rpc.client.request | counter | count(次) | server.mc.name | RPC服务端组件名称 | 必选 | rpc客户端请求指标 | 否,自定义指标 |
| client.mc.name | RPC请求端组件名称 | 必选 | ||||||
| rpc.dbus.path | RPC请求的dbus路径 | 必选 | ||||||
| rpc.dbus.interface | RPC请求的dbus接口 | 必选 | ||||||
| rpc.dbus.method | RPC请求的dbus方法 | 条件必选,方法访问 | ||||||
| rpc.dbus.property | RPC请求的dbus属性 | 条件必选,属性访问 | ||||||
| 持久化管理 | bmc.persistence.server.request | counter | count(次) | client.mc.name | 持久化请求端组件名称 | 必选 | 持久化服务侧请求指标 | 否,自定义指标 |
| persistence.data.type | 持久化类型,例如PermanentPer(跟模型定义保持一致) | 必选 | ||||||
| persistence.container.name | 持久化容器名 | 必选 | ||||||
| persistence.operation.name | 持久化操作类型,例如insert, update, delete | 必选 | ||||||
| bmc.persistence.flash.io | counter | By(字节) | client.mc.name | 持久化请求端组件名称 | 必选 | 持久化flash IO指标 (基于数据类型预估,跟实际写入量存在偏差) |
否,自定义指标 | |
| persistence.data.type | 持久化数据类型,例如PermanentPer(跟模型定义保持一致) | 必选 | ||||||
| persistence.container.name | 持久化存储容器名 | 必选 | ||||||
| flash.io.direction | flash IO操作方向 | 必选 |
新增可观测指标描述
使用场景:
- 统一定义和管理系统指标,解决命名冲突、含义模糊等问题
- 北向接口提供指标查询和使能能力
- 应用框架对指标进行校验和管控,禁止不合理的指标和属性标签
{
"metrics": [
{
"name": "bmc.hw.chip.io",
"description": "硬件器件IO操作",
"unit": "count",
"type": "Counter",
"attributes": [
{
"name": "hw.bus.name",
"description": "硬件总线的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.name",
"description": "硬件器件的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.operation.name",
"description": "硬件操作的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.operation.result",
"description": "硬件操作的结果",
"type": "String",
"level": "Required"
}
]
},
{
"name": "bmc.hw.chip.accessor",
"description": "硬件器件访问器",
"unit": "count",
"type": "Counter",
"attributes": [
{
"name": "hw.bus.name",
"description": "硬件总线的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.name",
"description": "硬件器件的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.accessor.name",
"description": "硬件器件的访问器名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.accessor.direction",
"description": "硬件器件的访问器的访问方向",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.accessor.result",
"description": "硬件器件的访问器的访问结果",
"type": "String",
"level": "Required"
}
]
},
{
"name": "bmc.hw.chip.scanner",
"description": "硬件器件扫描器",
"unit": "count",
"type": "Counter",
"attributes": [
{
"name": "hw.bus.name",
"description": "硬件总线的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.name",
"description": "硬件器件的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.scanner.name",
"description": "硬件器件扫描器的名称",
"type": "String",
"level": "Required"
},
{
"name": "hw.chip.scanner.result",
"description": "硬件器件扫描器的扫描结果",
"type": "String",
"level": "Required"
}
]
},
{
"name": "bmc.mc.flash.io",
"description": "微组件flash IO",
"unit": "By",
"type": "Counter",
"attributes": [
{
"name": "mc.name",
"description": "微组件名称",
"type": "String",
"level": "Required"
},
{
"name": "fs.file.name",
"description": "文件名称",
"type": "String",
"level": "Recommended"
},
{
"name": "fs.file.type",
"description": "文件类型",
"type": "String",
"level": "Required"
},
{
"name": "flash.io.direction",
"description": "flash IO操作方向",
"type": "String",
"level": "Required"
}
]
},
{
"name": "bmc.rpc.client.request",
"description": "RPC客户端请求",
"unit": "count",
"type": "Counter",
"attributes": [
{
"name": "server.mc.name",
"description": "RPC服务端组件名称",
"type": "String",
"level": "Required"
},
{
"name": "rpc.dbus.path",
"description": "RPC请求的dbus路径",
"type": "String",
"level": "Required"
},
{
"name": "rpc.dbus.interface",
"description": "RPC请求的dbus接口",
"type": "String",
"level": "Required"
},
{
"name": "rpc.dbus.method",
"description": "RPC请求的dbus方法",
"type": "String",
"level": "Conditionally-Required"
},
{
"name": "rpc.dbus.property",
"description": "RPC请求的dbus属性",
"type": "String",
"level": "Conditionally-Required"
}
]
},
{
"name": "bmc.persistence.server.request",
"description": "持久化服务请求",
"unit": "count",
"type": "Counter",
"attributes": [
{
"name": "client.mc.name",
"description": "持久化请求端组件名称",
"type": "String",
"level": "Required"
},
{
"name": "persistence.data.type",
"description": "持久化数据类型",
"type": "String",
"level": "Required"
},
{
"name": "persistence.container.name",
"description": "持久化存储容器名",
"type": "String",
"level": "Required"
},
{
"name": "persistence.operation.name",
"description": "持久化操作类型",
"type": "String",
"level": "Required"
}
]
},
{
"name": "bmc.persistence.flash.io",
"description": "持久化服务flash IO",
"unit": "By",
"type": "Counter",
"attributes": [
{
"name": "client.mc.name",
"description": "持久化请求端组件名称",
"type": "String",
"level": "Required"
},
{
"name": "persistence.data.type",
"description": "持久化数据类型",
"type": "String",
"level": "Required"
},
{
"name": "persistence.container.name",
"description": "持久化存储容器名",
"type": "String",
"level": "Required"
}
]
}
]
}
评审结论(评审结束后录入,描述全面且清晰,不能是通过或不通过、同意或不同意)
- 同意新增可观测指标定义,BMC侧指标调整如下:
- 指标名称加上bmc.的命名空间
- 指标属性(标签)名称加上更精准的命名空间约定
- 同意新增可观测指标指标描述,采用json格式,由observability可观测组件承载