Chapter 1: Introduction
Several factors determine how well your application and server configuration perform.
Response time is the time required to execute a specified task, for example, to call an EJB method or submit a JSP form request. For end users, response time provides the key measurement of performance.
In client-side coding, you can minimize perceived response time by displaying partial results or status bars. However, in server-side coding, all you can do is minimize the in-server response time to an acceptable level. It helps to break down the response time into time spent in each component and subsystem. Figure 1-1 illustrates the processing of a Web form request to a JSP that calls an EJB component which in turn executes a remote database query. A slowdown can occur in any of these components. When tuning, you must isolate the part of your deployment that is causing the delay.
Figure 1-1: Response time breakdown
Although a server configuration may perform well with a few users, response times can increase as the number of connected users increases. Scalability is a measure of how many simultaneous users your application and server configuration can support under prescribed use patterns before response times increase to unacceptable levels. Throughput is a measure of how many operations the server or application can process in a given time period; for example, database transactions per second or Web server page requests per second.
Throughput can be useful in comparing benchmark results for servers from different vendors, but scalability is a more useful measurement for tuning a given application deployment. You can directly measure the number of users and response times. End users are usually more concerned about how quickly their own work gets done than they are about overall server performance.
Many performance optimizations in EAServer use caching: once created, objects such as component instances and database server connections are pooled for reuse, avoiding the overhead of re-creating the object. EAServer also caches servlet responses and static HTTP pages to avoid the overhead of running the servlet or reading files from disk, respectively. Caching reduces response time at the expense of increased memory use.
To maximize the performance gain from caching, Sybase recommends you run EAServer with as much memory as possible, from 1GB minimum for large deployments up to the limit of the machine architecture (4GB on most 32-bit address systems).
Common performance problems related to memory use include:
Memory leaks A memory leak occurs when code creates dynamically allocated objects but never releases them. In a Java or EJB component, you must set object references to null to release the memory associated with them. When using JDBC connections, you must release statement objects before releasing connections back to the connection cache (see “Clean up connections before releasing them to the cache”). Since EAServer pools and reuses component instances and connection caches, a memory leak can slowly exhaust the available memory. You can diagnose and find memory leaks using a profiling tool—see “Profiling software”.
Swapping Most operating systems support some form of virtual memory, which allows programs to address more memory than is physically available on the machine. Excess memory is mapped to data stored on disk. Swapping occurs when the system exchanges in-memory data for data stored on disk. Swapping should be avoided since the resulting disk I/O slows down the server. Memory leaks can cause swapping. If you have eliminated memory leaks, you can avoid swapping by ensuring that the machine has enough memory to support the EAServer configuration, and by making sure the system’s per-process memory limit allows the server to use all of it. If you cannot increase physical memory, reduce the server’s memory requirements by adjusting the parameters listed in “EAServer memory requirements”.
Object churning Large, complex objects such as EJB components and database connections can take considerable time to allocate and construct. Object churning refers to repeated allocation and deallocation of the same object. For components, use instance pooling to avoid this phenomena, as described in “Instance pooling”. For database connections, use a connection cache. You can cache objects of other types within your component, servlet, or JSP class instance.
EAServer scales well, primarily through the use of native platform threads. Threading allows multiple components to execute concurrently with a minimum of context-switching overhead. Threading issues that affect performance include:
Number of threads You can tune the total number of EAServer threads, and partition the total to different tasks such as IIOP and HTTP request handling. More threads allow the server to handle more clients. However, if the number is too high, you may experience thrashing, which occurs when each thread gets so little execution time that more time is spent switching the thread context than running threads. You can avoid thrashing by reducing the number of threads, adding CPUs to a multi-CPU machine, or moving to a clustered EAServer deployment.
Concurrency When different threads share data structures or resources, you must synchronize their execution so that access to the shared data or resource is serialized, that is, accessed by only one thread at a time. If access to the shared object is not serialized, you can cause race conditions, where overlapping modifications yield unpredictable results, often causing a crash due to the resulting nonsense data or resource state. However, excessive serialization can slow down the application by creating bottlenecks where many threads idle waiting to acquire synchronization locks. To avoid this problem, do not use design patterns that require synchronized code. When objects must be shared across threads, minimize synchronization and design carefully to avoid deadlock.
Deadlock Deadlock occurs when two or more threads create recursive lock dependencies and wait indefinitely for each other to release the locks held. Figure 1-2 illustrates a deadlock scenario. Component 1 has locked object A while component 2 holds locks on object B. Now component 1 waits for B to be released while component 2 waits for A to be released.
Deadlock is an extreme problem that can hang the server or at least the threads that are deadlocked. You can eliminate deadlock by carefully designing and following a locking protocol that avoids recursive dependencies when a component locks more than one object at once. For example, to lock the two objects in Figure 1-2, always lock A before locking B.
Thread binding EAServer pools and reuses threads, allowing component instances to run on any thread rather than being tied to the same thread as a client connection or the thread that created the instance. Since most client connections have significant idle time, thread pooling allows fewer threads to serve more clients. However, if a component uses thread-local storage, each component instance must be bound to the thread that created it. Binding the thread significantly reduces scalability, since the thread cannot be used to run other instances and sits idle when the component is not running. For more information, see “Thread-related issues”.
|Copyright © 2005. Sybase Inc. All rights reserved.|