On a 56K modem, this report will take about half an hour to download (for a 30-second download of just the information contained in the report, click here).
From a web site that shall remain unnamed
Distributed-application bottlenecks are of two general types. The first type occurs within application subcomponents. This type of bottleneck is essentially independent of the distributed nature of the application, and the other chapters in this book deal with how to tune this type of bottleneck. In this chapter, we deal with the second type of bottleneck, which occurs within the distribution infrastructure. This latter type of bottleneck is specific to the distributed nature of the application, and can be tuned using a number of techniques:
When an application repeatedly distributes the same data, a significant gain in performance can be obtained by caching the data, thus changing some distributed requests to local ones.
If the volume of data being transferred is large or causes multiple chunks to be transferred, then compressing the transferred data can improve performance by reducing transfer times.
Most distributed applications have their performance limited by the latency of the connections. Each distributed message incurs the connection-latency overhead, and so the greater the number of messages, the greater the cumulative performance delay due to latency. Reducing the number of messages transferred by a distributed application can produce a large improvement in the application performance.
The performance of any distributed function in a distributed application normally has at least two factors involved. These two factors are the location for the function to execute and the location where the data for the function resides. Typically, the application developers are faced with the choice of moving the function to the location of the data, or moving the data to the location of the function. These decisions depend on the volume and nature of the data to be processed, the relative power and availability of the CPUs in the different locations, and how much of the data will be transferred after the function completes. If the function's result is to transfer a relatively small amount of data, it should be located on the machine where the data used by the function resides.
There are several ways that batching can improve the performance of a distributed application. First, the number of messages can be reduced by combining multiple messages into fewer batched messages. Second, data can be split up and transferred in shorter batches if waiting for all the data is the cause of the delay in response times. Third, data requirements can be anticipated, and extra data can be transferred in batches together with the data that is needed at that moment, in anticipation of the extra data that will be needed soon. Further batching variations can be used by extending these strategies.
When data needs to be transferred across a distributed application, the distribution infrastructure often uses general mechanisms for transfers. This results in transferring more data than is actually required. By selectively "stubbing out" data links, only the data that is needed is transferred. Instance variables of objects can be replaced with "stub" objects that respond to messages by transferring the required data (if the fields are defined using an interface). Java also supports the transient modifier, which can be used to eliminate unnecessary data transfers. Fields defined as transient are not transferred when serialization is used, but this is a rather blunt technique that leads to all-or-nothing transfers of fields.
Distributed systems should make maximum use of asynchronous activities wherever possible. No part of the application should be blocked while waiting for other parts of the application to respond, unless the application logic absolutely requires such blocked activities.
In the following sections, we look at examples of applying some of these techniques to optimize performance.
 This chapter deals with general distributed application optimizations. Higher-level J2EE optimizations are covered in Chapter 15 through Chapter 18.