使用 Application Insights 探查 Azure 中的生产应用程序

Application Insights Profiler 针对 Azure 生产环境中运行的应用程序提供性能跟踪。 探查器:

  • 大规模自动捕获数据,且不会给用户造成负面影响。
  • 它有助于识别在处理特定 Web 请求时花费时间最长的“热”代码路径。

对应用程序启用 Application Insights Profiler

Profiler 中支持

Profiler 适用于以下 Azure 服务中部署的 .NET 应用程序。 在下面的链接中查看有关为每个服务类型启用 Profiler 的具体说明。

计算平台 .NET (>= 4.6) .NET Core Java
Azure 应用服务
Azure 虚拟机和适用于 Windows 的虚拟机规模集
Azure 云服务 空值
适用于 Windows 的 Azure 容器实例
适用于 Linux 的 Azure 容器实例
Kubernetes
Azure Functions
Azure Spring Cloud 空值
Azure Service Fabric

如果已启用 Profiler 但未看到跟踪,请查看故障排除指南

如何生成加载以查看 Profiler 数据

要使 Profiler 上传跟踪,应用程序必须主动处理请求。 只需单击一下,即可手动触发 Profiler。

假设要运行 Web 性能测试。 需要借助跟踪来了解 Web 应用在承受负载情况下的运行性能。 通过控制何时捕获跟踪,你会知道负载测试将在何时运行,但随机采样时间间隔可能会错过它。

通过启动 Web 性能测试生成发往 Web 应用的流量

如果最近启用了 Profiler,可以运行简短的负载测试。 如果 Web 应用已有传入流量,或者只想手动生成流量,请跳过负载测试并启动 Profiler 按需会话。

启动 Profiler 按需会话

  1. 在“Application Insights 概述”页中,从左侧菜单中选择性能

  2. 性能窗格中,从 Profiler 设置的顶部菜单中选择 Profiler

    Screenshot of the Profiler button from the Performance blade

  3. 加载 Profiler 设置页面后,选择立即配置文件

    Profiler page features and settings

查看跟踪

  1. Profiler 会话运行完成后,返回到性能窗格。

  2. 钻取...下,选择 Profiler 跟踪以查看跟踪。

    Screenshot of trace explorer page

跟踪浏览器会显示以下信息:

筛选器 说明
配置文件树 v. 火焰图 以树形式或图形形式查看跟踪。
热路径 选择以打开最大的叶节点。 大多数情况下,此节点与性能瓶颈相邻。
框架依赖项 选择以查看与跟踪关联的每个跟踪框架依赖项。
隐藏事件 键入要从跟踪视图中隐藏的字符串。 为建议选择“建议”事件
事件 事件或函数名称。 树中显示了代码与发生的事件(例如 SQL 和 HTTP 事件)的混合形式。 最前面的事件表示请求总持续时间。
模块 发生跟踪事件或函数的模块。
线程时间 从操作开始到操作结束之间的时间间隔。
时间线 运行函数或事件的时间,此值相对于运行其他函数的时间。

如何读取性能数据

Microsoft 服务探查器结合使用采样方法和检测来分析应用程序的性能。 当详细收集操作正在进行时,服务探查器将每隔一毫秒对每台计算机的 CPU 指令指针采样。 每个样本捕获当前正在执行的线程的完整调用堆栈。 它从高级抽象化和低级抽象化两个角度,提供有关线程当前行为的有用详细信息。 服务探查器还会收集其他事件(包括上下文切换事件、任务并行库 (TPL) 事件和线程池事件),以跟踪活动相关性和因果关系。

时间线视图中显示的调用堆栈是采样和检测的结果。 由于每个样本会捕获线程的整个调用堆栈,因此包含 Microsoft .NET Framework 中的代码,以及引用的其他框架中的代码。

对象分配 (clr!JIT_New or clr!JIT_Newarr1)

clr!JIT_New 和 clr!JIT_Newarr1 是 .NET Framework 中的 helper 函数,用于分配托管堆中的内存。

  • 分配对象时,将调用 clr!JIT_New。
  • 分配对象数组时,将调用 clr!JIT_Newarr1。

这两个函数通常可快速工作。 如果时间线中的 clr!JIT_New 或 clr!JIT_Newarr1 花费了时间,则可能表示代码分配了很多对象,从而消耗了大量的内存。

加载代码 (clr!ThePreStub)

Clr!ThePreStub 是 .NET Framework 中的帮助程序函数,用于准备初始执行的代码,通常包括实时 (JIT) 编译。 对于每个 C# 方法,在进程的生存期内,最多只应调用 clr!ThePreStub 一次。

如果 clr!ThePreStub 针对某个请求花费了额外的时间,则表示这是第一个执行该方法的请求。 .NET Framework 运行时需要大量时间来加载第一个方法。 请注意以下几点:

  • 在用户访问该代码部分之前使用执行该代码部分的预热进程。
  • 在程序集上运行本机映像生成器 (ngen.exe)。

锁争用 (clr!JITutil_MonContention or clr!JITutil_MonEnterWorker)

clr!JITutil_MonContention 或 clr!JITutil_MonEnterWorker 指示当前线程正在等待释放锁。 此文本通常在以下情况下显示:

  • 执行 C# LOCK 语句,
  • 调用 Monitor.Enter 方法,或
  • 使用 MethodImplOptions.Synchronized 属性调用方法。

如果线程 A 获取了某个锁,而线程 B 在线程 A 释放该锁之前尝试获取同一个锁,此时通常会发生锁争用。

加载代码 ([COLD])

如果 .NET Framework 运行时首次执行未优化的代码,则方法名称将包含 [COLD]

mscorlib.ni![COLD]System.Reflection.CustomAttribute.IsDefined

对于每个方法,在进程的生存期内,它最多只应显示一次。

如果针对某个请求加载代码花费的时间很长,则表示这是第一个执行该方法的未优化部分的请求。 请考虑在用户访问该代码部分之前使用执行该代码部分的预热进程。

发送 HTTP 请求

HttpClient.Send 等方法指示代码正在等待某个 HTTP 请求完成。

数据库操作

SqlCommand.Execute 等方法指示代码正在等待某个数据库操作完成。

等待 (AWAIT_TIME)

AWAIT_TIME 指示代码正在等待另一个任务完成。 这种延迟会发生在 C# AWAIT 语句上。 当代码执行 C# AWAIT 时:

  • 线程展开并将控制权返回到线程池。
  • 没有阻止的线程等待 AWAIT 完成。

但是,从逻辑上讲,执行 AWAIT 的线程会被“阻止”,等待该操作完成。 AWAIT_TIME 语句指示等待任务完成的阻止时间。

阻塞时间

BLOCKED_TIME 指示代码正在等待另一个资源变为可用。 例如,它可能在等待:

  • 同步对象
  • 要可用的线程
  • 完成请求

非托管异步

为了跨线程跟踪异步调用,.NET Framework 发出 ETW 事件并在线程之间传递活动 ID。 由于非托管 (本机) 代码和某些较旧的异步代码样式缺少这些事件和活动 ID,因此 Profiler 无法跟踪线程上运行的线程和函数。 这在调用堆栈中标记为“非托管异步”。 下载 ETW 文件以使用 PerfView 获取更多见解。

CPU 时间

CPU 正忙于执行指令。

磁盘时间

应用程序正在执行磁盘操作。

网络时间

应用程序正在执行网络操作。

“时间”列

“时间”列是针对节点收集的各种“非独占”样本随时间发生的可视化效果。 请求的总范围被划分为 32 个时间段,节点的非独占样本在其中累积。 每个存储桶用一个条形表示。 条形的高度表示缩放后的值。 对于以下节点,条表示存储桶中某个资源的消耗量:

  • 标记为 CPU_TIMEBLOCKED_TIME 的节点。
  • 与使用资源 ((例如 CPU、磁盘或线程) )具有明显关系的节点。

如果消耗多个资源,这些指标的值可能大于 100%。 例如,如果在某个时间间隔内平均使用两个 CPU,则指标值为 200%。

限制

默认数据保留期为 5 天。 每天引入的最大数据量为 10 GB。

使用 Profiler 服务没有任何费用。 要使用该服务,Web 应用必须至少托管在 Azure 应用服务 Web 应用功能的基本层中。

开销和采样算法

在托管的应用程序已启用 Profiler 来捕获跟踪的每个虚拟机上,Profiler 每小时随机运行 2 分钟。 Profiler 在运行时会给服务器增加 5% 到 15% 的 CPU 开销。

后续步骤

为 Azure 应用程序启用 Application Insights Profiler。 另请参阅: