查找 Windows 服务中的性能瓶颈及其解决方案






4.70/5 (10投票s)
本文将介绍用于识别瓶颈的工具和技术以及性能改进的关键考虑因素。
作者:Sajid Majeed
引言
据观察,许多批处理过程在开发时并未考虑性能参数。原因可能是“这是夜间计划作业,不管它消耗多少 CPU/内存”或“这是一个后台作业;没有用户交互。如果它多花费一个小时,有什么问题吗?”
但是,如果一个企业使用多个夜间作业,会发生什么?或者,如果其他部门在白天晚些时候需要该批处理作业的结果,会发生什么?
如果我们以银行业为例;数据收集、数据处理和规则验证服务已成为其业务的关键部分,它们与许多第三方服务和数据服务器交互以同步和验证其数据等。在这种情况下,来自任何新供应商的单个糟糕的服务都可能给企业带来问题。
本文实际上基于一个案例研究,其中需要改进一个功能稳定且经过测试的 .Net Windows 服务,该服务将部署在美国一家企业银行的企业服务器上。
本文将介绍用于识别瓶颈的工具和技术以及性能改进的关键考虑因素。
如何识别问题区域?
常识是,如果你不知道什么和在哪里需要治疗,你就无法治愈。
时间记录
这是被证明是最佳的策略,在每个函数的前后将时间戳写入文本文件。处理完成后;您可以分析文本文件。但是,如果文本文件增长到 MB,则分析它是一项繁琐且耗时的活动。您需要做的是“智能地记录时间戳文本”。这可以通过添加一些分隔符来完成,以便您可以轻松地将此文件导入 Excel 或数据库表。
将其放入数据库表中可以为您提供更多帮助,因为可以轻松查询并获取趋势和问题区域。在这里,您可以看到每个函数花费了多少时间。一旦获得函数的高级计时,您就可以轻松识别花费时间超过预期的函数。现在,将此日志记录活动细化到该函数(们)的每个语句,并进行分析。可以轻松找到罪魁祸首语句(们)。
这是一项繁琐的活动;但随着时间的推移,事实证明,这种策略将告诉您在代码执行时实际发生了什么。
.NET:HiResTimer 类
这个简单的小 C# 类封装了 Kernel32 的 QueryPerformanceCounter API,并返回代码语句所花费的时间。此已用时间也可以用作时间记录,而不是记录当前时间。
下面的代码取自 http://www.windojitsu.com/code/hirestimer.cs.html。此链接包含此类及其用法的源代码。
用法很简单
|
分析
这是一种自动化方法,可以在几分钟内实时识别可疑区域。市面上有多种工具可用于分析数据库和 .net 程序集。
数据库分析
SQL Server 2000 和 2005 的企业版内置了分析工具。有几个内置模板;但很多时候您需要自己的模板来识别查询/操作计时等。
请记住,在使用分析时,日志记录活动可能不会显示正确的结果.
除了这些内置分析器外,市面上还有其他非常有用的数据库分析工具。Idera 工具(SQL diagnostic manager)是一个很好的数据库分析示例。它为您提供查询执行时间、CPU 和内存使用情况、阻塞命令、锁、表和索引运行状况等。此外,它还会突出显示花费时间超过指定时间的命令。以下是该工具的一些屏幕截图。
使用此工具,您可以获得糟糕查询的列表。需要将这些查询搜索到源代码和存储过程中,DBA 和数据库开发人员可以使用不同的优化策略进行优化。可能存在全表扫描、错误的索引、死锁、等待等。如果 DBA 或数据库架构师不了解您应用程序的业务,那么他或她心中应该有一个清晰的目标和界限。在修复性能问题部分提到了一些要点
应用程序分析
查找应用程序(.NET 代码)中的性能瓶颈非常重要。有许多工具,如 Jet Brains 的 dotTrace 和 Red Gate 的 ANTS profiler。这些工具帮助我们确定了问题的根本原因。它们实际上是手动时间戳日志记录策略的自动化替代方案,
在我们的案例研究中,我们使用了并评估了 ANTS profiler 3
作为分析的结果;该工具为您提供了已为进程调用的所有方法的列表,以及花费的时间、包含子进程花费的时间以及最重要的命中次数。此分析工具附带源代码信息,并帮助您向下钻取层次结构并显示每行代码花费的时间。您可以轻松识别执行时间超过预期的代码区域。以下是该工具的屏幕截图。
使用性能计数器的性能监视器
可以从“控制面板”->“管理工具”->“性能”访问此诊断工具。您需要智能地添加性能计数器。最重要的是 SQL Server、.NET 和 ASP.NET 性能计数器。这可以帮助您识别表扫描、索引扫描、锁请求、死锁数量、GC 消耗时间等等。
重要的性能计数器列于下文
性能计数器 |
注释 |
SQLServer:Access Methods - Full Scans / sec |
大于 1 或 2 的值表明我们有表/索引页扫描。我们需要分析如何避免这种情况。 |
SQLServer:Access Methods - Page Splits/sec |
有趣的计数器,可以引导我们了解表/索引设计。此值需要尽可能低。 |
SQLServer:Access Methods - Table Lock Escalations/sec |
这显示了每秒请求表锁的次数。高数字需要重新审视查询和表上的索引。 |
SQL Server:Buffer Manager - Buffer cache hit ratio |
在内存中找到的页面百分比。值越高越好。首选大约 90%。这包括系统中过程和数据缓存的可用性。 |
SQL Server:Buffer Manager - Database pages |
此数字显示构成 SQL 数据缓存的页面数量。此值的大幅变化表明数据库正在从缓存中交换缓存值。我们需要增加系统的内存或 max server memory 参数。 |
SQL Server:Buffer Manager - Procedure cache pages |
这表示缓存中过程的数量。这是存储编译查询的位置。 |
SQL Server:Buffer Manager - Stolen pages |
这是为了满足其他内存请求而从缓冲区缓存中“窃取”的页面数量。 |
SQL Server:Cache Manager - Cache hit ratio |
缓存命中和未命中之间的比率。此计数器是我们 SQL Server 中缓存机制的一个良好指标。此值需要很高。 |
SQL Server:Databases - Active Transactions |
系统中当前活动的事务数量。 |
SQL Server:Databases - Log growths |
日志文件扩展的次数。如果此计数器活动很多,我们需要为日志文件分配足够大的静态空间。 |
SQL Server:Databases - Transactions/sec |
此数字表示 SQL Server 系统的活跃程度。较高的值表示正在发生更多的活动。 |
SQL Server:General Statistics - User Connections |
当前连接到 SQL Server 的用户数量。 |
SQL Server:Locks - Lock Requests/sec |
每秒请求某种类型的锁的数量。 |
SQL Server:Locks - Average Wait Time |
这是获取锁的平均等待时间(以毫秒为单位)。值越低越好。 |
SQL Server:Locks - Number of Deadlocks/sec |
导致死锁的锁请求数量。 |
SQL Server:Memory Manager - Optimizer Memory |
服务器用于查询优化的内存量(以 KB 为单位)。我们需要此计数器保持稳定值。值的大幅波动表明正在执行大量动态 SQL。 |
SQL Server:Memory Manager - Connection Memory |
用于维护连接的内存量(以 KB 为单位)。 |
SQL Server:SQL Statistics - SQL Compilations/sec |
每秒发生 SQL Server 编译的次数。此值需要尽可能低。 |
SQL Server:SQL Statistics - SQL Re-Compilations/sec |
我们系统中的这个值需要尽可能为零。重新编译可能导致死锁和不兼容任何锁类型的编译锁。 |
Processor - %Processor Time |
处理器花费在执行非空闲线程上的时间百分比。从处理器空闲的时间(100%)中减去此值。这是系统整体 CPU 利用率的指标。 |
Processor - %Interrupt Time |
处理器花费在处理硬件中断上的时间百分比。这可以是服务器上的任何活动。在我们的测试过程中,此值需要为 0。 |
Processor - Processor Queue Length |
此计数器指示等待处理器队列的线程数。也可以解释为等待处理器运行的线程数。如果此值大于处理器数量,则系统中存在 CPU 瓶颈。 |
Processor - Context Switches/sec |
这是一个有趣的计数器。当操作系统或应用程序被迫将一个处理器上的执行线程更改为另一个处理器上的执行线程时,就会发生典型的上下文切换。此值必须尽可能小。在多处理器机器上,上下文切换是不可避免的。因此,低于 10000 的任何值都可以。 |
PhysicalDisk - %Disk Read Time |
磁盘用于读取操作的时间。我们还可以进行逐磁盘分析,以缩小任何读取 IO 瓶颈的范围。 |
PhysicalDisk - %Disk Write Time |
磁盘用于写入操作的时间。我们还可以进行逐磁盘分析,以缩小任何写入 IO 瓶颈的范围。 |
PhysicalDisk - Avg. Disk Queue Length |
特定磁盘上等待读写请求的平均请求数。高值表明存在 IO 瓶颈。 |
Memory - Page Faults/sec |
处理器每秒处理的总页面错误数。此值需要尽可能小。 |
Memory - Pages/sec |
为了解决页面错误而写入磁盘或从磁盘读取的页面数量。这将是 page reads/sec 和 page writes/sec 计数器的总和。 |
ASP.NET 性能计数器在 MSDN 网站上提供,对于理解计数器的重要性和用法非常有帮助。
以下是进程监视工具的示例屏幕截图。
解决性能问题的关键考虑因素
通常,性能问题会在应用程序开发完成后或在开发的最后阶段或在生产环境中出现。通过应用最佳性能和优化实践,可以预防这些问题,但最重要的是考虑优化和可伸缩性。
优化用户交互式应用程序比后台批处理过程要容易得多,因为在用户交互式应用程序中,应用程序的一部分会针对任何事件执行,而在后台过程中情况可能不同。
在修复性能问题时;以下是要牢记和列入议程的关键点。
-
修复应由开发团队进行,该团队开发了模块或正在处理该应用程序。因为将此任务交给某个技术专家组会导致大量的重构建议。
-
修复时应牢记不应更改模块/函数/过程的签名或契约。否则,开发和测试活动可能会延长,风险也会增加。
-
智能地应用多线程方法可以在多核机器上产生更好的结果。
-
始终在应用修复后执行问题识别技术,作为试金石。
-
如果您只执行几个周期的过程,就无法判断性能的行为。对于真实数据,您需要长时间多次执行过程,以便可以识别内存使用量或 CPU 使用量是否随时间增加。
硬件规格和环境软件
进行一些修复和应用优化技术并不总是能解决性能问题。您还必须关注硬件和软件。
例如,增加 RAM 或更强大的 CPU 可以提高性能。但是软件(操作系统和数据库服务器)必须与硬件兼容。例如;在具有 2 个或更多 CPU 和 5GB 或更高 RAM 的服务器级机器上,这些软件的标准版可能无法正常工作。同样,开发版、工作组版或标准版也有其自身的限制。因此,智能地推荐硬件和软件规格也可以达到目的。
请记住;由于硬件和软件组合不佳而导致的性能问题永远无法在有限的时间内通过编程方式得到改善。
“有时糟糕的代码可以在好机器上生存”,作者 Fraz Hassan
最佳实践分析器工具
Microsoft 推出了一些有用的分析器工具,它们将审查您的代码并指出未遵循最佳实践的区域。Microsoft FxCop 和 Microsoft SQL Server Best Practice Analyzer 是很好的例子。
致谢
特别感谢我的朋友 Fraz Hassan(Fraz.Hassan@systemsltd.com);我们一起使用本文讨论的工具和技术成功地识别和解决了性能问题。
参考文献
http://www.windowsitlibrary.com