本文将阐述应用性能监控 APM 的链路(Trace)协议标准,参与此协议标准,用户可以从 DescribeGeneralOTSpanList 云 API 中获取链路数据,也可以在应用中进行自定义埋点增强,覆盖更多的框架和类库。
链路协议设计原则
应用性能监控 APM 的链路协议设计遵循 OpenTelemetry 标准,关于链路的基本概念,可以参考 OpenTelemetry Trace 获得更详情的信息。如果应用通过 OpenTelemetry 方案接入,不管是从云 API 中获取链路数据,还是在代码中进行自定义埋点增强,都能直接对齐 OpenTelemetry 标准,这是 APM 推荐的接入方案。如果应用通过非 OpenTelemetry 方案(例如 Skywalking 方案)接入,APM 会根据链路语义将其他方案的字段映射到 OpenTelemetry 链路协议标准中。
从云 API 获取链路数据
响应结果转换
调用 DescribeGeneralOTSpanList 云 API 后,响应结果为如下 JSON 格式文本。
{"Response":{"RequestId":"f796c81b-d0c6-4cf7-b0fa-4d9194ecad10","Spans":"Base64EncodedString","TotalCount":11151}}
其中,
Spans
字段中包含了链路数据的全部内容,由于数据经过了压缩,需要对结果进行如下三步转换,以还原始的文本。1. 将
Spans
字段中的文本进行 Base64解码,得到经过压缩后字节数组。2. 使用 gzip 对压缩后的字节数组进行解压,得到压缩前的字节数组。
3. 使用 UTF-8字符集,将压缩前的字节数组转换为文本。
以 Java 语言为例,可以参考如下代码片段实现响应结果转换。
import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Base64;import java.util.zip.GZIPInputStream;public class OtApiDecoder {public static String decodeSpans(String spans) {Base64.Decoder base64Decoder = Base64.getDecoder();byte[] bytes = base64Decoder.decode(spans);try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);GZIPInputStream gis = new GZIPInputStream(bais);ByteArrayOutputStream baos = new ByteArrayOutputStream();) {byte[] buffer = new byte[1024];int bytesRead = 0;while ((bytesRead = gis.read(buffer)) != -1) {baos.write(buffer, 0, bytesRead);}bytes = baos.toByteArray();String result = new String(bytes, StandardCharsets.UTF_8);return result;} catch (IOException e) {e.printStackTrace();}return null;}}
对于其他语言,也有标准的类库能够处理结果转换工作。
链路数据结构
{"resourceSpans":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"java-order-service"}}]},"scopeSpans":[{"scope":{"name":"apm/traces/spans","version":"v1.0"},"spans":[{"traceId":"9bda979bfbf9f27f94232909dc2a0a68","spanId":"e2f379eb4405dcb5","parentSpanId":"","name":"GET /slowSql","kind":2,"startTimeUnixNano":"1741082699964148","endTimeUnixNano":"1741082703966151","attributes":[{"key":"key1","value":{"stringValue":"value1"}},{"key":"key2","value":{"stringValue":"value2"}}],"status":{"code":0}}]}]}]}
链路数据是由多个 Span 组成的结果集,在 JSON 文本中通过应用名进行分组,每个组包含了属于该应用的 Span 列表,通过
spans
字段体现。每个 Span 的具体内容都遵循 OpenTelemetry 协议标准,在属性集合(通过attributes
字段体现)中,APM 在 OpenTelemetry 协议标准的基础上,对如下属性进行了增强:属性 | 说明 |
service.instance | 代表产生该 Span 的应用实例,取自 Resource 中的的 host.name 字段。在使用腾讯云增强版 Java 探针接入,或者 TKE 环境通过 tencent-opentelemetry-operator 一键接入的情况下,探针会自动附带该信息。其他接入方案下,请在接入应用的时候往 Resource 中添加 host.name ,详情请参见 自定义应用实例属性。 |
peer.service | 代表该 Span 的对端服务。如果当前 Span 的调用角色为 Server,APM 会将此字段设置为发起请求的应用;如果当前 Span 的调用角色为 Client,APM 会将此字段设置为请求的目标应用。 |
status_code_xx | 代表该 Span 的状态码。APM 在此字段中整合了各种协议的状态码,以 协议_状态码 的形式表达,例如HTTP_404 或gRPC_0 。 |
origin.operation | |
db.statement.excess | 代表该 Span 的 SQL 语句,适用于数据库请求 Span。由于保存在指标数据中的 SQL 语句存在长度限制, db.query.text 属性中保存的 SQL 语句可能会被截断,APM 会将原始的 SQL 语句保存到此字段中。 |
component | 代表该 Span 的埋点组件。腾讯云增强版 Java 探针和部分开源 OpenTelemetry 探针会自动附带该信息。 |
agent.version | 代表应用接入使用的探针版本。腾讯云增强版 Java 探针会自动附带该信息。 |
自定义埋点增强
如果通过 OpenTelemetry API 进行自定义埋点增强,请关注如下重要的字段信息,如果没有在埋点的时候指定,可能会导致 APM 的部分功能无法使用。各类编程语言使用的 OpenTelemetry API 中都有便捷的方式指定此值。
通用场景:
字段名 | 说明 |
所有 Span 都必须指定,代表 Span 的类型,在 APM 中被称作调用角色。取值为 Server 、Client 、Producer 、Consumer 、Internal 中的一种。 | |
代表 Span 的状态。取值为 Ok 、Error 、Unset 中的一种。 | |
代表 Span 的错误类型。当 Span 的状态为 Error 的时候,建议指定,APM 将基于错误类型的维度对错误 Span 进行聚合统计。 | |
代表 Span 的错误信息。当 Span 的状态为 Error 的时候,建议指定。 |
数据库调用:
字段名 | 说明 |
代表数据库类型。当 Span 为数据库调用的时候,必须在属性集合(attributes)中指定此字段。 | |
代表数据库服务的地址。当 Span 为数据库调用的时候,建议在属性集合(attributes)中指定此字段。 | |
代表数据库服务的端口。当 Span 为数据库调用的时候,建议在属性集合(attributes)中指定此字段。 | |
代表数据库名称。当 Span 为数据库调用的时候,建议在属性集合(attributes)中指定此字段。 | |
代表数据库查询语句(SQL)。当 Span 为数据库调用的时候,必须在属性集合(attributes)中指定此字段。 |