关于 dotnet-trace-collect
帮助开发者为生产环境中的 .NET 性能问题选择诊断工具、规划数据采集并了解分析途径。它根据运行时、操作系统、部署方式和权限给出建议,但不直接分析代码或采集结果。
主要功能
- 01按环境和症状选择诊断工具
- 02提供采集命令与操作指引
- 03比较工具的适用条件和取舍
- 04覆盖容器与 Kubernetes 场景
- 05区分跟踪采集与转储分析
适用场景
- 01排查生产环境中的高 CPU 或内存增长
- 02调查慢请求、GC 过多或网络故障
- 03为容器或 Kubernetes 工作负载选择采集方式
- 04根据权限和运行时版本规划诊断
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dotnet/ skills --skill dotnet-trace-collect安装后在 Claude Code 中输入/dotnet-trace-collect确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/dotnet-monitor.mddotnet-trace-collect-linux.mddotnet-trace-collect.mdperfcollect.mdperfview.md详细介绍
.NET 跟踪收集
这项技能通过为开发者推荐适合其环境的诊断工具、指导数据收集并建议分析方法,帮助他们排查生产环境中的性能问题。它不会检查代码中是否存在反模式,也不会执行分析。
适用场景
- 开发者需要排查生产环境中的性能问题(CPU 占用率高、内存泄漏、请求缓慢、GC 过于频繁、网络错误等)
- 为特定运行时、OS 或部署拓扑选择合适的诊断工具
- 设置并运行诊断工具命令以收集数据
- 了解可用工具之间的权衡(例如 PerfView 与 dotnet-trace)
- 从容器化工作负载或 Kubernetes 工作负载中收集诊断数据
不适用场景
- 检查源代码中是否存在性能反模式(请改用代码审查技能)
- 在开发过程中进行基准测试(例如配置 BenchmarkDotNet)
- 分析已收集的跟踪或转储文件(这项技能会推荐分析工具,但不会执行分析)
输入
| 输入 | 必填 | 说明 |
|---|---|---|
| 症状 | 是 | 开发者观察到的现象(CPU 占用率高、内存增长、请求缓慢、挂起、GC 过于频繁、HTTP 5xx 错误、网络超时、连接失败、程序集加载失败等) |
| 运行时 | 是 | .NET Framework 或现代 .NET(以及版本,尤其是是否为 .NET 10+) |
| OS | 是 | Windows 或 Linux |
| 部署方式 | 是 | 非容器、容器或 Kubernetes |
| 管理员权限 | 建议提供 | 开发者是否拥有目标计算机上的管理员/root 访问权限 |
| 复现特征 | 建议提供 | 问题是否容易复现,还是需要很长时间才会出现 |
工作流
步骤 1:了解环境
确定以下信息,或请开发者补充说明:
- 症状:他们观察到的现象(CPU 占用率高、内存泄漏、请求缓慢、挂起、GC 过于频繁、HTTP 5xx 错误、网络超时、连接失败、程序集加载失败等)
- 运行时:.NET Framework 还是现代 .NET?如果是现代 .NET,具体是哪个版本?(尤其是是否为 .NET 10 或更高版本。)
- OS:Windows 还是 Linux?
- 部署方式:直接在主机上运行、在容器中运行,还是在 Kubernetes 中运行?
- 管理员权限:他们是否拥有目标计算机或容器上的管理员/root 访问权限?
- 复现特征:问题能否快速复现,还是需要很长时间才会出现?
- 工作负载上下文:确定或询问用户,你是否在工作负载的运行环境中(即在出现问题的同一台计算机上,或连接到发生问题的同一环境)。如果是,你可以代表他们直接运行诊断命令。如果不是,请将命令作为操作指南提供给用户,让他们自行运行。
使用这些信息在步骤 2 中选择合适的工具。
步骤 2:推荐诊断工具
根据以下优先级规则,结合环境选择工具。选定工具后,加载相应的参考文件,了解详细的命令行用法。
工具参考文件查询
| 环境 | 参考文件 |
|---|---|
| Windows + 现代 .NET + 管理员权限 | references/perfview.md |
| Windows + 现代 .NET,无管理员权限 | references/dotnet-trace-collect.md |
| Windows + .NET Framework | references/perfview.md |
| Linux + .NET 10+ + root 权限 | references/dotnet-trace-collect-linux.md |
| Linux + 早于 .NET 10 的版本 | references/dotnet-trace-collect.md |
| Linux + 需要本机调用栈 | references/perfcollect.md |
| 容器/K8s(可访问控制台) | references/dotnet-trace-collect.md(或 dotnet-trace-collect-linux.md) |
| 容器/K8s(无法访问控制台) | references/dotnet-monitor.md |
快速决策矩阵(初步排查)
| 环境 | 首选工具 | 备用方案 / 说明 |
|---|---|---|
| Windows + 现代 .NET + 管理员权限 | PerfView | 如果没有管理员权限,请使用 dotnet-trace |
| Windows + .NET Framework + 管理员权限 | PerfView | 没有管理员权限时,没有可用的跟踪备用方案;对于挂起 / 内存泄漏,直接提供转储命令(procdump -ma 或任务管理器),因为 dump-collect 不支持 .NET Framework |
| Linux + .NET 10+ + root | dotnet-trace collect-linux | 如果不满足 root 或内核前置条件,请使用 dotnet-trace |
| Linux + 早于 .NET 10 的版本 | dotnet-trace | 需要原生调用栈时,添加 perfcollect(需要 root) |
| Linux 容器 / Kubernetes | 在工作负载上下文中使用控制台工具;无法访问控制台时使用 dotnet-monitor | 详情请参阅 Linux 容器 / Kubernetes 部分 |
Windows(非容器、现代 .NET)
- PerfView(首选)——可生成更丰富的、基于 ETW 的数据;需要管理员权限。对于请求缓慢,添加
/ThreadTime以捕获线程级的等待和阻塞详情。 dotnet-trace——没有管理员权限时的备用方案。- 对于长时间运行的复现:使用 PerfView,并配置
/StopOn触发条件,使其在要捕获的症状出现时触发(例如/StopOnPerfCounter、/StopOnGCEvent、/StopOnException),并使用循环缓冲区(/CircularMB+/BufferSizeMB)。关键:停止触发条件必须在有意义的事件发生时触发,而不是在问题恢复时触发。循环缓冲区会持续覆盖旧数据,因此如果在问题恢复时触发,停止收集时缓冲区可能已经覆盖了有意义的行为。只有在已知开始事件先于停止事件时,才添加/StartOn。对于请求缓慢,默认不要包含停止触发条件——让用户根据具体场景自行设计。
Windows 容器
-
PerfView——大多数 Windows 容器(包括 Windows 上的 Kubernetes)默认使用进程隔离。从主机使用
/EnableEventsInContainers进行收集。收集完成后,有两个选项:- 在容器仍运行时于本地分析——PerfView 可以访问运行中的容器以解析符号,因此可以立即在主机上打开跟踪文件。
- 在其他机器上分析——在容器关闭前,将
.etl.zip复制到容器中,并在其中运行PerfViewCollect merge /ImageIDsOnly以嵌入符号信息。然后将合并后的跟踪文件复制出来。如果没有此合并步骤,其他机器将无法解析容器内二进制文件的符号。
对于较少见的 Hyper-V 容器,请直接在容器内收集。详细命令请参阅 references/perfview.md。
-
dotnet-monitor、dotnet-trace——如果镜像中已安装这些工具,则在容器内使用。收集转储时,请调用dump-collect技能。
Windows(.NET Framework)
- PerfView——Windows 上用于诊断 .NET Framework 的主要工具。需要管理员权限。
- 长时间运行复现的触发条件指南相同:使用在症状出现时触发的
/StopOn触发条件(例如/StopOnPerfCounter、/StopOnGCEvent、/StopOnException),并使用/CircularMB+/BufferSizeMB。 - 没有管理员权限时:PerfView 需要管理员权限,而 .NET Framework 没有其他跟踪工具。仍然可以在没有管理员权限的情况下捕获进程转储——直接提供转储命令(例如
procdump -ma <PID>或任务管理器),因为dump-collect技能不支持 .NET Framework。转储有助于诊断挂起和内存泄漏。但是,对于高 CPU 使用率、请求缓慢和GC 过多,没有管理员权限就无法调查 .NET Framework 问题。建议用户获取管理员权限。
Linux(非容器,.NET 10+)
dotnet-trace collect-linux(首选)— 使用perf_events获取更丰富的跟踪数据,包括本机调用堆栈和内核事件。默认捕获整台计算机的数据(无需指定 PID)。需要 root 权限,且内核版本 >= 6.4。dotnet-trace— 当无法获得 root 权限或不满足内核要求时使用。仅包含托管堆栈。
Linux(非容器,.NET 10 之前)
dotnet-trace(首选)— 收集托管跟踪数据;无需管理员权限。perfcollect— 需要本机调用堆栈时使用(需要管理员/root 权限)。
Linux 容器 / Kubernetes
如果在工作负载上下文中运行(即可以访问容器控制台),优先使用基于控制台的工具。与 dotnet-monitor 相比,这些工具更容易设置;dotnet-monitor 需要配置身份验证并部署 sidecar:
dotnet-trace collect-linux(.NET 10+ 且具有 root 权限)— 生成最丰富的跟踪数据,包括本机调用堆栈和内核事件。dotnet-trace— 如果镜像中已安装该工具,可在容器内使用。如需转储,请调用dump-collect技能。perfcollect— 在 .NET 10 之前的版本中,需要本机堆栈时可在容器内使用(需要SYS_ADMIN/--privileged)。
如果不在工作负载上下文中运行(无法访问控制台),或已部署 dotnet-monitor:
dotnet-monitor— 专为容器设计,以 sidecar 形式运行。应用容器中无需安装工具。无法访问控制台时,这是最简单的选择。
内存转储
需要转储时(内存泄漏、挂起),对于现代 .NET,不要直接提供转储收集命令 — 请改为调用 dump-collect 技能。dump-collect 技能仅支持现代 .NET(.NET Core 3.0+)。对于 .NET Framework,请直接提供转储收集指导(例如 procdump -ma <PID> 或任务管理器)。此技能仅专注于跟踪收集。
内存泄漏
- 在内存持续增长时捕获两个转储(例如,一个较早捕获,另一个在显著增长后捕获)。调用
dump-collect技能收集转储 — 不要直接提供转储命令。在 PerfView 中对比转储,查看哪些对象有所增加 — 这是识别泄漏对象最有效的方法。 - 没有管理员权限时:两个进程转储可以帮助了解堆上哪些内容正在增长,但可能不足以确定根本原因。如果转储不足以定位问题,请在可获得管理员权限的环境中重现问题,以收集更丰富的数据(跟踪)。
- Linux 上的现代 .NET(.NET 10 之前):建议捕获两个转储(调用
dump-collect技能)以进行堆对比,并在内存增长时运行dotnet-trace(用于分配跟踪)。无需触发条件 — 在增长期间捕获即可。两者结合可提供最全面的情况。 - Linux 上具有管理员权限的现代 .NET 10+:建议捕获两个转储(调用
dump-collect技能)以进行堆对比,并在内存增长时运行dotnet-trace collect-linux(可获取更丰富的数据,包括本机堆栈)。无需触发条件。 - .NET Framework:建议捕获两个转储,并在内存增长时使用 PerfView 跟踪,查看正在分配哪些内容。
dump-collect技能不支持 .NET Framework,因此请直接提供转储命令(例如procdump -ma <PID>,或在任务管理器中右键单击 →“创建转储文件”)。无需等待触发条件 — 只需在增长期间捕获跟踪即可。不要等待出现OutOfMemoryException。
GC 过度
分析 GC 事件、暂停时间和分配模式需要跟踪;仅有转储是不够的。
- Windows(PerfView):使用
PerfView collect /GCCollectOnly捕获 GC 事件。 - Linux(dotnet-trace):使用
dotnet-trace collect -p <PID> --profile gc-verbose。 - 启用 root 权限的 Linux .NET 10+:使用
dotnet-trace collect-linux --profile gc-verbose,获取包含本机堆栈的更丰富数据。 - 容器:
dotnet-monitor可以通过其 REST API(/trace?profile=gc-verbose)捕获 GC 跟踪。
请求缓慢
要排查请求缓慢,需要线程时间跟踪,以查看线程将时间花在了哪里——等待锁、I/O、外部调用等。请使用较大的缓冲区,因为线程时间跟踪会生成更多数据。对于 ASP.NET Core 应用,还要启用 Microsoft.AspNetCore.Hosting 和 Microsoft-AspNetCore-Server-Kestrel 提供程序,以获取服务端请求生命周期计时信息(请求到达的时间以及处理耗时)。
- Windows(PerfView):使用
PerfView /ThreadTime collect /BufferSizeMB:1024 /CircularMB:2048。/ThreadTime参数会添加线程级别的等待和阻塞详情。对于 ASP.NET Core,添加 Kestrel 提供程序:PerfView /ThreadTime collect /BufferSizeMB:1024 /CircularMB:2048 /Providers:*Microsoft.AspNetCore.Hosting,*Microsoft-AspNetCore-Server-Kestrel。默认情况下不要包含停止触发条件——让用户根据具体场景自行设计。 - Linux(dotnet-trace):
dotnet-trace默认会捕获线程时间数据——无需特殊参数。使用dotnet-trace collect -p <PID>。对于 ASP.NET Core,添加 Kestrel 提供程序:dotnet-trace collect -p <PID> --providers Microsoft.AspNetCore.Hosting,Microsoft-AspNetCore-Server-Kestrel。 - 启用 root 权限的 Linux .NET 10+:使用
dotnet-trace collect-linux --profile thread-time,获取包含本机堆栈的更丰富数据。对于 ASP.NET Core,添加:--providers Microsoft.AspNetCore.Hosting,Microsoft-AspNetCore-Server-Kestrel。 - 容器:
dotnet-monitor可以通过其 REST API(/trace?pid=<PID>&durationSeconds=30)捕获跟踪。
挂起
- 先从跟踪入手,了解线程正在执行什么。根据环境使用合适的跟踪工具(Windows 上使用带有
/ThreadTime的 PerfView,Linux 上使用dotnet-trace,启用 root 权限的 Linux .NET 10+ 上使用dotnet-trace collect-linux --profile thread-time)。跟踪可以揭示:- 活锁(线程不断循环但没有进展)——线程看起来很忙,但应用没有任何进展。
- 线程饥饿——ThreadPool 已耗尽,排队的工作项无法得到处理。这看起来可能像死锁,但根本原因不同。
- 是否有任何进展——如果某些线程仍在取得进展,问题可能是瓶颈,而不是真正的挂起。
- 如果跟踪无法解释挂起原因,问题可能是真正的死锁(线程在循环中相互等待)。此时,请调用
dump-collect技能来收集进程转储——不要直接提供转储命令。 - 使用调试器分析转储,检查线程堆栈并找出锁循环:
- Windows:使用带有 SOS 调试器扩展的 Visual Studio 或 WinDbg。
- Linux:使用带有 SOS 调试器扩展的
lldb。
网络问题
网络问题(下游服务返回 HTTP 5xx 错误、请求超时、连接失败、DNS 解析失败、TLS 握手失败、连接池耗尽)需要同时收集线程时间跟踪和网络事件提供程序。线程时间跟踪会显示线程阻塞的位置(下游调用缓慢、线程耗尽),而网络事件会显示请求的生命周期,包括哪些请求失败、返回了哪些状态码、DNS 解析和 TLS 握手耗时,以及请求从连接池获取连接时等待了多久。
对于 .NET Framework,PerfView /ThreadTime 已会收集相关网络事件(来自 System.Net ETW 提供程序),无需其他提供程序。
对于现代 .NET,必须显式启用 System.Net.* EventSource 提供程序:
| 提供程序 | 覆盖内容 |
|---|---|
System.Net.Http | HttpClient/SocketsHttpHandler — 请求生命周期、HTTP 状态码、连接池 |
System.Net.NameResolution | DNS 查询(开始/停止、耗时) |
System.Net.Security | TLS/SSL 握手(SslStream) |
System.Net.Sockets | 底层套接字连接/断开 |
System.Net.Http 的关键事件:RequestStart(scheme、host、port、path)、RequestStop(statusCode — 未收到响应时为 -1)、RequestFailed(超时、连接被拒绝等情况的异常消息)、RequestLeftQueue(从连接池获取连接的等待时间 — 表示连接池已耗尽)、ConnectionEstablished、ConnectionClosed。
在启用网络提供程序的情况下收集线程时间跟踪(仅适用于现代 .NET — .NET Framework 只需使用 PerfView /ThreadTime):
- Windows(PerfView):使用
PerfView /ThreadTime collect /BufferSizeMB:1024 /CircularMB:2048 /Providers:*System.Net.Http,*System.Net.NameResolution,*System.Net.Security,*System.Net.Sockets。对于 .NET Framework,省略/Providers标志 —/ThreadTime已包含网络事件。线程时间跟踪会显示线程阻塞的位置,而网络事件会显示哪些请求失败以及失败原因。 - Linux(dotnet-trace):
dotnet-trace默认会捕获线程时间数据,但指定--providers会覆盖默认设置,因此还必须包含--profile:dotnet-trace collect -p <PID> --profile dotnet-common,dotnet-sampled-thread-time --providers System.Net.Http,System.Net.NameResolution,System.Net.Security,System.Net.Sockets。 - Linux .NET 10+(以 root 身份运行):使用
dotnet-trace collect-linux --profile dotnet-common,cpu-sampling,thread-time --providers System.Net.Http,System.Net.NameResolution,System.Net.Security,System.Net.Sockets。 - 容器:
dotnet-monitor可通过其 REST API 使用自定义提供程序捕获跟踪。
程序集加载问题
对于现代 .NET,程序集加载问题(FileNotFoundException、FileLoadException、ReflectionTypeLoadException、版本冲突、在多个 AssemblyLoadContext 中重复加载程序集)需要从 Microsoft-Windows-DotNETRuntime 提供程序收集 程序集加载器绑定器事件,并启用 Loader 关键字(0x4)。这些事件会跟踪运行时程序集解析算法的每一步——探测了哪些路径、由哪个 AssemblyLoadContext 处理加载、加载是否成功,以及失败原因。对于 .NET Framework,使用同一提供程序和关键字进行基于 ETW 的收集也同样有效;此外,Fusion Log Viewer(fuslogvw.exe)无需跟踪即可诊断程序集绑定失败。
提供程序规范为 Microsoft-Windows-DotNETRuntime:0x4:4(提供程序名称、AssemblyLoader 关键字、Informational 详细级别)。
- Windows(PerfView):默认的 PerfView 跟踪已包含绑定器事件——只需运行
PerfView collect,无需额外提供程序。若要生成较小的跟踪文件,请使用PerfView collect /ClrEvents:Default-Profile,这会移除最详细的默认事件,同时保留诊断程序集加载问题所需的事件。 - Linux / 跨平台(dotnet-trace):使用
dotnet-trace collect --clrevents assemblyloader -- <path-to-built-exe>启动并跟踪进程,或使用dotnet-trace collect --clrevents assemblyloader -p <PID>附加到正在运行的进程。 - 具有 root 权限的 Linux .NET 10+:使用
dotnet-trace collect-linux --clrevents assemblyloader。 - 容器:
dotnet-monitor可通过其 REST API 使用加载器提供程序捕获跟踪。
对于启动时就失败的短生命周期进程(程序集加载问题中很常见),优先使用 dotnet-trace 启动方式(-- <path-to-built-exe>),而不是通过 PID 附加,因为进程可能会在你附加之前退出。
推荐工具时,请说明其中的取舍。例如:
- PerfView 提供更丰富的数据,但需要管理员权限;可在 Windows 上运行,包括 Windows 容器。
dotnet-trace无需管理员权限即可跨平台运行,但捕获的系统级详细信息较少。perfcollect可捕获原生调用堆栈,但需要管理员/root 权限。- 无法访问控制台时,
dotnet-monitor是容器/K8s 的最佳选择,但需要部署 sidecar 并配置身份验证。
步骤 3:指导数据收集
为推荐的工具提供具体命令。请从工具参考查找表中加载相应的参考文件,获取详细的命令行示例。
需要包含的关键指导:
- 安装:说明如何安装尚不可用的工具(例如
dotnet tool install -g dotnet-trace)。推荐多个工具时,需分别提供每个工具的安装和使用说明——不要只提及工具,却不展示如何安装和使用。 - PID 发现(在运行任何
-p <PID>命令前必须执行):先确认目标进程(例如:dotnet-trace ps、curl <monitor-endpoint>/processes,或在容器内运行ps)。即使预计应用在容器中的 PID 为 1,也要在收集前确认。 - 收集命令:提供要运行的确切命令,包括相关提供程序、输出格式和持续时间。
- 容器注意事项:
- 从容器内部收集:确保镜像中已安装工具,或使用
kubectl cp将工具复制进去。 - 从容器外部收集:将
dotnet-monitor用作 Sidecar,并使用共享诊断端口(/tmp中的 Unix 域套接字)。 - Kubernetes:将
dotnet-monitor用作 Sidecar 容器,或使用kubectl debug启动临时调试容器。
- 从容器内部收集:确保镜像中已安装工具,或使用
- 长时间运行的复现(Windows/PerfView):展示如何使用触发参数和循环缓冲区设置。
- 输出位置:说明收集的文件将保存在哪里,以及如何将其从目标环境复制出来以供分析。
- 制品交接清单:将跟踪文件交给他人分析时,需包含运行时版本、OS/内核、容器镜像标签或构建 SHA、PID/进程名称、UTC 收集开始/结束时间戳、所用的确切命令,以及最终制品路径。
步骤 4:推荐分析方法
收集数据后,推荐合适的分析工具。不要执行分析——只需将开发者指向合适的工具和文档。
| 收集的数据 | 分析工具 | 备注 |
|---|---|---|
.nettrace 文件 | PerfView(Windows)、Speedscope(Web) | PerfView 在 Windows 上可提供最丰富的视图 |
.etl / .etl.zip 文件 | PerfView | 来自 PerfView 或 perfcollect 的 ETW 跟踪 |
perfcollect 生成的 perf.data.nl | PerfView(Windows) | 将文件复制到 Windows 计算机上,并用 PerfView 打开 |
验证
- 推荐的工具与开发者的运行时、OS 和部署拓扑兼容
- 收集命令可无错误运行
- 输出文件已在预期位置生成
- 开发者知道该使用哪种分析工具处理收集的数据
常见陷阱
| 陷阱 | 解决方案 |
|---|---|
在 .NET Framework 上使用 dotnet-trace | dotnet-trace 仅适用于现代 .NET(.NET Core 3.0+)。对于 .NET Framework,请使用 PerfView。 |
| PerfView 未以管理员权限运行 | PerfView 需要管理员权限才能进行 ETW 跟踪。如果无法获得管理员权限,请改用 dotnet-trace。 |
在没有 SYS_ADMIN 的容器中使用 perfcollect | 容器默认会移除 SYS_ADMIN。请使用 --privileged 运行,或添加 SYS_ADMIN 能力;也可以改用 dotnet-trace。 |
| 长时间复现导致跟踪文件过大 | 在 Windows 上,使用 PerfView /StopOn 触发器,在出现你想要捕获的症状时触发(例如 /StopOnPerfCounter、/StopOnGCEvent、/StopOnException),并配合 /CircularMB 和 /BufferSizeMB。切勿在问题恢复时触发——循环缓冲区会持续覆盖旧数据,因此在停止收集时,重要行为可能已经丢失。 |
| 容器中无法访问诊断端口 | 将 /tmp 挂载为应用容器与 dotnet-monitor sidecar 之间的共享卷,用于诊断 Unix 域套接字。 |
| 忘记在容器映像中安装工具 | 在 Dockerfile 中添加 dotnet tool install,或使用 dotnet-monitor 作为 sidecar,以避免修改应用映像。 |
在生产环境中使用 --no-auth 暴露 dotnet-monitor | 保持启用身份验证,绑定到 localhost,并使用 kubectl port-forward 进行访问。仅在短时间、隔离的调试场景中使用 --no-auth。 |
| 网络问题只收集 CPU/线程时间跟踪 | 仅靠 CPU 和线程时间跟踪无法显示 HTTP 状态码、DNS 耗时或连接池行为。除了线程时间跟踪,还要添加网络提供程序(System.Net.Http、System.Net.NameResolution、System.Net.Security、System.Net.Sockets)。 |
| 只需一个网络提供程序却启用了所有提供程序 | 每个网络提供程序都会增加开销。如果问题明显属于 HTTP 层面(5xx 状态码),仅使用 System.Net.Http 可能就足够了。如果根本原因不明确,再添加 DNS、TLS 和套接字提供程序。 |