Hi all. I apologize for a huge post and if you could answer any of my questions 
it would be a great help. I desperately need advice on the best way to use 
HttpClient to balance performance and resource utilization.

Here's how my application uses the library. I may have up to 100 Applet clients 
running at the same time on various hosts. These clients need to display 
information from different servers, but because applets can only connect back 
to the server from which they were loaded, they ask one central server to give 
them data from the remote server they're interested in. Applets use HttpClient 
to connect to CentralServer, and include the URI of the remote server from 
which they need to get data as part of the request. CentralServer uses a static 
HttpClient instance to pass the Applet's request on to the other servers. There 
may be up to 20 such remote servers. Each client can manage only one remote 
server at a time, so it'll connect only to that one server. Each client can, 
however, make multiple concurrent requests. So if 20 clients all decide to look 
at the same server and make 5 concurrent requests each, the CentralServer will 
get hit with 100 requests, all for the same remote
 server. Of course, the other clients will still keep asking for data from 
other servers.


I'm trying to figure out the best way of using HttpClient, 
MultiThreadedHttpConnectionManager, pool sizes, and HostConfigurations to make 
my CentralServer (the component that sits in the middle and distributes 
requests from clients to remote servers) as efficient as possible. I've been 
through tutorials and mailing list archives, but I still can't quite figure out 
all the relationships between these concepts.


In CentralServer, all http requests are made through the one static instance of 
HttpClient. CentralServer creates a new PostMethod for every request. Code from 
"CentralServer" servlet is below, and after that I ask specific questions.

---------------

    private static HttpClient httpClient;
    private static MultiThreadedHttpConnectionManager httpConnectionManager;

    /*** Initalize singleton HttpClient and connection manager when servlet 
class is loaded.
    ***/
    static {
        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        
        params.setConnectionTimeout(10000);
        
        /*** I'm using arbitrary value of 200 for the max number of connections,
         *** but this is one of the values I need to pin down
         ***/
        params.setDefaultMaxConnectionsPerHost(200);
        params.setMaxTotalConnections(200);

        httpConnectionManager = new MultiThreadedHttpConnectionManager();
        httpConnectionManager.setParams(params);        
        
        // Configure a thread to check for and close idle connections.
        IdleConnectionTimeoutThread idleConnectionTimeoutThread = new 
IdleConnectionTimeoutThread();
        idleConnectionTimeoutThread.addConnectionManager(httpConnectionManager);
        
        // Check for idle connections to close every 15 seconds.
        idleConnectionTimeoutThread.setTimeoutInterval(15000);
        
        // Close connections that have been idle for at least 30 seconds.
        idleConnectionTimeoutThread.setConnectionTimeout(30000);
        idleConnectionTimeoutThread.start();
        
        httpClient = new HttpClient(httpConnectionManager);
    }

    private void makeRequest(HttpServletResponse response, String serverPath) {
        PostMethod method = new PostMethod(serverPath);
        method.addRequestHeader(CONTENT_TYPE_HEADER_NAME, 
CONTENT_TYPE_HEADER_VALUE);
        method.addParameter("serverCommandValueObject", "someParam");

        Reader reader = null;
        Writer writer = null;
        try {
            httpClient.executeMethod(method);
            reader = new InputStreamReader(method.getResponseBodyAsStream(), 
"UTF-8");
            writer = new BufferedWriter(new 
OutputStreamWriter(response.getOutputStream(), "UTF-8"));
            
            /*** What's a good buffer size? Does it matter? ***/
            char[] buffer = new char[1024];
            int numRead;
            while ((numRead = reader.read(buffer)) > 0) {
                writer.write(buffer, 0, numRead);
            }
        }
        catch (Exception e) {
            ex.printStackTrace();
        }
        finally {
            ... Some code to safely close reader and writer ...
            method.releaseConnection();
        }
    }

---------------

Questions:

1. Since I have a finite set of remote URIs, does it buy me anything to create 
HostConfiguration objects for each server and use them when I make requests? 
Like this:

    Map uriToHostMap = new HashMap();
    uriToHostMap.put("http://chef:18081/RemoteServlet";, chefHostConfiguration);
    uriToHostMap.put("http://cartman:18081/RemoteServlet";, 
cartmanHostConfiguration);
    uriToHostMap.put("http://kenny:18081/RemoteServlet";, 
kennyHostConfiguration);
    
I can build the map up as new requests are being made and then pass correct 
HostConfiguration to httpClient, like this

    PostMethod method = new PostMethod(serverPath);
    HostConfiguation host = (HostConfiguration)uriToHostMap.get(serverPath);
    httpClient.executeMethod(host, method);
    
Will this improve how the connection manager selects HttpConnection to reuse?


2. Since I have a finite number of servers, does it make sense to use per-host 
connection pool size? Or is it just as good to have one big pool of connections?


3. Is the following statement true: <Number of Hosts> * <MaxHostConnections> 
must be <= MaxTotalConnections?


4. Can I set MaxHostConnections to 100 and MaxTotalConnections to 200 and still 
connect to 20 hosts? Will the connections shift from connection pool for one 
host to connection pool of another as needed?


5. Is the purpose of MaxHostConnections simply to limit the number of 
connections that can be made to a given Host. If so, then I can probably have 
just one global connection pool, because I don't want to put any limit on the 
number of host connections - I just want to keep the CentralServer system from 
running out of sockets.

Also, I can't predict what clients will look at what servers. It may be pretty 
eveny distributed in one moment, but then 50 clients will decide to look at the 
same remote server. And clients CAN send multiple concurrent requests.


6. I wanted to monitor pool size, so I periodically print the value of 
httpConnectionManager.getConnectionsInPool(), but I noticed that it never 
shrinks, even though I'm running the IdleConnectionTimeoutThread. I figured out 
that to shrink it, I have to call 
httpConnectionManager.deleteClosedConnections().

  (a) Do calls to closeIdleConnections completely release all system resources 
used by HttpConnection objects it closes? Meaning sockets, of course.
  
  (b) Is there a way to determine how many of the connections in a pool are 
closed (for tracking purposes)? I mean, an existing way, other than extending 
some class in the library?
  
  (c) Is it a good idea to call httpConnectionManager.deleteClosedConnections() 
once in a while? If an HttpConnection is not deleted, will it hold any 
resources, other than the memory it occupies?

  (d) Are there advantages to keeping closed connections in the pool? Is it 
faster to open an existing closed connection then to create a new one and open 
it?
  
Thanks you very much

Reply via email to