Introduction
COM+ is there for developing scalable applications. You
have finished your component, and you have put it into COM+. Now you want to
know how scalable is your component? The question arises, how to measure the
scalability of your COM+ application? Basically there two major metrics to
measure a COM+ application�s scalability: The latency and the throughput under
different user load.
Latency is often called response time. From a client's
perspective, it is the delay experienced between the point when a request is
made and the server's response at the client is received. It is usually measured
in units of time, such as seconds. In certain testing tools, such as the
Microsoft� Web Application Stress (WAS) tool, latency is best represented by the
metric "time to last byte" (TTLB), which calculates the time between sending out
a Web page request and receiving the last byte of the complete page content.
Below is a typical latency versus user load curve.
Figure 1.
Typical characteristics of latency versus user load
Throughput is another one of the most useful metrics to
measure a distributed application�s scalability. It is the number of client
requests the application can process within a certain unit of time. Typically,
the unit of measurement is requests per second. It can help to identify
performance bottlenecks and improving application and system performance. Figure
2 demonstrates typical characteristics of throughput versus user load.
Figure 2.
Typical characteristics of throughput versus user load
Given the metrics, how can we know them of our COM+
application? The answer is to stress test it. But how? Microsoft and other
vendors provide testing tools such as Web Application Stress (WAS) tool, but
they are mainly focused on the Web application stress testing. They send http
request to the web application to test it, and basically interact with the
Presentation layer of the distributed application. Unfortunately it is usually
too late when the presentation layer is finished and if we found the metrics
don�t meet our design goal. We need to test the Data Layer and the Business
Logical Layer before testing the web application as a whole to ensure bad
performance is not propagated into the next layer.
That's why this stress testing tool comes into play. It is mainly focused on
the Data Layer and Business Layer stress testing. It can be used in at least two
scenarios. The first is to stress test Data Layer and business Layer after they
are finished to make sure that they meet the design goal. The other is to
trouble shoot the Data Layer and Business Layer if other stress testing tools
such WAS found that the Web application's scalability is not so good.
Techniques used
in this tool
One of
the design goal is to make this tool suitable for all the Components that
support IDispatch
.
To make this tool powerful, flexible yet easy to use, I make it based on the
SOAP protocol. SOAP protocol is ideal for describing method calls to the
component. It uses a rich type system which includes most of the types that you
may use in your programming language. Yet it is easy to use and parse. As for a
SOAP request, it can specify which component it is for, which method it is
calling, and what are the types and values of the input parameters. I use the
component's ProgID
as the URI of the namespace for the request message. For example the SOAP
request below is to call a component with ProgID
PooledObjTest.IpooledObjTest
.
It is calling the component�s GetDataset
method, passing a SQL query string to the parameter 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>
For more
information about the SOAP protocol, you can have a look at the SOAP :
http://www.w3.org/TR/SOAP/
To parse
the SOAP request, which is a XML file, I use the MSXML library to read the
XMLDOM object tree. There are couple of important interfaces in the library such
as IXMLDOMDocument
and IXMLDOMNode
. The IXMLDOMDocument
interface represent a
XML document. And the IXMLDOMNode
interface represents a node in the tree. The
code snippet below parse a IXMLDOMNode
to yield out a Method call.
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(m_AttribNames.GetSize()== 0)
{
cPreSoapMethod = m_cSoapReq.GetMethodCall(m_cSoapReq.GetMethodCount() -1);
cSoapMethod.SetProgID(cPreSoapMethod.GetProgID());
}
else
{
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
{
cPreSoapMethod = m_cSoapReq.GetMethodCall(m_cSoapReq.GetMethodCount() -1);
cSoapMethod.SetProgID(cPreSoapMethod.GetProgID());
}
}
}
ParseParams(pChild, cSoapMethod);
m_cSoapReq.AddMethodCall(cSoapMethod);
}
After the SOAP request file is parsed, we need to create
and call the component. To achieve the flexibility of calling different
components based on the ProgID, I use late binding. To call IDispatch
directly from VC++ is not so easy in my opinion. The most tedious task is to
package the parameters into a
DISPPARAMS
parameter.
Thanks to Xiangyang Liu�s cool article
Getting the most out of IDispatch, it make the task much easier. It uses ITypeInfo
interface to read the type library of the component and
generate the necessary information to call the IDispatch
interface. I modified the code to load the type library information from
Xiangyang Liu's article.
To simulate multiple connections at the same time, I use
the multiple-threads to create the COM+ component and to call its methods. To
display the result, I use the MsChart control, which is ideal for displaying
charts. The code below calls the MsChart control to display the Request Per
Second (RPS) result.
void CTestClientDlg::UpdateChartRPS(int nFinished)
{
COleSafeArray saRet;
DWORD numElements[] = {TESTROUNDS, 2};
saRet.Create(VT_VARIANT, 2, numElements);
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);
}
}
}
m_ctlChart.SetChartData(saRet.Detach());
m_ctlChart.Refresh();
UpdateWindow();
}
How to use this
tool
To use this SOAP based COM+ component stress tool, you
need to:
-
Create a XML file to describe what
component and what methods you want to call in a round of test. You can do it
with any XML editor, or you can use the Notepad if you like. You can start with
the sample SOAP request described in the previous section, but be sure to change
the xmlns:m
namespace to the ProgID of your
component, and change the GetDataSet
node name to the name of the
method. Also be sure to change the strSQL to the name of the
parameter. You can check the component�s parameter names with the OLEView tool.
Next you need to change
"xsd:string
" to the type
of your parameter. Finally you need to change to the text of the strSQL
node to the appropriate parameter value.
Though there is only
one method call in the sample SOAP request, you can add more method calls to it
to make it like a typical client session.
NOTE: All the names
in the SOAP request file is case-sensitive.
-
Start
TestClient.exe and click on the Open File button. Select the XML file you have
created in step 1 and click Open button.
Figure3. Open the XML file.
-
Specify the Thread numbers in the textbox controls. Or you can use the
default thread numbers. The TestClient will start the number of threads at the
same time to call the COM+ component�s methods simultaneously.
-
Click on the Latency Test, or the Throughput test button to start test.
It will report the testing result with the MsChart control.
Sample Test Results
Figure 4. A sample Latency test result .
Figure 5. A sample Throughput test result .
Known
Limitations and issues
There are a couple of the known limitations and issues
about this SOAP based stress testing tool. First of all, since it uses IDispatch
to
invoke the methods of the component, it requires that your component to support IDispatch
. Next, for the time being it doesn�t
support all the parameter types that the SOAP supports. For example it doesn�t
supports arrays and structures. Finally it reports the result on the screen and
doesn�t save the result on the disk. You can extend it to add that feature.