Apache V1.3 on UNIX operating systems provides a preforking process per request server. When the Apache parent process starts, it forks a number of child processes responsible for accepting connections off the listening sockets. When the system receives a connection, the system wakes up one of the processes to handle the connection. Since Apache does not do asynchronous network I/O, Apache needs a process to handle each concurrently connected browser and client. For example, Apache needs 1000 processes to handle 1000 concurrently connected clients, or connections.
If you notice that server CPU utilization appears low, but client requests for static pages take a long time to service, you could run out of server processes to handle requests. This situation results when you have more inbound requests than you have Apache processes to handle those requests. New connections queue in the TCP/IP stack listen queue, waiting for acceptance from an available process. As a process becomes available, it accepts and handles a connection off the listen queue. Connections can take a long time to reach the top of the listen queue.
If you configured Apache to listen on multiple ports, you can find responses slow on one port (port 80, for example) but adequate on another port (port 443, for example). The disparity in response time results from each port having its own listen queue. You could have a deep port 80 queue and a shallow port 443 queue. Apache does not attempt to balance the number of connections received from each queue. When a connection becomes available, Apache and the operating system consume from either queue at random.
To address this scenario, add more Apache processes to handle inbound connections.
You can use several configuration directives to control the number of IBM HTTP Server processes, or the number of concurrently supported clients. The most important directives follow:
MaxClients has an upper bound specified by the directive, HARD_SERVER_LIMIT, in the src/include/httpd.h directory.
The IBM HTTP Server V1.3.26 HARD_SERVER_LIMIT equals 4096.
HTTP V1.1 has a feature known as Connection KeepAlive. In a non-KeepAlive connection, the browser starts a TCP connection and sends a single request to the server. The server responds and then takes down the connection. Each request includes the bring-up and take down of a TCP connection. The KeepAlive feature maintains connections for a number of requests, controlled by configuration directives. This control reduces network overhead related to startup and tear down of TCP connections. The server assumes that for a KeepAlive connection, the browser sends another request. The server attempts to read the next request off the network. When the next request becomes unavailable, the process blocks on the read, waiting for the next request.
Consider a typical scenario where a user goes to a Web site resulting in the fetching and rendering of an information page on the browser. The user lingers while reading the page. The user does not actively request more pages, but the server blocks on a network read waiting for the next request. This blocked process becomes unavailable to handle requests from other clients. The user can follow a link off the Web site, get a cup of coffee and never send another request. You can configure the IBM HTTP Server to wait a specific time for the next request using:
Some heavily loaded sites disable the KeepAlive feature entirely.
Assess the needs of your site and set KeepAliveTimeout appropriately. Give the browser enough time to request all the elements of a page over the KeepAlive connection, but not wait too long for the user to initiate the next page request. Some recommend setting KeepAliveTimeout to 5 seconds as a good compromise between balancing available processes with minimizing network I/O.
You can reduce connection requests to your site by setting document expiration dates with mod_expires. If the browser has cached a previous visit, this action can save another connection request to your site.