Exploring the Dark Side of SOAs
Gaining visibility into a Web service helps you troubleshoot problems
by Robbie Clark
December 17, 2004
Building a Service-Oriented Architecture (SOA) involves creating multiple services in support of business practices. The advantage is that the use of multiple services can make an enterprise more flexible and better able to respond to rapidly changing competitive conditions. Building services can increase the efficiency of existing applications and make it easier to build new ones.
In many enterprises (about 70 percent, according to Gartner), both Java and Microsoft platforms are employed. Ideally, this mixture of platforms shouldn't matter to the SOA. The service can be written in one platform, while the client application in either the same or the other. That's one of the significant advantages promoted by the SOA approach to building applicationsmany different skills can be applied to creating services, and even legacy application components can be modified to perform as services.
In theory this is certainly true. The only required common element between the client application and the service is the ability to send, receive, and decode SOAP messages. Of course, there's a little more to it than that, in that both client and service must also agree on the schema of those messages, or provide a mechanism such as the Web Services Description Language (WSDL) to enable the client to determine the appropriate schema.
But in general, the concept of loosely coupled application components requires remarkably little coordination. Assuming that the schema has been negotiated, communication between client application and service should just work.
Except when it doesn't. That may sound contradictory, but in fact it's a perfectly understandable state of affairs. Many things can go wrong with an application, often stemming from poorly developed requirements, bad design, errors in coding, and inefficiencies that lead to performance or scalability problems. All of which and more can happen in combination with a Web service and one or more clients.
Here's just a few examples of some of the problems that client application developers may encounter when using a Web service: it fails entirelythis could mean it has a bug or object leak; it returns the wrong answerthis could be a logic error or unexpected behavior; it returns results too slowlyis it the Web service or the database?and narrowing it down further is difficult for the application developer; and it fails to scalein many cases, this is due to inefficient code or bottlenecks that aren't caught until the load of a production application is applied.
These problems are compounded when the Web service uses a different platform than the client application. As mentioned previously, one of the other key advantages of Web services is that the concept is platform agnostic. Web services can be written in any language on any platform, making it problematic that any single group of developers building a client application will be able to understand and appreciate the strengths and limitations of services their applications call.
These might sound like normal issues surrounding application development, even if the client and service platforms are different, except that the Web service is developed typically and maintained by groups other than those building the application. Application developers working with Web services lack insight into the application details, and even the platform upon which the service is built.
Of course, that's the way it is supposed to be, but in practice those building client applications would do well to have a technical appreciation of how the Web service does its chores. This may assist with issues surrounding how and how often to make calls to that service, for example, or it may help developers resolve problems that are inherent within the service itself.
This latter reason represents a true problemconsuming Web services without knowing anything about them other than the required input and expected output. Application developers are frequently at a loss to analyze and diagnose problems they encounter with a Web service. There is little or no visibility into the service, and if an application doesn't work or perform as expected, developers may only be able to analyze the code they have written, rather than the application as a whole. To the application developer, the Web service is the dark side.
Peeking into the Web Service
Let's take a closer look at what is likely to be a typical scenario in an enterprise. One such circumstance is when the Web service runs on the Java platform, while a client application uses Microsoft .Net technology. In this example, the client application fails to scale to the required number of users. In fact, in actual use, it supports only 10 simultaneous users, whereas the requirement is to support 100 simultaneous users. Specifically, at 10 users it eventually crashes.
Solving a problem such as this should follow standard processes. They might look something like this: encounter a problem, characterize the problem, analyze the parameters of the problem, do some diagnosis of the problem, and turn over analysis and diagnosis to the Web service owner.
Once this scalability problem is encountered, the initial task is to localize it to either the client application or the Web service. A logical way to do that is to separate the two and test them individually. For example, it is reasonable to write a test harness that acts as the back end to the client application, and produces canned responses similar to that expected of the Web service. Likewise, it's straightforward to write a test harness that exercises the Web service specifically.
While these test harnesses will generate the appropriate responses, what they won't do is simulate the characteristics of multiple users on the application. What is needed in addition to the test harness is a vehicle for load testing. Although in many enterprises, load testing is still a manual process, there are several ways to automate the process. Using a commercial load-testing tool, it's possible to substantially reduce the manual effort involved and obtain accurate data on the Web service response time and system characteristics.
Figure 1 shows the results of a load test performed with a commercial load-testing product. The data indicate that memory use within the context of the Java Virtual Machine (JVM) is increasing over time and not declining as simulated users leave the system.
A logical culprit is how the application is using memory. Although many developers believe that a managed platform such as Java can have no significant memory issues, rather than concentrating on the tactical mechanics of allocating, initializing, casting, and freeing memory blocks of specific size and location, developers must focus on overarching strategies for using memory management to improve application performance and reliability.
How possible is this on the Java platform? Consider the following simple Java method:
java.lang.String:
String r = new String ();
For (int I-0< limit; I+=1) {
r = r + compute(i);
}
return r;
In this method, a new String r is allocated as a temporary object for use in the iteration. In the iteration itself, the current r is copied into that new instance. In addition, the results of the method compute(i) is added to the new r string. This is done each time through the loop. The result is that a new temporary object is created each time you iterate through this loop.
This has a couple of implications. First, the proliferation of temporary objects means that memory is continually being allocated. Although memory allocation isn't particularly expensive, it does extract a performance penalty. And the larger memory footprint means more memory locations to access. This also doesn't take a great deal of time, but it has an associated performance penalty.
The major performance penalty comes in garbage collecting that excess memory. Garbage collection is expensive enough so that it's worthwhile going through the effort to avoid allocating any unnecessary memory, and the way you do that is to write code that reduces use of temporary objects. An alternative might be:
java.lang.StringBuffer:
StringBuffer r =
new StringBuffer();
For (int i=0; I< limit; i+=1) {
r.append(compute(i));
}
return r.toString();
This code uses the append() method to perform the addition operation, eliminating the need for the JVM to generate temporary objects. These types of memory problems are new and unfamiliar to most developers, even Web service developers. In many cases, developers simply lack the experience and understanding to know when a service has a memory problem, and what if anything they can do about it. They assume that they have no control over how memory is used, allocated, and de-allocated, and pay no attention to how design and implementation decisions impact memory usage.
Performance issues such as this in Web services can cause them to not perform to requirements, or to fail to scale. This kind of problem can occur on any SOA platform. This example happens to be Java, but it could just as easily be C# in .Net.
Diagnosing the Web Service from Afar
Application developers may not be familiar with the service platform or language. But they can help the service owners make it bulletproof by collecting and analyzing data in the context of their application. They do this by providing a diagnosis of the Web service issues identified through load testing within the context of their application.
In this case, since load testing has identified a potential memory problem, the diagnosis stage goes one step further by performing a memory analysis on the service using a commercial memory analysis product. Often this is possible without having source code for the service. At least one product can be installed and controlled remotely, making it possible to analyze a Web service without being physically present at the server.
For example, Figure 2 shows an object leak that emanates from the JVM. Further drill-down demonstrates that the object leak originates from the method that opens the database connection. It turns out that each time the database is accessed, the connection is opened, but never closed at the end. The net result is the leaking of 48 bytes for each call to the database. With many users over time, this results in a steadily growing application image that can reduce performance and eventually crash.
These results are actionable, though not by the consumers of the service. Instead, they can be turned over to the service owners for additional diagnosis and repair.
Web service developers have a good understanding of what the Web service should do, and how to implement those requirements. However, they lack the real-world experience of designing an application directly in support of end users. Developers of client applications can assist Web services by providing real-world feedback on their performance and reliability.
This enables application developers to better understand Web service strengths and limitations, while providing service developers with invaluable information on service use. This type of information is essential to both groups when architecting and building an enterprise SOA. Service consumers can field test the work of service providers, which may provide the only true test of the Web service, and in doing so help bulletproof applications that use the SOA.
An SOA strategy has the potential to improve and accelerate enterprise application development, while making applications more robust and extensible. But this works only if the application can count on its services for performance and scalability.
Service consumers can help in two ways, first by testing the service with their application, and second by analyzing and diagnosing problems within the context of their application. This level of participation by service consumers is key if enterprises hope to build a truly bulletproof SOA.
About the Author
Robbie Clark is a freelance writer.
|