使用 ANTS Performance Profiler 6 进行多层性能调优





0/5 (0投票)
当您开发一个存在 I/O 瓶颈的数据库应用程序时,您需要全面了解应用程序的所有层是如何协同工作的。Jeremy Jarrell 使用 ANTS Performance Profiler 6 快速找到了他代码中的瓶颈及其负责的存储过程。
数据,数据,数据
所有优秀的报告和分析产品的核心都是数据……大量的数据。事实上,有人认为报告应用程序的真正有效性直接与其能处理的数据量成正比。
SalesCenter by Matrix Solutions 是面向媒体行业的战略销售分析工具的领先提供商,它通过允许用户筛选大量原本会让人不堪重负的收入数据来使其用户受益。
跨越多个层
SalesCenter 必须每天导入非常大的文件,以确保它拥有我们客户报告所需的最新的信息。然而,随着这些文件越来越大,导入所需的时间也越来越长。由于导入过程可能会对 SalesCenter 的响应时间产生不利影响,因此导入时间必须尽可能短。
为了进一步使问题复杂化,导入例程遇到了几个常见的瓶颈……
- CSV 文件从磁盘读取和写入磁盘,造成文件 I/O 瓶颈。
- 在大型内存数据集上执行繁重的计算,造成应用程序逻辑瓶颈。
- 将结果信息与 SQL Server 实例进行比较并保存到其中,造成数据库瓶颈。
调整三种不同类型的瓶颈通常非常耗时,因为通常需要不同的工具来分析每种类型。此外,由于每个工具通常不知道其他工具的结果,我们只能通过将三个独立的输出拼凑在一起,像拼图一样,才能获得一个完整的图景。
找到瓶颈
以前,我们不得不通过应用程序代码分析器结果的排除法来确定磁盘 I/O 和数据库瓶颈,而 ANTS Performance Profiler 6 现在将所有三个瓶颈源的信息直接合并到结果中,使我们能够立即判断我们的瓶颈是与代码相关、与磁盘相关还是与数据库相关。
如果问题与数据库相关,ANTS Performance Profiler 还会向我们显示运行时间最长的存储过程,这样我们就不必自己花费大量时间查看分析器结果来确定相同的信息。
在对导入过程进行全程分析后,我们得到了一个完整的端到端图景,清楚地了解了我们的瓶颈实际在哪里。
我们从检查应用程序代码开始。通过反复深入调用堆栈,我们最终可以找到最耗时的那个方法。我们最耗时的那个方法称为 GetImportedDRBRows()
,它是 ImportDBAdapter
类的一部分。GetImportedDRBRows()
负责检索数据库中的新记录,以便按照我们的业务规则进行处理。
然而,一旦我们检查了 GetImportedDRBRows()
方法的内部,我们就遇到了一个问题。尽管我们知道 GetImportedDRBRows()
是我们当前瓶颈所在,但该方法中没有任何看起来特别可疑的地方。事实上,当我们查看源视图的“时间(秒)”列时,我们发现只有很少的方法消耗了任何时间。看起来这个方法比表面上看起来要复杂得多,但究竟是什么呢?
如果我们查看堆栈跟踪,我们会发现 GetImportedDRBRows()
的持续时间报告为 48.816 秒,但我们看到的源视图中的逐行计时显示,其中只有很少一部分时间与此相关。但等等,我们一直在检查方法的 CPU 时间,而不是实际经过的时间(Wall-clock times)。
ANTS Performance Profiler 可以以 CPU 时间或实际经过的时间(Wall-clock time)来测量时间。CPU 时间仅测量当前线程实际执行的时间(或未阻塞),而实际经过的时间测量线程开始以来的总经过时间。在许多情况下,这两个值之间的差异可以忽略不计;但是,如果某个特定方法碰巧调用外部资源(如数据库),那么这两个时间可能会发生巨大变化。让我们看看 GetImportedDRBRows 的实际经过时间……68.404 秒。这比 CPU 时间增加了 40%!这个方法肯定有什么问题,但是什么呢?根据我们对代码库的了解,我们知道 GetImportedDRBRows()
与我们的 SQL Server 实例进行了交互,所以我们的瓶颈最有可能在那里。在 ANTS Performance Profiler 的最新版本之前,我们必须在此阶段启动 SQL Server Profiler 来了解我们的瓶颈在哪里,但现在我们可以直接在分析器中检查与 SQL Server 的交互,而无需离开分析器。
要查看 SQL Server 分析结果,只需在 ANTS Performance Profiler 的左上角下拉菜单中选择 SQL Server。分析器现在列出了在分析会话期间在我们的 SQL Server 实例上运行的所有存储过程。默认情况下,此列表按“时间”排序,以立即引起我们对任何潜在瓶颈的注意,但我们也可以按“命中次数”排序,以查找可能运行次数过多而不必要的“热点”存储过程。请注意,我们的存储过程的总持续时间已经可用,并且相同存储过程的多个出现已折叠在一起,以显示该存储过程所有运行的总持续时间。如果使用 SQL Server Profiler 分析相同的会话,我们将不得不手动计算相同的信息。
但这是整个分析会话,我们怎么知道哪一部分对应于我们在性能分析视图中找到的代码部分呢?这就是事件时间线发挥作用的地方。注意显示在我们时间线中间的浅绿色条。这是我们在性能分析视图中选择 GetImportedDRBRows()
时可见的相同绿色条。此条表示 GetImportedDRBRows()
处于活动状态的时间段。仅选择包含此绿色条的时间段,我们可以将分析器结果限制为仅包含在 GetImportedDRBRows()
方法执行期间运行的存储过程。
我们立刻可以看到,我们最大的瓶颈是(不出所料)dbo.GetImportDRBS
存储过程。虽然我们仍然需要检查存储过程本身以确定如何最好地对其进行调优,但我们已经能够轻松地确定瓶颈的确切位置。
请注意,ANTS Performance Profiler 还提供文件 I/O 视图,使我们能够轻松识别应用程序在读写磁盘时遇到的最大瓶颈。这有助于我们真正了解文件 I/O 对我们系统的影响,并确定考虑替代存储实现(例如减少磁盘访问次数的内存映射文件)是否值得我们付出努力。
文件 I/O 视图还有助于我们快速发现由于看似无害的磁盘访问引起的瓶颈,例如快速将数据写入临时文件或重复从配置文件读取。下图红色矩形中高亮的绿色区域表示在选中文件 clean_00000.csv 被读取的时间点。
结论
在不仅确定了瓶颈开始的代码区域,还确定了负责的确切存储过程之后,只需对该存储过程内的查询进行一些调整即可大大提高其性能。通过提高该存储过程的性能,我们可以明显提高我们导入例程该部分的性能。
通过不仅分析我们的应用程序代码,还理解我们应用程序的所有层是如何协同工作的,我们能够显著减少导入过程所需的时间,从而明显改善我们为客户提供的 SalesCenter 的性能。但是,同样重要的是,我们也了解到,要 解决我们项目中的性能问题,有时我们必须超越 .NET 代码。