衡量和监控 WCF Web 服务性能





5.00/5 (17投票s)
使用 ServiceMon 获取 Web 服务的性能统计信息。
引言
今年早些时候,我工作的软件公司发布了 RightCalc,这是一个旨在使保险公司能够集中管理其价格的解决方案。
在启动之前,我们需要确保系统能够处理预期的流量,同时仍然能够对大多数请求做出可接受的响应。未能做到这一点可能会导致客户不满以及保险公司销售额损失。这一需求促使了 ServiceMon 的开发。
背景
在进行任何性能测试之前,了解要实现的目标至关重要,这需要建立一个关于服务将如何使用的现实情况。对于 RightCalc,我们很幸运在系统开发的早期就就性能目标达成了一致。这些是我们商定的基准。
1. 典型负载测试
系统必须能够处理每秒 3 个请求 的典型负载,并继续以50ms或更低的响应时间为99%或更多的请求提供可观的响应。我们预计这对于系统上线后的最初几个月来说足够了。
2. 持久性测试
确保系统能够以每秒 1 个请求 的持续负载运行 1 年,而无需任何手动干预。系统应在测试期间保持稳定的响应速率。
3. 峰值测试
确保系统能够处理短暂的、高强度的流量峰值,而不会导致数据丢失或性能大幅下降。系统必须能够处理偶尔的、高强度的负载,即每秒 100 个请求,持续 30 秒,同时仍能在 100ms 内响应 99% 的请求。
引入 ServiceMon
我们专门为 RightCalc 项目开发了 ServiceMon,以帮助监控关键网页和 Web 服务,并施加负载并收集统计数据,以证明系统能够处理上述三种情况。
当我们找不到合适的监控解决方案时,我们决定构建一个能在 Windows 上运行、可扩展且易于配置的解决方案。我们需要一个易于配置的解决方案,以便能够开发临时测试来根据结果探索新的研究方向,同时仍然能够管理一个标准的、持续运行的监控套件,该套件可以使用 Subversion 等标准工具以类似源代码的方式进行版本控制。
上周,Kaleida 决定将 ServiceMon 作为开源软件根据 GPL 许可协议 发布给社区,希望其他开发人员、QA 和运维人员能够从该工具中受益。
ServiceMon 的工作原理是执行一个非常简单的脚本,包含类似以下的操作:
http-get "http://www.google.com" must-contain "<title>Google</title>"
脚本可以包含任意数量的操作,但它们都遵循请求然后响应处理程序的结构。操作的请求部分,http-get
,会在定时器滴答时执行(默认每秒一次),然后等待接收响应。当响应到达时,它会被交给响应处理程序,在本例中是must-contain
,它会检查 HTML 是否包含指定的短语。
当一个操作正在等待接收响应时,脚本执行将继续,后续操作将在每个新的定时器滴答时继续执行。
如果请求或响应处理程序不成功,则会记录一次失败,屏幕也会相应改变以反映这一点。
有许多内置的请求类型,可用于常见的测试场景,例如监控网页是否可用或 ping 服务器。
为了生成专有 SOAP Web 服务的性能统计数据,我们需要编写自定义的请求类型。稍后我们将讨论如何做到这一点(别担心,这非常简单!),但首先,我们将仔细看看 ServiceMon 生成的统计数据类型。
响应时间统计
生成响应时间分布图是建立 Web 服务性能特征图的绝佳方法。
首先,我们在服务器负载稳定时,在较长一段时间内发送大量请求。然后,在记录了每个请求所需的时间后,我们找到合适的“存储桶”并将其项目计数加一。
假设我们发送了 100 个请求,并将它们花费的时间记录在 10ms 宽的“存储桶”中。我们可能会看到类似以下的结果:
响应时间 (ms) | Count |
0-10 | 0 |
11-20 | 2 |
21-30 | 49 |
31-40 | 22 |
41-50 | 12 |
51-60 | 8 |
61-70 | 4 |
71-80 | 2 |
81-90 | 1 |
91-100 | 0 |
当这些值绘制出来时,我们通常会看到这种特征曲线。
峰值的位置显示了最常遇到的响应时间;越靠左越好。
形状和尺度也很重要。细长的峰值是理想的,表明 Web 服务提供一致的响应时间 - 大多数访问者将有类似的等待时间。大的分布范围和延长的右尾是不理想的,需要进一步调查以确定响应时间为何如此可变。
理想情况下,图表应包含一个峰值。如果存在次峰值,则应进行调查,这可能表明一个频繁发生的后台任务影响了很大比例的请求的处理,例如备份作业或重新索引任务。
对于某些目的,例如SLA,通过指定一些“九”来定量描述曲线很有用。
- 90% 的请求耗时少于 60ms
- 99% 的请求耗时少于 80ms
- 99.9% 的请求耗时少于 90ms
- 99.99% 的请求耗时少于 90ms
对于网站和间接被人类使用的 Web 服务,您的目标响应时间应考虑人类对时间的感知。研究表明,在 100ms 内收到的响应感觉是即时的,在 1000ms(1 秒)内是可容忍的,但任何超过 10,000ms(10 秒)的时间都足以让用户失去兴趣而做别的事情。
使用 ServiceMon 查看统计信息
现在我们已经了解了网站或 Web 服务的性能度量,我们将使用 ServiceMon 来生成这些统计数据。
在此示例中,我们将创建一个包含一个操作的脚本 - 一个简单的 HTTP GET 请求。
一个警告:请勿对您不拥有的网站或 Web 服务运行侵略性的性能测试。 向别人的 Web 服务器发送数千个请求是不礼貌的 - 在许多国家都是非法的 - 并且可能被视为拒绝服务攻击。至少,您的 IP 地址可能会被限制或阻止。
要开始监控,请按 ServiceMon 上的“开始”按钮。屏幕将自动切换到“10 英尺”状态显示,该显示设计为远距离查看。
绿色的背景和笑脸表示监控正在进行且未检测到错误。我们可以通过查看显示每个接收到的单独响应的“响应”选项卡来查看更多详细信息。然而,真正令人感兴趣的是可通过“统计信息”选项卡查看的响应时间分布图。此图每秒更新一次,运行一段时间后,将看起来像这样:
这张图现在绘制在对数 x 轴上,以揭示驼峰的细节,符合预期的形状。它一目了然地表明,大多数请求都在大约 10ms 内发送、处理和接收。可以通过查看右侧框中的“九”值来确认:99% 的请求在 15ms 内处理;99.9% 在 25ms。请注意,99.99% 的数值为何明显高于其他数值(191ms)?这表明了获得足够大的样本量的重要性。此测试运行仅发送了约 2,800 个请求,由于数量少,一个慢响应就会将 99.99% 的值推高。我们需要数万个请求才能获得值得信赖的数字。
此测试是在服务器没有后台负载的情况下进行的,测试负载为每秒 2 个请求(每 500 毫秒 1 个)。为了建立更全面的性能配置文件,我们需要在不同的后台负载和不同的测试负载下重复测试。可以使用 ServiceMon 来完成这两项工作,方法是创建两个脚本,在实用程序的两个不同实例中运行。一个实例将用于施加后台负载,然后一个或多个额外的 ServiceMon 实例将施加测试负载并生成实际统计数据。我们在 RightCalc 上线前进行测试时采用了这种方法,并继续使用它来评估实时服务的性能问题。
创建自定义 ServiceMon 请求类型
到目前为止,我们已经介绍了如何使用内置的 http-get
请求类型来构建网站的性能配置文件。但是,我们如何测试一个 SOAP Web 服务,它需要的不只是一个 URL 来调用?
SOAP 消息将有一个头部,其中可能包含身份验证令牌和路由信息,以及一个包含请求数据的正文。 每个 SOAP 服务和 Web 方法都有其特定的要求,这使得像 ServiceMon 这样的工具难以以通用方式支持。
幸运的是,ServiceMon 是以可扩展的方式构建的,允许新的请求类型和响应处理程序轻松插入其框架,然后以与内置操作相同的方式使用。
我们将从创建一个新的 ServiceMon 请求开始,该请求调用 W3Schools 提供的示例 Web 服务,该服务只需将摄氏度转换为华氏度。
首先,我们需要创建一个新的 Visual Studio 类库解决方案。
然后,添加对 ServiceMon 框架的引用(它将位于与 ServiceMon.exe
相同的位置,通常在 C:\Program Files (x86)\Kaleida\ServiceMon
)。
Kaleida.ServiceMonitor.Framework.dll
最后,创建一个名为 GetCelsius
的新公共类,该类派生自 PreparedRequest
。
要创建新的请求类型,我们只需做到这一点。显然,它还没有调用 Web 服务,但我们有足够的内容可以在 ServiceMon 中对其进行测试。
构建 DLL 后,将其复制到与 ServiceMon.exe
相同位置的 Operations
文件夹(通常是 C:\Program Files (x86)\Kaleida\ServiceMon\Operations
)。
重新启动 ServiceMon,要验证 DLL 是否已成功发现,请查看 ServiceMon 中的“帮助”选项卡。
新的请求类型将列出,名称为 get-celcius
,该名称源自类名。请注意,它尚未接受任何参数,也没有描述。我们稍后会处理。
您现在可以像使用任何内置请求一样使用此请求。创建一个新脚本并添加此行:
get-celsius log-response
当您单击“开始”按钮并查看“响应”选项卡时,您将看到类似如下的内容:
03-Oct-2012 13:05:24.329 0ms [no description present] and log response my response
接下来,我们将回到我们的 Visual Studio 解决方案来完成。
如果没有指定华氏度值,get-celsius
请求就没有什么用处。我们通过向类添加一个带有字符串参数的公共构造函数来实现这一点。
public class GetCelsius : PreparedRequest { private string fahrenheit; public GetCelsius(string fahrenheit) { this.fahrenheit = fahrenheit; }
现在我们需要添加对 Web 服务的引用,并完成 GetResponse
的实现。
Web 服务代理是使用项目菜单上的“添加服务引用...”选项生成的。
这是要添加到 GetResponse
的代码,以便使用我们的华氏度值实际调用 Web 服务。
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None); var endpoint = new EndpointAddress("https://w3schools.org.cn/webservices/tempconvert.asmx"); var soapClient = new TempConvertSoapClient(binding, endpoint); return soapClient.FahrenheitToCelsius(fahrenheit);
最后,我们将覆盖 Description
属性。这是完成的类:
就是这样!将新 DLL 复制到 Operations 文件夹,并更改脚本以指定华氏度值。
get-celsius "98.6" must-equal "37"
单击“开始”,ServiceMon 将开始监控 tempconvert
Web 服务,并在其未能返回预期结果的时刻通知您。
为了监控 RightCalc,我们有许多这样的自定义请求类型,每种 Web 服务一种。我们的脚本不断监控实时系统和不同暂存平台上的网页和 Web 服务,以便在出现任何实时问题或开发管道中的潜在回归时立即通知我们。我们的系统已经运行了六个多月,ServiceMon 已被证明是一个无价的工具。
我们希望您发现 ServiceMon 有用,如果您有任何问题或想帮助构建新的扩展,请随时与我们联系。
项目的首页、最新下载和所有文档可以在这里找到:ServiceMon 首页
历史
初稿:2012 年 9 月 6 日
更新以反映 ServiceMon 新版本中的更改:2012 年 9 月 17 日
更改标题并更新从 v1.0 截取的屏幕截图:2012 年 10 月 3 日
将许可证更改为 GPLv3 并包含 Article 的 ServiceMon v1.0 源代码。删除指向公司的链接:10 月 8 日