基于SOAP的COM+组件压力测试工具





5.00/5 (1投票)
2002年7月31日
6分钟阅读

57663

853
此工具解析 SOAP 请求并调用 COM+ 组件进行压力测试。
引言
COM+ 用于开发可伸缩应用程序。您已经完成了组件,并将其放入 COM+。现在您想知道组件的可伸缩性如何?问题来了,如何衡量 COM+ 应用程序的可伸缩性?基本上,有两种主要指标可以衡量 COM+ 应用程序的可伸缩性:不同用户负载下的延迟和吞吐量。
延迟通常称为响应时间。从客户端的角度来看,它是从发出请求到在客户端接收到服务器响应之间经历的延迟。通常以时间单位衡量,例如秒。在某些测试工具中,例如 Microsoft® Web Application Stress (WAS) 工具,延迟最好通过“最后一个字节时间”(TTLB) 这个指标来表示,该指标计算从发送网页请求到接收完整页面内容的最后一个字节之间的时间。
下面是典型的延迟与用户负载曲线。
图 1. 延迟与用户负载的典型特征
吞吐量是衡量分布式应用程序可伸缩性的另一个非常有用的指标。它是应用程序在一定时间内可以处理的客户端请求数量。通常,度量单位是每秒请求数。它可以帮助识别性能瓶颈并改进应用程序和系统性能。图 2 展示了吞吐量与用户负载的典型特征。
图 2. 吞吐量与用户负载的典型特征
给定这些指标,我们如何了解 COM+ 应用程序的这些指标呢?答案是进行压力测试。但是如何测试呢?Microsoft 和其他供应商提供 Web Application Stress (WAS) 工具等测试工具,但它们主要侧重于 Web 应用程序的压力测试。它们向 Web 应用程序发送 HTTP 请求进行测试,并且主要与分布式应用程序的表示层进行交互。不幸的是,当表示层完成时,通常为时已晚,如果发现指标未达到设计目标。我们需要在测试整个 Web 应用程序之前测试数据层和业务逻辑层,以确保不良性能不会传播到下一层。
这就是这个压力测试工具的用武之地。它主要侧重于数据层和业务层的压力测试。它至少可以在两种场景中使用。第一种是在数据层和业务层完成后对其进行压力测试,以确保它们达到设计目标。另一种是在 WAS 等其他压力测试工具发现 Web 应用程序的可伸缩性不佳时,对数据层和业务层进行故障排除。
此工具使用的技术
设计目标之一是使此工具适用于所有支持 IDispatch
的组件。为了使此工具功能强大、灵活且易于使用,我将其基于 SOAP 协议。SOAP 协议非常适合描述对组件的方法调用。它使用丰富的类型系统,该系统包含您在编程语言中可能使用的绝大多数类型。同时它易于使用和解析。至于 SOAP 请求,它可以指定请求消息的命名空间 URI 所使用的组件的 ProgID。例如,下面的 SOAP 请求是调用 ProgID 为 PooledObjTest.IpooledObjTest
的组件。它正在调用组件的 GetDataset
方法,并将 SQL 查询字符串传递给参数 strSQL。
<?xml version="1.0" standalone="yes" ?>
- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
- <SOAP-ENV:Body>
- <m:GetDataset xmlns:m="PooledObjTest.IPooledObjTest">
<strSQL xsi:type="xsd:string">select * from orders</strSQL>
</m:GetDataset>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
有关 SOAP 协议的更多信息,您可以参考 SOAP: http://www.w3.org/TR/SOAP/
为了解析 SOAP 请求(一个 XML 文件),我使用 MSXML 库来读取 XMLDOM 对象树。该库中有几个重要的接口,例如 IXMLDOMDocument
和 IXMLDOMNode
。IXMLDOMDocument
接口表示 XML 文档。而 IXMLDOMNode
接口表示树中的一个节点。下面的代码片段解析 IXMLDOMNode
以产生方法调用。
void CSoapRequestParser::ParseACall(IXMLDOMNodePtr pChild) { GetNodeInfo(pChild); CSoapRequestCall cSoapMethod; CSoapRequestCall cPreSoapMethod; int nStartIdx = m_strName.Find(':'); if(nStartIdx != -1) cSoapMethod.SetMethodName(m_strName.Right(m_strName.GetLength() - nStartIdx - 1)); else cSoapMethod.SetMethodName(m_strName); //if there is no attributes if(m_AttribNames.GetSize()== 0) { cPreSoapMethod = m_cSoapReq.GetMethodCall(m_cSoapReq.GetMethodCount() -1); cSoapMethod.SetProgID(cPreSoapMethod.GetProgID()); } else { //find the progid in the attributes; for(int i = 0; i< m_AttribNames.GetSize(); i++) { nStartIdx = m_AttribNames[i].Find("xmlns"); if(nStartIdx != -1) { CString strTemp = m_AttribValues[i]; strTemp.TrimLeft(); strTemp.TrimRight(); cSoapMethod.SetProgID(strTemp); break; } else { //if we omit the prog id, we set it to the same as the prevous one. cPreSoapMethod = m_cSoapReq.GetMethodCall(m_cSoapReq.GetMethodCount() -1); cSoapMethod.SetProgID(cPreSoapMethod.GetProgID()); } } } //parse the parameters. ParseParams(pChild, cSoapMethod); m_cSoapReq.AddMethodCall(cSoapMethod); }
解析 SOAP 请求文件后,我们需要创建并调用组件。为了实现基于 ProgID 调用不同组件的灵活性,我使用了后期绑定。在我看来,直接从 VC++ 调用 IDispatch
并不容易。最繁琐的任务是将参数打包到 DISPPARAMS
参数中。感谢 Xiangyang Liu 的精彩文章 充分利用 IDispatch,这使得任务更加容易。它使用 ITypeInfo
接口读取组件的类型库,并生成调用 IDispatch
接口所需的必要信息。我修改了代码以从 Xiangyang Liu 的文章中加载类型库信息。
为了模拟同时的多个连接,我使用多线程来创建 COM+ 组件并调用其方法。为了显示结果,我使用了 MsChart 控件,该控件非常适合显示图表。下面的代码调用 MsChart 控件来显示每秒请求数 (RPS) 的结果。
void CTestClientDlg::UpdateChartRPS(int nFinished) { COleSafeArray saRet; DWORD numElements[] = {TESTROUNDS, 2}; // 10x10 // Create the safe-array... saRet.Create(VT_VARIANT, 2, numElements); // Initialize it with values... long index[2]; for(index[0]=0; index[0]< TESTROUNDS; index[0]++) { for(index[1]=0; index[1]<2; index[1]++) { if(index[1] == 0) { VARIANT v; CString str; str.Format("%u Threads", m_uThreadNum[index[0]]); v.vt = VT_BSTR; v.bstrVal = _bstr_t(str); saRet.PutElement(index, &v); } else { VARIANT v; v.vt = VT_I4; if(index[0] <= nFinished) v.lVal = m_dwRPSResult[index[0]]; else v.lVal = 0; saRet.PutElement(index, &v); } } } // Return the safe-array encapsulated in a VARIANT... m_ctlChart.SetChartData(saRet.Detach()); m_ctlChart.Refresh(); UpdateWindow(); }
如何使用此工具:
要使用此基于 SOAP 的 COM+ 组件压力测试工具,您需要:
-
创建一个 XML 文件来描述在一轮测试中要调用哪个组件和哪个方法。您可以使用任何 XML 编辑器来完成此操作,也可以使用记事本来完成。您可以从上一节描述的示例 SOAP 请求开始,但请务必将
xmlns:m
命名空间更改为您组件的 ProgID,并将GetDataSet
节点名称更改为您要调用的方法的名称。还要确保将 strSQL 更改为参数的名称。您可以使用 OLEView 工具检查组件的参数名称。接下来,您需要将 "xsd:string
" 更改为您的参数类型。最后,您需要将 strSQL 节点文本更改为适当的参数值。尽管示例 SOAP 请求中只有一个方法调用,但您可以添加更多方法调用,使其看起来像一个典型的客户端会话。
注意:SOAP 请求文件中的所有名称都区分大小写。
- 启动 TestClient.exe 并单击“打开文件”按钮。选择您在步骤 1 中创建的 XML 文件,然后单击“打开”按钮。
图 3. 打开 XML 文件。
- 在文本框控件中指定线程数。或者您可以使用默认线程数。TestClient 将同时启动指定数量的线程来同时调用 COM+ 组件的方法。
- 单击“延迟测试”或“吞吐量测试”按钮开始测试。它将使用 MsChart 控件报告测试结果。
示例测试结果
图 4. 示例延迟测试结果。
图 5. 示例吞吐量测试结果。
已知限制和问题
此基于 SOAP 的压力测试工具存在一些已知限制和问题。首先,由于它使用 IDispatch
调用组件的方法,因此要求您的组件支持 IDispatch
。其次,目前它不支持 SOAP 支持的所有参数类型。例如,它不支持数组和结构。最后,它在屏幕上报告结果,而不将结果保存在磁盘上。您可以对其进行扩展以添加此功能。