ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SkyWalking Trace Profiling 实践指南:基于线程栈采样的方法级性能瓶颈定位

SkyWalking Trace Profiling 实践指南:基于线程栈采样的方法级性能瓶颈定位 可观测性后端微服务云原生【免费下载链接】skywalkingAPM, Application Performance Monitoring System项目地址https://gitcode.com/gh_mirrors/sky/skywalking点击查看免费下载Trace Profiling链路剖析是 SkyWalking 内置于自动探针auto-instrument agent中的按需诊断能力对应 In-Process Profiling 场景当某个服务端点的响应延迟异常升高时运维与开发人员可以动态下发剖析任务让探针周期性抓取该请求相关线程的栈快照最终由 OAP 聚合分析出具体慢方法。本文以 backend-trace-profiling.md 为主线完整覆盖任务创建、数据采集、查询分析与线程栈合并原理并结合仓库源码说明底层实现帮助读者在真实环境里落地这一能力。Trace Profiling 的定位与工作原理在分布式系统中某个接口变慢是最常见的性能问题但链路追踪只能告诉你在哪一跳服务/数据库上耗时较长无法进一步定位到进程内部具体是哪一行业务代码拖慢了响应。SkyWalking 的 Trace Profiling 正是为填补这一盲区而设计。与三类剖析能力的关系SkyWalking 整体提供三种剖析方式详见 profiling.mdIn-process profiling进程内剖析随自动探针内置面向 VM 类运行时当前 Java 与 Python 探针支持以周期性线程栈快照的方式定位慢方法Out-of-process profiling进程外剖析由 eBPF 探针驱动面向 C/C、Rust 等无 VM 语言Golang 因向 eBPF 暴露了 VM 元数据也可剖析包括 On-CPU / Off-CPU 与网络剖析Continuous profiling持续剖析基于 eBPF 监控系统、进程指标命中阈值后自动触发剖析任务。本文讨论的 Trace Profiling 属于第一类——进程内剖析是唯一由普通自动探针承载、无需 eBPF 内核能力的剖析方案。任务驱动的工作机制Trace Profiling 的核心机制是任务下发生效任务以Task剖析任务的形式下发到探针可动态开启或关闭无需重启业务进程当一个服务的某个endpoint出现高延迟时即可创建 Trace Profiling 任务探针收到任务后按设定周期对与该端点相关的线程栈进行周期采样采样完成后通过分析端点内的线程栈即可确定导致性能问题的具体业务代码行。从源码结构看这条链路在 OAP 侧由receiver-profile模块承载任务查询、快照收集、任务完成上报三个 gRPC 接口集中在 ProfileTaskServiceHandler.java 中实现分别对应getProfileTaskCommands探针拉取任务、collectSnapshot探针上报线程栈快照与reportTaskFinish任务执行完成上报。在 OAP 中启用 receiver-profile 模块由于 OAP 与探针之间使用全新协议交换 Trace Profiling 数据必须显式启用对应的接收器模块。在 OAP 配置文件中加入以下配置完整配置文件见 application.ymlreceiver-profile: selector: ${SW_RECEIVER_PROFILE:default} default:receiver-profile模块名对应源码中的 ProfileModule.javaProfileModule.NAME receiver-profileselector选择启用的 Provider默认值来自环境变量SW_RECEIVER_PROFILE缺省为default即使用 ProfileModuleProvider.java 中定义的默认实现defaultprovider 的具体配置节当前实现无额外参数newConfigCreator()返回null。该 provider 启动时会把ProfileTaskServiceHandler及其兼容版本注册到共享 gRPC 服务SharingServerModule上并声明依赖CoreModule与SharingServerModule。也就是说只要按上述配置启动 OAP探针即可通过共享 gRPC 通道完成剖析数据的收发。Trace Profiling 任务的完整使用流程官方文档给出了四个标准步骤创建任务 → 生成请求 → 查询任务详情 → 分析数据。下面逐一展开。第一步创建剖析任务创建 Trace Profiling 任务的目的是通知所有执行该服务实体的探针节点哪个端点需要执行 Trace Profiling。该端点通常是 HTTP 请求或 RPC 请求地址。创建任务时需要配置以下字段字段说明Service需要监控的服务即该服务下哪些 Agent 需要被监控Endpoint具体的端点名称例如POST:/path/to/requestStart Time任务开始时间可立即执行也可设定在未来时间执行Duration任务执行的持续时间Min Duration Threshold仅当指定端点执行时间超过该阈值时才触发监控有效避免因执行时间过短而采集到无效数据Dump Period线程栈采集周期每隔指定的毫秒数触发一次线程采样Max Sampling Count单个任务最多可采集的 Trace 数量避免因过度采样影响程序执行如 Java 的 Stop-The-World 场景其中Dump Period的取值需要特别注意。按 profiling.md 的建议周期通常为10~100 毫秒不建议低于 10 毫秒因为线程栈采集通常会引发 VM 的 stop-the-world过于密集的采样会拖累整个进程的性能。探针确认任务的日志当 Agent 从 OAP 收到 Trace Profiling 任务后会自动生成一条日志以确认任务已被受理日志包含以下字段InstanceAgent 所在实例的名称Type支持NOTIFIED与EXECUTION_FINISHED两种当前日志展示的是NOTIFIEDTimeAgent 收到任务的时间。从源码实现看这两类日志分别对应 OAP 侧记录的操作类型探针在getProfileTaskCommands拉取到新任务时写入NOTIFIED在reportTaskFinish上报完成时写入EXECUTION_FINISHED最终以 ProfileTaskLogRecord.java 形式异步落库RecordStreamProcessor.getInstance().in(...)。第二步生成请求任务创建后与该端点及其他条件匹配的 Tracing 请求会自动进入 Profiling 流程。这里需要特别说明跨线程敏感性问题剖析是否对线程敏感取决于探针端实现。Java Agent 已支持跨线程请求因此当请求涉及跨线程操作时相关线程栈同样会被周期性采样。第三步查询任务详情当 Tracing 请求完成后可以查询与该 Trace Profiling 任务关联的 Tracing 数据包含以下信息TraceId当前请求的 Trace IDInstance当前剖析数据所属的实例Duration当前实例处理该 Tracing 请求的总耗时Spans当前 Tracing 关联的 Span 列表每个 Span 包含SpanId当前 Span 的 IDParent Span Id父 Span 的 ID用于构成树形结构SegmentIdSpan 所属 Segment 的 IDRefs当前 Span 的引用信息注意只包含CROSS_THREAD类型的引用ServiceSpan 所属的服务实体信息InstanceSpan 所属的实例实体信息Time当前 Span 的开始与结束时间Endpoint Name当前 Span 的名称TypeSpan 类型为Entry、Local或ExitPeer远端网络地址Component当前 Span 使用的组件名称LayerSpan 所属的层TagsSpan 中包含的标签信息LogsSpan 中的日志信息Profiled当前 Span 是否支持 Profiling 数据分析。其中的Profiled字段是后续线程栈分析的关键标记——它标识了哪些 Span 具备可分析的剖析快照数据。第四步分析数据在确认哪些 Segment 可进行剖析分析后即可依据 Span 中的profiled字段确定可用于线程栈分析的时间范围并提交以下查询内容segmentId待分析的 Segment。Segment 通常绑定在单个线程上因此确定了 Segment 也就确定了需要分析哪个线程time range包含开始与结束时间。将 segmentId 与时间范围组合即可确定指定线程在指定时间段内的快照数据从而合并该线程在该时间范围内的线程栈分析哪些代码行耗时更长。合并结果中每个栈帧提供以下字段字段说明Id标识当前线程栈帧Parent Id与id配合确定层级关系Code Signature当前线程栈帧的方法签名Duration当前线程栈帧消耗的总时间Duration Child Excluded排除子方法调用后当前方法自身消耗的时间Count当前线程栈帧被采样的次数查询侧的实现由ProfileTaskQueryService与ProfileAnalyzer承载前者负责按任务/实例/时间范围检索剖析数据后者在 ProfileAnalyzer.java 中按segmentId 时间范围查询快照序列区间queryMinSequence/queryMaxSequence将二进制栈快照反序列化后并行聚合为ProfileStackTree列表最终返回ProfileAnalyzation。GraphQL 层的入口可参考 ProfileQuery.java。线程栈合并机制从快照到栈树得到线程栈树后Duration、Duration Child Excluded与Count等字段是如何计算出来的答案在 backend-profile-thread-merging.md 中SkyWalking 用线程转储thread dump来估算方法执行时间而不是为慢方法增加多个本地 Span资源开销远小于用分布式追踪定位慢方法因此适合在生产环境使用。数据读取与转换使用流按页读取数据库记录每页 50 条以并行流的方式将数据转换为 gRPC 数据结构合并为一个数据列表。对应地ProfileAnalyzer.analyze()中使用parallelStream()并行查询各时间区间的快照记录再distinct()去重后统一分析。数据分析采用 Java 并行流中的 group-by 与 collector 模式按数据库记录中的第一个栈元素分组并通过 collector 聚合生成多根树。核心步骤按首栈元素分组Group by first stack element以每个栈中的第一层元素分组保证具有相同根节点的栈归为一组生成空栈树Generate empty stack tree生成多个顶层空树为后续步骤做准备。生成多棵顶层树的原因是可以无锁并行地添加原始数据累加数据到栈树Accumulator data to stack tree将每条线程转储加入已生成的树——遍历线程转储中的每个元素在父元素下查找是否已存在代码签名相同且栈深度相同的子元素不存在则添加同时保留各节点来源的转储序列号与时间戳合并栈树Combine stack trees按与累加器相同的规则将所有树合并为一棵。合并时使用 LDR 顺序遍历树节点并借助Stack数据结构避免递归调用两个节点合并的任务即合并子节点列表——若代码签名相同且父节点相同则在该节点中保存转储序列号与时间戳否则作为新子节点加入目标节点计算耗时并构建结果Calculate durations and build result按同样的遍历逻辑转换为 GraphQL 数据结构将所有节点放入列表后进行耗时计算——对每个节点并行计算耗时先对序列号排序若存在连续的两个序列号则耗时累加这两个序列号对应时间戳的差值再并行计算每个节点的执行时间当前节点耗时需扣除所有子节点消耗的时间即得到Duration Child Excluded。这段按首元素分组 → 空树并行累加 → 树合并 → 并行算耗时的流程正是查询结果中Duration、Duration Child Excluded、Count三个字段的由来Count是采样命中次数Duration来自连续序列时间戳差值累加Duration Child Excluded则是在Duration基础上扣除全部子节点耗时。剖析数据导出与问题上报如果发现剖析结果不正确可以通过导出工具把原始剖析数据打包上报给社区协助定位。导出方式与内容详见 backend-profile-export.md按实际存储情况修改tools/profile-exporter/application.yml中的存储配置准备数据Profile Task ID剖析任务 ID、Trace ID出错的 Trace ID、Export dir数据导出目录进入 SkyWalking 根目录执行bash tools/profile-exporter/profile_exporter.sh --taskid{profileTaskId} --traceid{traceId} {exportDir}执行完毕后生成{traceId}.tar.gz文件。导出的数据内容包括basic.ymlTrace 中被剖析 Segment 的完整信息snapshot.data当前 Segment 中所有被监控的线程快照数据。上报问题时需提供导出工具生成的压缩包、Span 的操作名与分析模式包含/排除子 Span、问题描述如有 UI 截图更佳。注意导出数据包含类名、方法名、行号等敏感信息提交前请确认不会泄露系统安全信息。如需在本地深入调试剖析数据也可参考 backend-profile-thread-merging.md 中的调试指引用导出工具打包剖析数据后解压再使用 ProfileExportedAnalyze.java 的 main 函数运行分析。小结Trace Profiling 将分布式链路与进程内线程栈两种视角结合起来先通过 Trace 定位到慢请求对应的 Segment 与线程再利用周期性线程栈采样与 OAP 侧的栈合并算法把执行耗时精确落到具体的方法签名上。整个过程由任务动态驱动、可随时启停配合Min Duration Threshold、Dump Period、Max Sampling Count三个关键参数可以在采样精度与业务进程性能尤其是 VM 的 stop-the-world 开销之间取得平衡。对于 Java、Python 探针覆盖的服务这是一种无需 eBPF、成本远低于全量链路追踪的按需性能瓶颈定位方案。赞分享可观测性后端微服务云原生【免费下载链接】skywalkingAPM, Application Performance Monitoring System项目地址https://gitcode.com/gh_mirrors/sky/skywalking点击查看免费下载相关推荐Apache SkyWalking 基于 eBPF 的 CPU Profiling定位服务网格关键性能瓶颈的实战指南Apache SkyWalking 基于 eBPF 的 CPU Profiling定位服务网格关键性能瓶颈的实战指南 导读 本指南以 SkyWalking 官可观测性APM链路追踪指标监控日志分析微服务SkyWalking Go App Profiling 实战指南基于 pprof 的按需性能采样与火焰图分析SkyWalking Go App Profiling 实战指南基于 pprof 的按需性能采样与火焰图分析 本文是 SkyWalking 后端OAPGo可观测性APM链路追踪指标监控日志分析微服务HCCL 性能分析流程实战指南基于 Profiling 数据定位集合通信性能瓶颈HCCL 性能分析流程实战指南基于 Profiling 数据定位集合通信性能瓶颈 本文是 CANN/HCCL 集合通信库性能分析的流程指南。集群性能受 AI人工智能分布式训练高性能计算通信Ascend上一篇Angular 国际化标记机制深解认识 angular/localize 与 $localize 标签模板下一篇如何用MonoGame打造沉浸式游戏音效SoundEffect与Song类完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表