HomeDigital EditionSys-Con RadioSearch Web Services Cd
B2B Beginning WS Business Process Management Case Studies Content Management Distributing Computing e-Business Electronic Data Interchange Enterprise Industry Insight Integration Interviews Java & Web Services .NET Portal Product Reviews Scalability & Performance Security SOAP Source Code UDDI Wireless WS Standards WS Tips & Techniques WSDL WS Editorials XML

The growth of applications using the .NET platform has generated an increased emphasis on performance measurement and analysis. Distributed applications, while much more flexible and potentially more scalable than monolithic ones, have characteristics that make it more difficult to achieve these very goals.

The problem arises both in the individual components and in their interactions with one another. Individual application components may include computationally expensive code and bottlenecks that don't manifest themselves during unit testing, because the functionality is correct. Once separately developed components are integrated into the full application, performance bottlenecks may result from interactions between them.

These problems are especially true of distributed applications utilizing Web services. In the case of traditional components utilizing COM or CORBA, processing tended to be more synchronous, or at least more tightly coupled, which in turn can result in performance more in line with the overall application. In the case of asynchronous and loosely coupled Web services, there could well be significant differences in their ability to provide the performance and scalability required by the application.

Developers who have worked primarily on stand-alone applications or fat clients may lack direct experience in the performance considerations needed by Web-based distributed applications. In fact, many developers may be surprised at the need to analyze performance and tune individual components including Web services in a .NET application. This doesn't represent a deficiency or limitation of .NET, but rather the reality of the trade-offs required to obtain the flexibility inherent in Web services.

Web services adapt the traditional Web programming model for use from all sorts of applications, not just browser-based ones. These applications are loosely coupled and remarkably interoperable because they can be called from any location that is reachable with a URL or URI, and are not limited by the calling conventions of a specific language.

Microsoft positions ASP.NET as a natural technology for implementing Web services based on the .NET Framework. The ASP.NET Web services infrastructure provides an API for Web services based on mapping SOAP messages to method invocations. ASP.NET Web services support requests from clients using SOAP over HTTP, as well as with HTTP GET or POST operations. ASP.NET Web services automatically generate WSDL files for Web services development efforts. Developers can also use ASP.NET Web services to implement a Web service SOAP listener that waits for service requests and accesses a business facade implemented as a COM component or as a managed code class.

But Web services haven't been proven to stand up to the performance requirements of a wide variety of production uses. That's not to say that they won't or can't, but rather that this type of application model represents a significant unknown in practice.

There are two aspects to measuring and evaluating the performance of an application composed of one or more Web services. The first is the throughput of the Web service itself. This is its ability to accept a request and provide a response in accordance with required performance parameters. On a larger scale, it's also the ability to actually have a transaction throughput that the component was designed to meet. We know that as scalability, although it's difficult to test scalability prior to integrating all application components and functionality.

The second aspect is the ability to evaluate the performance of the application in the aggregate, including the Web service. This includes not only the ability of the Web service to respond, but also how that response is coordinated with the responsiveness of the application as a whole. While the focus may be specifically on the performance of the Web service component, it must be analyzed within the context of the entire application.

To accomplish this, it's necessary to measure the performance of all of the application components simultaneously, during the same testing run, and correlate those disparate measurements into an integrated view. While the Web service may appear to perform acceptably within its own context, resource or processing issues, synchronization problems, networking, or data throughput, bottlenecks may prevent it from reaching its potential.

Unit Testing During Development
Unit testing a Web service presents the first significant challenge. As a practical matter, it requires an external stimulus to initiate execution, so it isn't simple to call the service as you would a DLL or link it in as you would a library. Fortunately, using the Web services wizard in Visual Studio .NET has the side effect of creating a Web page front end for functional testing purposes, and it works well enough to initiate unit testing also. Otherwise, you would have to write your own call method into the service.

Unit testing should cover both functional and performance testing. Functional testing involves exercising the operations which compose the service, to ensure that they behave as specified. Whether you employ an automated test management system or conduct these unit tests manually, keeping track of code coverage is important to determine what code you've tested and how much you've tested it. Many developers already do this, and while doing so with Web services opens certain challenges, the process is largely familiar.

The goal of performance testing is to identify slow code and potential bottlenecks. For developers with experience in monolithic or tightly coupled applications, this is often simply a matter of noting that the application doesn't perform as expected, isolating the component responsible, and fine-tuning the code. It's not quite like that when building a loosely coupled application with Web services.

However, profiling a .NET Web service is a necessary part of the development process. Since you're not looking at performance or scalability testing of the entire application at this point, you can initiate profiling early in the development cycle.

At a minimum, profiling should collect two types of information - execution time and number of times executed (see Figure 1). The reason for the first is readily apparent - so that you can quickly identify parts of the code that seemingly execute more slowly than others. It's not necessarily indicative of poorly performing code because it may just be performing a computationally intensive operation that can't be improved upon. However, information on the performance of your code justifies a closer look.

Figure 1

The number of times executed can also be indicative of poorly performing code, but in a different sense. A single line or method may execute in an acceptable amount of time, but may be inefficient in the sense that a single call to that operation does too little work for too much overhead. The trick is to find the optimum amount of data that can be processed most efficiently.

Analyzing Performance and Diagnosing Issues
Profiling a .NET Web service frequently requires looking at both managed and unmanaged code simultaneously. This may be because all but the most trivial calls into native code must undergo a mode transition. The mode transition, which is the physical process of moving data between the managed and unmanaged modes of operation, typically requires about two dozen instructions. The second cost is marshalling the data to move across the boundary. Marshalling is computationally expensive, and the more data you move back and forth, the more expensive it becomes.

Alternatively, within the Microsoft model Web services can also be unmanaged. Existing or new COM components can be used to implement the business facade, business logic, and data access layers. Using Windows Server 2003, developers and system administrators can allow existing COM+ applications to be called using XML/SOAP by simply checking a configuration box.

Therefore, you may be making unmanaged calls from your .NET Web service, either because you are using it as a gateway to call COM objects, or are making platform calls, or are using prepackaged native components. Profiling both managed and unmanaged calls together gives you a comprehensive view of the Web service, and most important a view of the performance cost of mode transitions.

The granularity of your profiling should be at least to the method level, and preferably to the individual line of code. At the method level, you can quickly get a view of what operations your code is spending most of its time performing.

In addition to obtaining the execution time and number of calls, you should also be able to analyze your code in several different views of performance, including percent of time in method and percent of time in children. Walking the call stack is an excellent way of determining what resources, .NET services, and OS services your Web service is using, and how expensive those services are (see Figure 2).

Figure 2

Modifying Web Service Performance
Once you have identified slow code, the next step is to address those issues. One popular technique for addressing how data is passed between the application and the Web service is to carefully monitor and optimize the amount of data transmitted in each SOAP call.

In this circumstance, one change you can consider is whether your code should be "chatty" or "chunky." As the names imply, chatty calls are those that occur often and pass little data, while chunky calls occur less frequently but do more work when they do occur. While at first glance it might appear that large calls to the service are more efficient, that's not necessarily true. A chatty interface passing less complex data more often may turn out to be less computationally expensive because its marshalling isn't as complex.

How do you determine whether or not you should be using chatty or chunky calls to your service? There's no easy way that applies to all circumstances; it depends on the amount of data and frequency of calls. The best thing to do is to prototype both the type of interface and the performance profile. By investing a little time early in the development phase, you can ensure that you made the right performance choice and not have to go back and make substantial changes after you have a working application.

That's not to say that you might not have to go back and make adjustments to your calls once the application is done. For example, you may find that in certain Web services features, chunky calls are more efficient because of the overall volume of calls. But prototyping your data and calls ahead of time gives you a better ability to determine the optimum amount of data to exchange with your Web services in individual transactions.

Another common problem is that certain .NET services can be computationally expensive. At first glance it may appear that you have little control over what the .NET Framework does. However, the framework is rich in features, and there are often multiple ways of obtaining the services you need. Alternatively, the framework calls you are using may be doing more work than you actually need. You won't know any of this unless you have complete profiling information on child behavior from your own methods.

Taking the Uncertainty Out of Web Service Performance
Web services represent the potential to reuse code components as features across multiple applications simultaneously. The loosely coupled model and XML/SOAP communications standard is simple to understand and implement, but the performance implications are not yet well understood. In particular, it's not clear how a Web service used simultaneously by multiple applications will respond to such asynchronous requests.

You're going to be feeling your way in building and testing the performance of Web services. That makes it important to profile these services, both by themselves and within the context of the entire application or applications, to determine where slow code and bottlenecks may reside. And in doing so, you can address those issues by changing the calls to or within the Web service, by modifying expensive database calls, by simplifying complex code paths, or other techniques.

Author Bio
Peter Varhol is a product manager at Compuware Corporation and frequent contributor to technology publications. peter.varhol@compuware.com

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.

  E-mail: info@sys-con.com

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.