SkyWalking OAP 查询链路追踪(Query Tracing)调试指南:定位指标、Trace、拓扑与日志查询性能瓶颈
【免费下载链接】skywalkingAPM, Application Performance Monitoring System项目地址: https://gitcode.com/gh_mirrors/sky/skywalking
SkyWalking OAP 后端自带一套「查询链路追踪(Query Tracing)」能力,可以在一次查询请求(MQE 指标、Trace、Zipkin、Topology 拓扑、Log 日志)中,自动记录 OAP 内部的执行调用链:每个环节的耗时、错误信息,甚至底层存储(Elasticsearch / BanyanDB)的真实请求与响应内容。本文基于 query-tracing.md 展开,结合 debugging-query-plugin 与 server-core 源码,完整讲解如何通过 HTTP REST 接口与 GraphQL 两种方式开启查询追踪、解读 DebuggingTrace 结构,并给出可直接复制的 curl 与 GraphQL 示例,帮助你快速诊断 SkyWalking 后端自身的查询性能问题。
一、什么是 OAP Query Tracing
SkyWalking OAP(Observability Analysis Platform)对外提供指标(metrics)、Trace、日志(log)、拓扑(topology)等查询能力,这些查询最终会落到存储层(Elasticsearch、BanyanDB、MySQL 等)执行。当用户反馈「查询很慢」或「某条查询不符合预期」时,仅看最终结果很难定位瓶颈——究竟是 MQE 语法解析慢、聚合计算慢,还是存储层响应慢、返回数据过大?
Query Tracing 正是为此设计:它把一次 OAP 查询请求的内部执行过程,按照类似分布式追踪的 Span 树结构记录下来,并随查询结果一起返回给调用方。从源码看,这一机制的载体是DebuggingTraceContext(DebuggingTraceContext.java):
- 每个查询线程通过
ThreadLocal<DebuggingTraceContext> TRACE_CONTEXT保存上下文; createSpan(operation)创建并压栈一个DebuggingSpan,记录System.nanoTime()级别的起止时间(纳秒);stopSpan(span)负责计算耗时并弹栈,天然形成父子层级;stopTrace()收尾,生成整条 trace 的duration。
public DebuggingSpan createSpan(String operation) { DebuggingSpan span = new DebuggingSpan(spanIdGenerator++, operation); if (debug) { span.setStartTime(System.nanoTime()); DebuggingSpan parentSpan = spanStack.isEmpty() ? null : spanStack.peek(); if (parentSpan != null) { span.setParentSpanId(parentSpan.getSpanId()); } else { span.setParentSpanId(-1); } spanStack.push(span); execTrace.addSpan(span); } return span; }这意味着:只有开启 debug 的查询才会产生追踪开销(createSpan/stopSpan内部有if (debug)守卫),日常查询不会受任何影响。
1.1 Trace 结构
一次查询追踪由根 Trace 与若干 Span 组成,字段定义见 DebuggingTrace.java:
| 字段 | 说明 |
|---|---|
| traceId | 本次追踪的唯一 ID(UUID.randomUUID()生成) |
| condition | 本次查询的完整条件描述(表达式、实体、时间范围等) |
| startTime | 追踪开始时间,纳秒 |
| endTime | 追踪结束时间,纳秒 |
| duration | 追踪总耗时,纳秒 |
| spans | 本次追踪包含的所有 Span |
1.2 Span 结构
| 字段 | 说明 |
|---|---|
| spanId | Span 的唯一 ID |
| parentSpanId | 父 Span ID,根 Span 为 -1 |
| operation | Span 的操作名(如 "MQE query"、"MQE syntax analysis") |
| startTime | Span 开始时间,纳秒(相对时间,依赖具体实现与环境) |
| endTime | Span 结束时间,纳秒 |
| duration | Span 耗时,纳秒 |
| msg | Span 附加信息,可包含请求条件、数据库响应、BanyanDB 内部 trace 的 Tags |
| error | Span 出错时的错误信息 |
二、通过 HTTP REST API 调试
Query Tracing 服务内置于 OAP 的 rest server,所有调试接口统一走 HTTP GET:http://{core restHost}:{core restPort}/debugging/query/...(restHost/restPort 即 OAP 的 HTTP 监听地址与端口,默认0.0.0.0:12800,可在application.yml的core.restPort配置)。
所有调试接口都由 DebuggingHTTPHandler.java 实现,它内部直接复用了 GraphQL 层的MetricsExpressionQuery、TraceQuery、TopologyQuery、LogQuery以及 Zipkin 的ZipkinQueryHandler,因此返回内容与 GraphQL 查询等价,并额外以YAML 格式输出调试追踪信息(通过transToYAMLString序列化)。这也说明 Query Tracing 不是另起炉灶的「假查询」,而是对真实查询链路的旁路观测。
另外,该插件还提供GET /debugging/config/dump用于导出启动配置(serverStatusService.dumpBootingConfigurations),与查询追踪配合可用于排查配置类问题。
2.1 追踪 MQE 执行(/debugging/query/mqe)
- URL:
http://{core restHost}:{core restPort}/debugging/query/mqe?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| dumpDBRsp | 是否把数据库响应 dump 到 span 的 msg 中,支持 Elasticsearch 与 BanyanDB | 否,默认 false |
| expression | MQE 查询表达式 | 是 |
| startTime | 查询开始时间 | 是 |
| endTime | 查询结束时间 | 是 |
| step | 查询步长(SECOND/MINUTE/HOUR/DAY 等) | 是 |
| service | 服务名 | 是 |
| serviceLayer | 服务层名(如 GENERAL、MESH) | 是 |
| serviceInstance | 服务实例名 | 否 |
| endpoint | 端点名 | 否 |
| process | 进程名 | 否 |
| destService | 目标服务名 | 否 |
| destServiceLayer | 目标服务层名 | 否 |
| destServiceInstance | 目标服务实例名 | 否 |
| destEndpoint | 目标端点名 | 否 |
| destProcess | 目标进程名 | 否 |
时间与 step 参数遵循 Duration 格式:start/end为yyyy-MM-dd HHmm或yyyy-MM-dd等格式,step为枚举值。
示例:追踪一条 MQE 表达式avg(service_sla),查询 2024-07-03 一天、步长 DAY、服务mock_a_service、服务层GENERAL,并开启dumpDBRsp=true:
curl -X GET 'http://127.0.0.1:12800/debugging/query/mqe?dumpDBRsp=true&expression=avg(service_sla)&startTime=2024-07-03&endTime=2024-07-03&step=DAY&service=mock_a_service&serviceLayer=GENERAL'响应同时包含查询结果与debuggingTrace信息:
type: "SINGLE_VALUE" results: - metric: labels: [] values: - id: null value: "10000" traceID: null doubleValue: 10000.0 emptyValue: false error: null debuggingTrace: traceId: "4f972417-c543-4f7d-a3f1-f5e694cfeb2b" condition: "Expression: avg(service_sla), Entity: Entity(scope=null, serviceName=mock_a_service,\ \ normal=true, serviceInstanceName=null, endpointName=null, processName=null,\ \ destServiceName=null, destNormal=null, destServiceInstanceName=null, destEndpointName=null,\ \ destProcessName=null), Duration: Duration(start=2024-07-03, end=2024-07-03,\ \ step=DAY)" startTime: 115828803080350 endTime: 115828877400237 duration: 74319887 rootSpan: spanId: 0 parentSpanId: -1 operation: "MQE query" startTime: 115828803110686 endTime: 115828877396756 duration: 74286070 msg: null error: null childSpans: - spanId: 1 parentSpanId: 0 operation: "MQE syntax analysis" startTime: 115828803699331 endTime: 115828805015745 duration: 1316414 msg: null error: null childSpans: [] - spanId: 2 parentSpanId: 0 operation: "MQE Aggregation OP: avg(service_sla)" startTime: 115828805052267 endTime: 115828876877134 duration: 71824867 msg: null error: null childSpans: - spanId: 3 parentSpanId: 2 operation: "MQE Metric OP: service_sla" startTime: 115828805209453 endTime: 115828875634953 duration: 70425500 msg: null error: null childSpans: ...从上面这棵 Span 树可以清晰看出耗时分布:整个查询耗时约 74.3ms,其中 MQE 语法分析仅约 1.3ms,聚合算子avg(service_sla)占了约 71.8ms,而真正的瓶颈是底层指标读取MQE Metric OP: service_sla(约 70.4ms)——问题直指存储层,而非表达式解析。
这些 Span 的来源可以从源码得到印证:MQEVisitorBase.java 中每类 MQE 操作(Binary OP、Aggregation OP、Mathematical OP、TopN OP、Logical OP、Trend OP、Sort OP 等)都会调用traceContext.createSpan(...);MetricsQueryService.java 则在readMetricsValues/readLabeledMetricsValues处创建Query Service: readMetricsValues等 Span。
BanyanDB 原生存储下的内部执行 trace
注意:如果使用 SkyWalking 原生存储 BanyanDB,debuggingTrace会进一步包含 BanyanDB 内部的执行追踪信息,例如 measure 查询、index scan 的具体计划,此时msg中携带了大量底层细节:
... childSpans: - spanId: 7 parentSpanId: 6 operation: "BanyanDB: measure-grpc" startTime: 1720059017222584700 endTime: 1720059017223492400 duration: 907700 msg: "[Tag(key=request, value={\"groups\":[\"measure-default\"], \"\ name\":\"service_sla_day\", \"timeRange\":{\"begin\":\"2024-07-02T16:00:00Z\"\ , \"end\":\"2024-07-03T16:00:00Z\"}, \"criteria\":{\"condition\"\ :{\"name\":\"entity_id\", \"op\":\"BINARY_OP_EQ\", \"value\":{\"\ str\":{\"value\":\"bW9ja19hX3NlcnZpY2U=.1\"}}}}, \"tagProjection\"\ :{\"tagFamilies\":[{\"name\":\"storage-only\", \"tags\":[\"entity_id\"\ ]}]}, \"fieldProjection\":{\"names\":[\"percentage\"]}, \"trace\"\ :true})]" error: null childSpans: - spanId: 8 parentSpanId: 7 operation: "BanyanDB:>curl -X GET 'http://127.0.0.1:12800/debugging/query/trace/queryBasicTraces?startTime=2024-06-26%200900&endTime=2024-06-26%200915&step=MINUTE&service=mock_a_service&serviceLayer=GENERAL&serviceInstance=mock_a_service_instance&traceState=ALL&queryOrder=BY_DURATION&pageNum=1&pageSize=15&tags=http.status_code%3D404%2Chttp.method%3Dget'响应包含查询结果与debuggingTrace信息,结构同 MQE 查询追踪:
traces: ... debuggingTrace: ...注意:tags参数在源码中是按逗号切分、再按等号切分组装成Tag列表的,因此 URL 中需要将,编码为%2C、=编码为%3D。queryBasicTraces的 Span 由 TraceQueryService.java 中的Query Service: queryBasicTraces创建。
queryTrace
- URL:
http://{core restHost}:{core restPort}/debugging/query/trace/queryTrace?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| traceId | 要查询的 Trace ID | 是 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/trace/queryTrace?traceId=8211a1d1-de0f-4485-8766-c88866a8f034'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
spans: ... debuggingTrace: ...2.3 追踪 Zipkin Trace 查询
Zipkin API /api/v2/traces
- URL:
http://{core restHost}:{core restPort}/debugging/query/zipkin/api/v2/traces?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| serviceName | 服务名 | 否 |
| remoteServiceName | 远端服务名 | 否 |
| spanName | Span 名 | 否 |
| annotationQuery | 注解查询 | 否 |
| minDuration | Trace 最小耗时 | 否 |
| maxDuration | Trace 最大耗时 | 否 |
| endTs | 查询结束时间戳,默认当前时间戳 | 否 |
| lookback | 回看窗口,默认86400000(24 小时) | 否 |
| limit | 返回数量上限,默认10 | 否 |
所有参数与 Zipkin 原生 API/api/v2/traces保持一致。
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/zipkin/api/v2/traces?serviceName=frontend'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
traces: ... debuggingTrace: .../api/v2/trace/{traceId}
- URL:
http://{core restHost}:{core restPort}/debugging/query/zipkin/api/v2/trace?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| traceId | 要查询的 Trace ID | 是 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/zipkin/api/v2/trace?traceId=fcb10b060c6b2492'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
spans: ... debuggingTrace: ...从源码可以看到,Zipkin 调试接口的实现方式略有不同:它先在DebuggingTraceContext中手动设置 condition,再调用真实的ZipkinQueryHandler(基于默认的 ZipkinQueryConfig)执行查询,最后把内嵌的 exec trace 一并返回(见 DebuggingHTTPHandler.java 中queryZipkinTraces与getZipkinTraceById的try/finally结构——finally中stopTrace()并清理TRACE_CONTEXT,保证线程上下文不会泄漏)。
2.4 追踪拓扑查询
getGlobalTopology
- URL:
http://{core restHost}:{core restPort}/debugging/query/topology/getGlobalTopology?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| startTime | 查询开始时间 | 是 |
| endTime | 查询结束时间 | 是 |
| step | 查询步长 | 是 |
| serviceLayer | 服务层名 | 否 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getGlobalTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&serviceLayer=GENERAL'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
nodes: ... calls: ... debuggingTrace: ...getServicesTopology
- URL:
http://{core restHost}:{core restPort}/debugging/query/topology/getServicesTopology?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| startTime | 查询开始时间 | 是 |
| endTime | 查询结束时间 | 是 |
| step | 查询步长 | 是 |
| serviceLayer | 服务层名 | 是 |
| services | 服务名列表,逗号分隔,如mock_a_service, mock_b_service | 是 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getServicesTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&serviceLayer=GENERAL&services=mock_a_service%2Cmock_b_service'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
nodes: ... calls: ... debuggingTrace: ...getServiceInstanceTopology
- URL:
http://{core restHost}:{core restPort}/debugging/query/topology/getServiceInstanceTopology?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| startTime | 查询开始时间 | 是 |
| endTime | 查询结束时间 | 是 |
| step | 查询步长 | 是 |
| clientService | 客户端服务名 | 是 |
| serverService | 服务端服务名 | 是 |
| clientServiceLayer | 客户端服务层名 | 是 |
| serverServiceLayer | 服务端服务层名 | 是 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getServiceInstanceTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&clientService=mock_a_service&serverService=mock_b_service&clientServiceLayer=GENERAL&serverServiceLayer=GENERAL'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
nodes: ... calls: ... debuggingTrace: ...getEndpointDependencies
- URL:
http://{core restHost}:{core restPort}/debugging/query/topology/getEndpointDependencies?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| startTime | 查询开始时间 | 是 |
| endTime | 查询结束时间 | 是 |
| step | 查询步长 | 是 |
| service | 服务名 | 是 |
| serviceLayer | 服务层名 | 是 |
| endpoint | 端点名 | 是 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getEndpointDependencies?startTime=2024-07-03&endTime=2024-07-03&step=DAY&service=mock_a_service&serviceLayer=GENERAL&endpoint=%2Fdubbox-case%2Fcase%2Fdubbox-rest%2F404-test'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
nodes: ... calls: ... debuggingTrace: ...getProcessTopology
- URL:
http://{core restHost}:{core restPort}/debugging/query/topology/getProcessTopology?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| startTime | 查询开始时间 | 是 |
| endTime | 查询结束时间 | 是 |
| step | 查询步长 | 是 |
| service | 服务名 | 是 |
| serviceLayer | 服务层名 | 是 |
| instance | 实例名 | 是 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getProcessTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&service=mock_a_service&serviceLayer=GENERAL&instance=mock_a_service_instance'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
nodes: ... calls: ... debuggingTrace: ...拓扑类查询的 Span 埋点分布在各拓扑构建器中,例如 TopologyQueryService.java 中的Query Service: getGlobalTopology、Query Service: getServiceInstanceTopology等,以及 ServiceTopologyBuilder.java 中的Build service topology、ServiceInstanceTopologyBuilder.java 的Build service instance topology、EndpointTopologyBuilder.java 的Build endpoint topology、ProcessTopologyBuilder.java 的Build process topology。借此可以区分「拓扑计算耗时」与「底层存储查询耗时」。
2.5 追踪日志查询
queryLogs
- URL:
http://{core restHost}:{core restPort}/debugging/query/log/queryLogs?{parameters} - 参数:
| 字段 | 说明 | 必填 |
|---|---|---|
| startTime | 查询开始时间 | 是,除非 traceId 非空 |
| endTime | 查询结束时间 | 是,除非 traceId 非空 |
| step | 查询步长 | 是,除非 traceId 非空 |
| service | 服务名 | 否,需配合 serviceLayer |
| serviceLayer | 服务层名 | 否 |
| serviceInstance | 服务实例名 | 否,需配合 service |
| endpoint | 端点名 | 否,需配合 service |
| traceId | Trace ID | 否 |
| segmentId | Segment ID | 否,需配合 traceId |
| spanId | Span ID | 否,需配合 traceId |
| queryOrder | 查询结果排序:ASC、DES,默认DES | 否 |
| tags | 日志标签过滤,格式key1=value1,key2=value2 | 否 |
| pageNum | 结果页码 | 是 |
| pageSize | 每页大小 | 是 |
| keywordsOfContent | 日志内容关键词,keyword1,keyword2 | 否 |
| excludingKeywordsOfContent | 排除关键词,keyword1,keyword2 | 否 |
示例:
curl -X GET 'http://127.0.0.1:12800/debugging/query/log/queryLogs?service=e2e-service-provider&serviceLayer=GENERAL&startTime=2024-07-09&endTime=2024-07-09&step=DAY&pageNum=1&pageSize=15&queryOrder=ASC&tags=level%3DINFO'响应包含查询结果与debuggingTrace信息(结构同 MQE 查询追踪):
logs: ... debuggingTrace: ...从 DebuggingHTTPHandler.java 的queryLogs实现可以看到一个细节:当traceId为空时必须提供startTime/endTime/step,否则直接返回错误提示字符串;按traceId查询时走TraceScopeCondition(可叠加segmentId/spanId)精确定位日志。日志查询的 Span 由 LogQueryService.java 中的Query Service: queryLogs创建。
三、通过 GraphQL 调试
除了 REST 调试接口,Query Tracing 也内置于 GraphQL API 中。所有 GraphQL 查询接口都新增了一个debug: Boolean参数:设为true即可开启查询追踪,并在返回类型中追加debuggingTrace: DebuggingTrace字段。GraphQL 相关类型定义可参考 query-protocol.md 与 query-graphql-plugin 源码。
3.1 追踪 MQE 执行(Metrics V3 APIs)
- Bundle API:Metrics V3 APIs
extend type Query { ... # Param, if debug is true will enable the query tracing and return DebuggingTrace in the ExpressionResult. # Param, if dumpDBRsp is true the database response will dump into the DebuggingTrace span message. execExpression(expression: String!, entity: Entity!, duration: Duration!, debug: Boolean, dumpDBRsp: Boolean): ExpressionResult! }type ExpressionResult { ... debuggingTrace: DebuggingTrace }示例:通过 GraphQL 查询指标并开启追踪。GraphQL 端点地址为http://127.0.0.1:12800/graphql:
{ execExpression(expression: "avg(service_sla)", entity: {serviceName: "mock_a_service", normal: true}, duration: {start: "2024-07-03", end: "2024-07-03", step: DAY}, debug: true, dumpDBRsp: true) { type error results { metric { labels { key value } } values { id value traceID } } debuggingTrace { traceId condition startTime endTime duration spans { spanId parentSpanId operation startTime endTime duration msg error } } } }响应包含查询结果与debuggingTrace信息:
{ "data": { "execExpression": { "type": "SINGLE_VALUE", "error": null, "results": [ { "metric": { "labels": [] }, "values": [ { "id": null, "value": "10000", "traceID": null } ] } ], "debuggingTrace": { "traceId": "3116ffe3-ee9c-4047-9f22-c135c237aad5", "condition": "Expression: avg(service_sla), Entity: Entity(scope=null, serviceName=mock_a_service, normal=true, serviceInstanceName=null, endpointName=null, processName=null, destServiceName=null, destNormal=null, destServiceInstanceName=null, destEndpointName=null, destProcessName=null), Duration: Duration(start=2024-07-03, end=2024-07-03, step=DAY)", "startTime": 117259274324665, "endTime": 117259279847720, "duration": 5523055, "spans": [ { "spanId": 0, "parentSpanId": -1, "operation": "MQE query", "startTime": 117259274328719, "endTime": 117259279846559, "duration": 5517840, "msg": null, "error": null }, { "spanId": 1, "parentSpanId": 0, "operation": "MQE syntax analysis", "startTime": 117259274333084, "endTime": 117259274420159, "duration": 87075, "msg": null, "error": null }, { "spanId": 2, "parentSpanId": 0, "operation": "MQE Aggregation OP: avg(service_sla)", "startTime": 117259274433533, "endTime": 117259279812549, "duration": 5379016, "msg": null, "error": null }, ... ] } } } }注意:与 REST 接口相同,若使用 BanyanDB 存储,debuggingTrace.spans中会包含 BanyanDB 内部执行 trace,如 measure-grpc 请求、IndexScan 执行计划等:
... { "spanId": 7, "parentSpanId": 6, "operation": "BanyanDB: measure-grpc", "startTime": 1720060447687765300, "endTime": 1720060447688830200, "duration": 1064900, "msg": "[Tag(key=request, value={\"groups\":[\"measure-default\"], \"name\":\"service_sla_day\", \"timeRange\":{\"begin\":\"2024-07-02T16:00:00Z\", \"end\":\"2024-07-03T16:00:00Z\"}, \"criteria\":{\"condition\":{\"name\":\"entity_id\", \"op\":\"BINARY_OP_EQ\", \"value\":{\"str\":{\"value\":\"bW9ja19hX3NlcnZpY2U=.1\"}}}}, \"tagProjection\":{\"tagFamilies\":[{\"name\":\"storage-only\", \"tags\":[\"entity_id\"]}]}, \"fieldProjection\":{\"names\":[\"percentage\"]}, \"trace\":true})]", "error": null }, { "spanId": 8, "parentSpanId": 7, "operation": "BanyanDB:># Param, if debug is true will enable the query tracing and return DebuggingTrace in the result. extend type Query { # Search segment list with given conditions queryBasicTraces(condition: TraceQueryCondition, debug: Boolean): TraceBrief # Read the specific trace ID with given trace ID queryTrace(traceId: ID!, debug: Boolean): Trace ... }# The list of traces type TraceBrief { ... #For OAP internal query debugging debuggingTrace: DebuggingTrace } # The trace represents a distributed trace, includes all segments and spans. type Trace { ... #For OAP internal query debugging debuggingTrace: DebuggingTrace }用法与 MQE 查询追踪一致:按 GraphQL 协议与语法查询结果,并把debug参数置为true,即可在返回中取得debuggingTrace信息。
3.3 追踪拓扑查询(GraphQL)
- Bundle API:Topology
# Param, if debug is true will enable the query tracing and return DebuggingTrace in the result. extend type Query { # Query the global topology # When layer is specified, the topology of this layer would be queried getGlobalTopology(duration: Duration!, layer: String, debug: Boolean): Topology # Query the topology, based on the given service getServiceTopology(serviceId: ID!, duration: Duration!, debug: Boolean): Topology # Query the topology, based on the given services. # `#getServiceTopology` could be replaced by this. getServicesTopology(serviceIds: [ID!]!, duration: Duration!, debug: Boolean): Topology # Query the instance topology, based on the given clientServiceId and serverServiceId getServiceInstanceTopology(clientServiceId: ID!, serverServiceId: ID!, duration: Duration!, debug: Boolean): ServiceInstanceTopology ... # v2 of getEndpointTopology getEndpointDependencies(endpointId: ID!, duration: Duration!, debug: Boolean): EndpointTopology # Query the topology, based on the given instance getProcessTopology(serviceInstanceId: ID!, duration: Duration!, debug: Boolean): ProcessTopology }# The overview topology of the whole application cluster or services, type Topology { nodes: [Node!]! calls: [Call!]! debuggingTrace: DebuggingTrace } # The instance topology based on the given serviceIds type ServiceInstanceTopology { nodes: [ServiceInstanceNode!]! calls: [Call!]! debuggingTrace: DebuggingTrace } # The endpoint topology type EndpointTopology { nodes: [EndpointNode!]! calls: [Call!]! debuggingTrace: DebuggingTrace } # The process topology type ProcessTopology { nodes: [ProcessNode!]! calls: [Call!]! debuggingTrace: DebuggingTrace }用法与 MQE 查询追踪一致:按 GraphQL 协议与语法查询结果,并把debug参数置为true,即可在返回中取得debuggingTrace信息。
3.4 追踪日志查询(GraphQL)
- Bundle API:Log
extend type Query { ... queryLogs(condition: LogQueryCondition, debug: Boolean): Logs ... }type Logs { # When this field is not empty, frontend should display it in UI errorReason: String logs: [Log!]! debuggingTrace: DebuggingTrace }用法与 MQE 查询追踪一致:按 GraphQL 协议与语法查询结果,并把debug参数置为true,即可在返回中取得debuggingTrace信息。
四、底层实现原理与使用建议
4.1 埋点链路一览
从源码来看,Query Tracing 的埋点覆盖了 OAP 查询的完整调用链:
- MQE 表达式层:MQEVisitorBase.java 为每个 MQE 操作(Binary OP、Aggregation OP、Mathematical OP、TopN OP、Logical OP、Trend OP、Sort 系列 OP 等)创建 Span;
- 查询服务层:MetricsQueryService.java、TraceQueryService.java、LogQueryService.java、TopologyQueryService.java、AggregationQueryService.java 等在方法入口/出口创建
Query Service: ...与sortMetrics等 Span; - 拓扑构建层:ServiceTopologyBuilder.java 等各 Builder 创建
Build xxx topologySpan; - 存储层:若使用 BanyanDB,其内部 trace 通过
createSpanForTransform挂接到 OAP 的 Span 树中,直接展示存储侧的 gRPC 请求、IndexScan 计划与执行细节。
4.2 实践建议
- 只在需要时开启 debug:
debug/dumpDBRsp参数默认关闭,生产环境默认不产生额外开销;排查问题时再针对单条查询开启。 - 优先观察根因层级:阅读返回的 Span 树时,先看
duration最大的子树,再对照operation判断瓶颈落在 MQE 计算、拓扑构建还是存储查询;结合error字段定位失败环节。 - 善用
dumpDBRsp=true:当怀疑存储返回数据异常时,开启该参数可将 Elasticsearch / BanyanDB 的真实响应 dump 到 Span 的msg中,直接核对存储层行为。 - 区分两种调试入口:REST 调试接口(
/debugging/query/...)适合命令行快速验证与脚本化;GraphQL 的debug参数适合在业务集成、UI 二次开发场景中随查询一起返回追踪信息。
五、相关资源
- Query Tracing 官方文档
- Debugging HTTP Handler 实现
- 调试模块配置(含敏感信息脱敏关键词)
- DebuggingTrace 数据结构
- DebuggingTraceContext 上下文实现
- MQE 运行时 Span 埋点
- GraphQL 查询协议(含 Duration 格式)
- BanyanDB 存储接入文档
【免费下载链接】skywalkingAPM, Application Performance Monitoring System项目地址: https://gitcode.com/gh_mirrors/sky/skywalking
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考