<document>
  <header>
    <product>resin</product>
    <title>Performance</title>
    <type>contents</type>
  </header>

  <body>
  <!-- performance-benchmarks.xtp -->

  <s1 title="Resin 10,000">

<p>Resin 4.0 has been load tested with 10,000 simultaneous
keepalive connections and 10,000 simulteneous async comet connections.</p>

<p>In a HTTP server, most of the browsers are
idle, waiting for the user to finish reading and click on the next page.
The browser and Resin can keep the TCP socket connected for
improved efficiency, while taking minimal resources until the next page
is needed.  Because of Resin's use of non-blocking i/o like the
Linux epoll() call, it can maintain thousands of keepalive connections
with little overhead.</p>

  </s1>
  
    <s1 title="Resin v. Apache">
      <p>Resin is an excellent web server for both static pages
        and for load-balancing to multiple backend application servers.
        For a web-tier server, static page performance and load-balance
        performance are both important, as is the ability to
        <a href="proxy-cache.xtp">proxy cache</a> pages. The following benchmarks
        give a quick comparison between Resin and Apache as web-tier servers:
        both are very close in performance, although Resin is slightly faster
        than Apache in most of these cases.</p>
      
      <p>These results were benchmarked with Resin 3.1.0 and
        Apache 2.2.3 with a pair of Debian Linux machines using
        a 1G ethernet. Resin's proxy cache was disabled to match Apache's
        default no proxy-cache configuration, but no other special configurations
        were applied to either server.</p>
      
      <p>The first set of benchmarks compare static page serving using a 1k page
        to simulate small image files and a 64k page to simulate
        normal web pages. For the small pages, Resin was about 5% faster
        than Apache, and for large pages, the two are essentially identical.</p>
      
      <deftable title="Static Pages">
        <tr>
          <th></th>
          <th>Resin (ops per second)</th>
          <th>Apache (ops per second)</th>
        </tr>
        <tr>
          <th>1k html (1 client, 1 keepalive)</th>
          <td>3,537 OPS</td>
          <td>3,287 OPS</td>
        </tr>
        <tr>
          <th>1k html (10 client, 4 keepalive)</th>
          <td>19,568 OPS</td>
          <td>16,466 OPS</td>
        </tr>
        <tr>
          <th>64k html (1 client, 1 keepalive)</th>
          <td>874 OPS</td>
          <td>859 OPS</td>
        </tr>
        <tr>
          <th>64k html (10 client, 4 keepalive)</th>
          <td>1,800 OPS</td>
          <td>1,804 OPS</td>
        </tr>
      </deftable>
      
      <p>The second set of benchmarks compare load balancing of JSP pages
        to a backend Resin server.  Both a 1k page and a 64k page were simulated.
        For comparison, the performance of Resin serving the same JSP
        page as a standalone HTTP server is also provided.  Again, for small pages
        Resin is about 5-10% faster than Apache and is essentially identical for
        larger pages.</p>
      <deftable title="Load Balancing for Resin JSP">
        <tr>
          <th></th>
          <th>Resin Load Balancing</th>
          <th>Apache Load Balancing</th>
          <th>Resin Standalone</th>
        </tr>
        <tr>
          <th>1k jsp (1 client, 1 keepalive)</th>
          <td>2,269 OPS</td>
          <td>1,989 OPS</td>
          <td>3,903 OPS</td>
        </tr>
        <tr>
          <th>1k jsp (10 client, 4 keepalive)</th>
          <td>14,119 OPS</td>
          <td>10,351 OPS</td>
          <td>26,620 OPS</td>
        </tr>
        <tr>
          <th>64k jsp (1 client, 1 keepalive)</th>
          <td>579 OPS</td>
          <td>604 OPS</td>
          <td>826 OPS</td>
        </tr>
        <tr>
          <th>64k jsp (10 client, 4 keepalive)</th>
          <td>1,668 OPS</td>
          <td>1,661 OPS</td>
          <td>1,799 OPS</td>
        </tr>
      </deftable>
      <s2 title="Caveats">
        <p>As always, no artificial benchmark can replace measuring your own
          application with your own configuration and load.
          In most cases, other considerations like the application
          performance and database performance will dominate the performance (although
          <a href="proxy-cache.xtp">proxy caching</a> can make slow
          applications run as fast as static pages.)  These numbers in particular
          are a trivial tests with a simple load.  They do measure the maximum
          performance of the web server, so they are valuable information, but
          they are very different from a benchmark of a complete application.</p>
        <p>Warnings aside, these results do indicate that many sites should
          seriously consider using Resin as their web-tier load-balancing
          server. (After benchmarking your own application, of course.)</p>
      </s2>
    </s1>

    <!-- jvm-tuning.xtp -->

<s1 name="memory" title="Heap size">

<p>The allocation of memory for the JVM is specified using -X options when
starting Resin (the exact options may depend upon the JVM that you are using,
the examples here are for the Sun JVM).</p>

<deftable>
<tr>
  <th>JVM option passed to Resin</th>
  <th>Meaning</th>
</tr>
<tr>
  <td>-Xms</td>
  <td>initial java heap size</td>
</tr>
<tr>
  <td>-Xmx</td><td>maximum java heap size</td>
</tr>
<tr>
  <td>-Xmn</td>
  <td>the size of the heap for the <i>young generation</i></td>
  </tr>
  </deftable>

<example title="Example: resin.xml startup with heap memory options">
&lt;resin xmlns="http://caucho.com/ns/resin">
&lt;cluster id="">

  &lt;server id="" address="127.0.0.1" port="6800">
    &lt;jvm-arg>-Xmx500M&lt;/jvm-arg>
    &lt;jvm-arg>-Xms500M&lt;/jvm-arg>
    &lt;jvm-arg>-Xmn100M&lt;/jvm-arg>

    &lt;http port="80"/>
  &lt;/server>

  ...

&lt;/cluster>
&lt;/resin>
</example>

<p>It is good practice with server-side Java applications like Resin to set the
minimum <var>-Xms</var> and maximum <var>-Xmx</var> heap sizes to the same value.</p>

<p>For efficient <a href="#garbage-collection">garbage collection</a>, the
<var>-Xmn</var> value should be lower than the <var>-Xmx</var> value.</p>

<s2 title="Heap size does not determine the amount of memory your process uses">

<p>If you monitor your java process with an OS tool like top or taskmanager,
you may see the amount of memory you use exceed the amount you have specified
for -Xmx.  -Xmx limits the java heap size, java will allocate memory for other
things, including a stack for each thread. It is not unusual for the total
memory consumption of the VM to exceed the value of -Xmx.</p>
</s2>

</s1> <!-- memory -->

<s1 name="garbage-collection" title="Garbage collection">


<p>(thanks to Rob Lockstone for his comments)</p> 

<p>
There are essentially two GC threads running. One is a very lightweight
thread which does "little" collections primarily on the Eden (a.k.a.
Young) generation of the heap. The other is the Full GC thread which
traverses the entire heap when there is not enough memory left to
allocate space for objects which get promoted from the Eden to the
older generation(s).
</p>


<p>
If there is a memory leak or inadequate heap allocated, eventually the older
generation will start to run out of room causing the Full GC thread to run
(nearly) continuously. Since this process "stops the world", Resin won't be
able to respond to requests and they'll start to back up.
</p>


<p>
The amount allocated for the Eden generation is the value specified with
<var>-Xmn</var>.  The amount allocated for the older generation is the value of
<var>-Xmx</var> minus the <var>-Xmn</var>.  Generally, you don't want the Eden to be
too big or it will take too long for the GC to look through it for space that
can be reclaimed.
</p>


<p>See also:</p>
<ul>
<li><a href="troubleshoot.xtp#garbage-collector">Troubleshooting Technique: Garbage Collector</a>
</li><li><a href="http://java.sun.com/docs/hotspot/gc1.4.2/">Sun documentation on garbage collection</a>
</li></ul>
</s1> <!-- garbage-collection -->

<s1 name="stack-size" title="Stack size">

<p>Each thread in the VM get's a stack.  The stack size will limit the number of
threads that you can have, too big of a stack size and you will run out of
memory as each thread is allocated more memory than it needs.</p>

<p>
The Resin startup scripts (resin.exe on Windows, resin.sh on Unix) will set
the stack size to 2048k, unless it is specified explicity.  2048k is an
appropriate value for most situations.
 </p>

<deftable title="Stack configuration">
<tr>
  <th>&lt;jvm-arg></th>
  <th>Meaning</th>
</tr>
<tr>
  <td>-Xss</td>
  <td>the stack size for each thread</td>
</tr>
</deftable>

<p><code>-Xss</code> determines the size of the stack: <code>-Xss1024k</code>.
If the stack space is too small, eventually you will see an exception <a href="javadoc|java.lang.StackOverflowError|"/>.

</p><p>Some people have reported that it is necessary to change stack size settings
at the OS level for Linux.  A call to <code>ulimit</code> may be necessary, and
is usually done with a command in /etc/profile:</p>

<example title="Limit thread stack size on Linux">
unix> ulimit -s 2048
</example>
</s1>

<s1 name="monitor" title="Monitoring the JVM">

<p>
JDK 5 includes a number of tools that are useful for monitoring the JVM.
Documentation for these tools is available from the
<a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/index.html#manage">Sun
website</a>.  For JDK's prior to 5, Sun provides the
<a href="http://developer.sun.com/dev/coolstuff/jvmstat">jvmstat tools</a>.
</p>

<p>
The most useful tool is <var>jconsole</var>.  Details on using jconsole are
provided in the <a href="jmx.xtp#console">Administration</a> section of the
Resin documentation.
</p>

<example title="Example: jconsole configuration">
&lt;resin xmlns="http://caucho.com/ns/resin">
&lt;cluster id="">

  &lt;server-default>
    &lt;jvm-arg>-Dcom.sun.management.jmxremote&lt;/jvm-arg>
  &lt;/server-default>

  &lt;server id="" address="127.0.0.1" port="6800"/>

  ...
&lt;/cluster>  
&lt;/resin>
</example>

<example title="Example: jconsole launching">
<i> ... in another shell window ... </i>

win&gt; jconsole.exe
unix&gt; jconsole

<i>Choose Resin's JVM from the "Local" list.</i>
</example>

<p>
<var>jps</var> and <var>jstack</var> are also useful, providing a quick command line
method for obtaining stack traces of all current threads.
Details on obtaining and interpreting stack traces is in the
<a href="troubleshoot.xtp#thread-dump">Troubleshooting</a>
section of the Resin documentation.
</p>

<example title="jps and jstack">
<b># jps</b>
12903 Jps
20087 Resin
<b># jstack 20087</b>
Attaching to process ID 20087, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.5.0-beta2-b51
Thread 12691: (state = BLOCKED)
 - java.lang.Object.wait(long) (Compiled frame; information may be imprecise)
 - com.caucho.util.ThreadPool.runTasks() @bci=111, line=474 (Compiled frame)
 - com.caucho.util.ThreadPool.run() @bci=85, line=423 (Interpreted frame)
 - java.lang.Thread.run() @bci=11, line=595 (Interpreted frame)


Thread 12689: (state = BLOCKED)
 - java.lang.Object.wait(long) (Compiled frame; information may be imprecise)
 - com.caucho.util.ThreadPool.runTasks() @bci=111, line=474 (Compiled frame)
 - com.caucho.util.ThreadPool.run() @bci=85, line=423 (Interpreted frame)
 - java.lang.Thread.run() @bci=11, line=595 (Interpreted frame)

...

</example>

</s1>

    <!-- performance-faq.xtp -->
    
<s1 title="How many concurrent users can a Resin server handle?" type="faq">

<p>
This is not a question that can be answered in a general way.  It
is very dependent on the particular application that Resin is used
for.  Factors such as database usage, how the session object is
used, the use of server side caching, and application
architecture in general have a significant effect on the
capabilities of a website.
</p>

<p>
The best (and only practical) way to answer this question is to
perform some benchmarking tests for your particular application on
a server similar to the one that will host the website.
The freely available httperf tool, as well as various others, are
useful for this purpose.
</p>

<p>
When using testing tools, 500 "concurrent threads" does not mean
the same thing as "500 concurrent users".  A typical user is not
constantly making requests to the server.  Typical usage involves
a request for a page (with possible subsequent requests for
images), and then a period of inactivity as the user reads or
watches the content that has been downloaded.
</p>

<p>
The ratio of number of users to number of threads again depends
on the application involved.  For example, it may be that the
ratio for an application is 50:1, meaning that 2500 users will
use at maximum 250 threads on the server.
</p>

<p>
Ideally, application benchmarks use "user scenario" scripts.  The
script imitates what a typical user wil do, including pauses
between requests.  This kind of script is useful for providing an
accurate picture of web server usage.
</p>

<p>
The primary configuration item in Resin for handling a greater
load is <a config-tag="thread-max"/>.  The default in <code>resin.xml</code>
can be adjusted upwards to handle increased load, the limit is determined by
the underlying operating system.
</p>

<p>
If anticipated load overruns a Resin server, either with CPU
usage or with encountering OS thread limitations, clustering can
be used to add another server to share the load.
</p>
</s1>

<s1 title="How does Resin use JNI?" type="faq">

<p>
The JNI code is compiled on the various
Unix systems when the <code>./configure; make; make install</code>
step is performed during installation.  Windows has precompiled dlls.
</p>

<p>
Resin uses JNI in certain critical performance areas, such as low level socket
connections and file operations.  JNI is also used to interface with the
OpenSSL libraries.
</p>

<p>
A significant benefit in particular is in Resin's ability to handle
keepalive's.  With JNI, Resin does not need a thread for each keepalive
connection.  The low-level <code>poll()</code> (or <code>select()</code> if
poll() is not available) functions are used.  The end result is the possibility of many more keepalive's than if a thread was needed for each keepalive.
</p>

<p>
The fallback if JNI is not available is to use the JDK equivalents of the
faster JNI calls.  Also, OpenSSL is only available through JNI.
</p>

<p>
Resin indicates that JNI is being used with a log message at startup:
</p>

<example>Loaded Socket JNI library.</example>

<p>
If JNI is not available, the log message is:
</p>


<example>Socket JNI library is not available.</example>
</s1>

  <!-- performance-scrapbook.xtp -->

<s1 title="General">

<s2 title="What are the best things to tune for better performance?" type="faq">
<description>
</description>
<p>The main configuration item is the <a config-tag="dependency-check-interval"/> especially
for Windows.  For deployment, you should set it something high like 60s
or larger.</p>

<p>You can also change the <a config-tag="cache-mapping"/> values, especially for stuff
like *.gif files that don't change.  Higher values mean that the
browsers won't need to go back to the server.</p>

<p>Other than that, most of the default configuration values are pretty
good, so you normally won't need to touch them.

</p><p>The most important performance tweak you can make is to set Expires or
better Last-Modified and/or ETag values on your servlet/JSP output.  If
the servlet/JSP output only changes every 15 minutes, as for a news
page, then caching it can be a big performance win.</p>

<p>Of course, for stuff like shopping carts and stuff that's personalized,
that won't help.  But for many sites, the most heavily hit pages can be
cached.</p>
</s2>


<s2 title="Is Apache faster than Resin Standalone?" type="faq">
<description>
</description>
<p>For small files, Resin is about 10-20% faster.  For large files 
(1M), they're essentially identical.  (It's possible that the very 
latest Apache has improved performance.)</p>

<p>For JSP and Servlets, Resin standalone is certainly faster than 
Resin/Apache.  Because of the extra overhead of the Resin/Apache 
connection, the Resin/Apache configuration is necessarily slower than 
Resin standalone.</p>

<p>It's only static files where Apache could be faster.  Well, there's an 
exception for SSL.  It's conceivable that Apache/Resin with SSL would be 
faster that Resin with SSL.</p>
</s2>

<s2 title="What is the performance loss with a Servlet or JSP comparted to a static file?" type="faq">
<description>
</description>
<p>With Resin standalone, JSP files are essentially as fast as
static files (as long as you don't actually do any
processing. :-)</p>

<p>If Resin is behind another web server, like IIS or Apache,
there is a performance decrease with JSP and Servlet files,
which comes from the overhead needed for the communication
between the other web server and Resin.</p>
</s2>
</s1>

<s1 title="Caching">
<s2 title="What gets cached when a servlet does a forward?" type="faq">
<description>
I'm a bit unclear as to how to ensure that a servlet that forward to a JSP
page caches its output. Of course at the top of my JSP page (and any of its
&lt;jsp:include&gt;s) I put &lt;%@ page session=false %&gt;. Now, what do I need to do
about cache-mapping? Do I need to explicitly map the servlet, or will
resin.xml's suggested &lt;cache-mapping url-pattern='/' expires='15m'/&gt; work?
</description>

<p>The only thing that matters is the HTTP headers.  So if you telnet to 
the server, you should be able to see whether the headers are properly 
set or not.</p>

<p>In the case of a forward, you should be able to just set the headers 
without needing to modify the JSP itself.</p>
        
<p>One thing to be aware of: the caching is based on the original URL.  So 
if your forwarding servlet varies it's output based on some request 
headers (like User-Agent), it needs to set the Vary header.</p>

<p>&lt;cache-mapping&gt; is a related but somewhat separate issue, and I think we 
haven't explained it properly. </p>

<p>&lt;cache-mapping&gt; only works on cacheable responses which have not set the 
Expires header.  If you're missing the Expires header, &lt;cache-mapping&gt; 
will set it for you.  </p>

<p>Cacheable means:</p>

<ol>
<li>either ETag or Last-Modified must be set in the response (ETag is 
better).  The servlet will normally set that value.
</li><li>no cache-control is set in the response headers
</li><li>no Vary tag is set (Resin doesn't completely implement Vary.)
</li></ol>

<p>So your servlet still needs to do some work.  &lt;cache-mapping&gt; isn't all 
that you need.  The reason that &lt;cache-mapping&gt; works with  normal files 
is that Resin's FileServlet sets the Last-Modified and ETag headers, but 
does not set the Expires header.
</p>
</s2>
<s2 title="What if while the cache is being filled, another request comes?" type="faq">

<description>
I've tried several other server-side caching mechanisms, and
I've found that all of them are somewhat deficient when it comes
to refreshing expired caches.  The problem that usually arises is
that when the cache expires, every request then tries to take
responsibility for refreshing that cache - until one of them
finally completes and subsequent requests see the cache is up to
date.  If the page takes a long time to finish execution on a
busy site, this results in hundreds of requests piling up, all
executing the original page to refresh the cache.
</description>

<p>Resin 'fills a cache' the first time a request comes in.  If
another request comes in and Resin has not finished filling the cache,
the second request will be treated as uncachable.  This means that
until the cache is filled, requests will miss the cache and get
serviced directly.</p>

<p>This is also what happens when the
cache expires.  The first request to come in after the expiry
time invalidates it, and while it is being filled the other
requests pass through to the resource being cached.</p>

<p>This behaviour may be changed in Resin 3.0, updates are available
<a href="http://www.caucho.com/quercus/bugtrack/view.xtp?bugreport_id=1135">here</a>.</p>

</s2>
</s1>

  <!-- tuning.xtp -->

<s1 title="Resin Threads">

<p>Resin will automatically allocate and free threads as the load requires.
Since the threads are pooled, Resin can reuse old threads without the
performance penalty of creating and destroying the threads.  When the
load drops, Resin will slowly decrease the number of threads in the
pool until is matches the load.</p>

<p>Most users can set <var>thread-max</var> to something large (200 or
greater) and then forget about the threading.  Some ISPs dedicate a
JVM per user and have many JVMs on the same machine.  In that case, it
may make sense to reduce the <var>thread-max</var> to throttle the
requests.</p>

<p>Since each servlet request gets its own thread, <var>thread-max</var>
determines the maximum number of concurrent users.  So if you have a
peak of 100 users with slow modems downloading a large file, you'll
need a <var>thread-max</var> of at least 100.  The number of concurrent
users is unrelated to the number of active sessions.  Unless the user
is actively downloading, he doesn't need a thread (except for "keepalives").
</p>

</s1>

<s1 title="Keepalives">

<p>Keepalives make HTTP and srun requests more efficient.  Connecting to
a TCP server is relatively expensive.  The client and server need to
send several packets back and forth to establish the connection before
the first data can go through.  HTTP/1.1 introduced a protocol to keep
the connection open for more requests.  The srun protocol between
Resin and the web server plugin also uses keepalives.  By keeping the
connection open for following requests, Resin can improve performance.
</p>

<example title="resin.xml for thread-keepalive">
&lt;resin xmlns="http://caucho.com/ns/resin"&gt;
  &lt;cluster id="app-tier">

    &lt;server-default>
      &lt;thread-max&gt;250&lt;/thread-max&gt;

      &lt;keepalive-max&gt;500&lt;/keepalive-max&gt;
      &lt;keepalive-timeout&gt;120s&lt;/keepalive-timeout&gt;
    &lt;/server-default>
    ...
  &lt;/cluster>
&lt;/resin>
</example>

<s2 title="Timeouts">

<p>Requests and keepalive connections can only be idle for a limited
time before Resin closes them.  Each connection has a read
timeout, <var>request-timeout</var>.  If the client doesn't send a request
within the timeout, Resin will close the TCP socket.  The timeout
prevents idle clients from hogging Resin resources.</p>

<example>
&lt;resin xmlns="http://caucho.com/ns/resin">
  &lt;cluster id="app-tier">

    &lt;server-default>
      &lt;thread-max&gt;250&lt;/thread-max&gt;

      &lt;socket-timeout&gt;30s&lt;/socket-timeout&gt;

      &lt;http port="8080"/>
    &lt;/server-default>

    ...
  &lt;/cluster>
&lt;/resin>
</example>

<example>
&lt;resin xmlns="http://caucho.com/ns/resin">
  &lt;cluster id="app-tier">

    &lt;server-default>
      &lt;thread-max&gt;250&lt;/thread-max&gt;

      &lt;load-balance-idle-time&gt;20s&lt;/load-balance-idle-time&gt;

      &lt;socket-timeout&gt;30s&lt;/socket-timeout&gt;

      &lt;http port="8080"/>
    &lt;/server-default>

     &lt;server id="app-a" address="192.168.2.1" port="6802"/>

     ...
   &lt;cluster&gt;
 &lt;resin&gt;
</example>

<p>In general, the socket-timeout and keepalives are less important
for Resin standalone configurations than Apache/IIS/srun
configurations.  Very heavy traffic sites may want to reduce the
timeout for Resin standalone.</p>

<p>Since <var>socket-timeout</var> will close srun connections, its
setting needs to take into consideration the
&lt;<a href="server-tags.xtp#load-balance-idle-time">load-balance-idle-time</a>
setting for mod_caucho or isapi_srun.  <var>load-balance-idle-time</var> is the
time the plugin will keep a connection open.  <var>socket-timeout</var> must
always be larger than <var>load-balance-idle-time</var>, otherwise the plugin
will try to reuse a closed socket.</p>

</s2>

<s2 title="Plugin keepalives (mod_caucho/isapi_srun)">

<p>The web server plugin, mod_caucho, needs configuration for its keepalive
handling because requests are handled differently in the web server.
Until the web server sends a request to Resin, it can't tell if Resin
has closed the other end of the socket.  If the JVM has restarted
or if closed the socket because of <var>socket-timeout</var>,
mod_caucho will not know about the closed socket.  So mod_caucho needs
to know how long to consider a connection reusable before closing it.
<var>load-balance-idle-time</var> tells the plugin how long it should consider a
socket usable.</p>

<p>Because the plugin isn't signalled when Resin closes the socket,
the socket will remain half-closed until the next web server request.
A <var>netstat</var> will show that as a bunch of sockets in the FIN_WAIT_2
state.  With Apache, there doesn't appear to be a good way around
this.  If these become a problem, you can increase
<var>socket-timeout</var> and <var>load-balance-idle-time</var> so the JVM won't close the
keepalive connections as fast.</p>

<example>
unix&gt; netstat
...
localhost.32823      localhost.6802       32768      0 32768      0 CLOSE_WAIT
localhost.6802       localhost.32823      32768      0 32768      0 FIN_WAIT_2
localhost.32824      localhost.6802       32768      0 32768      0 CLOSE_WAIT
localhost.6802       localhost.32824      32768      0 32768      0 FIN_WAIT_2
...
</example>

</s2>

<s2 title="TCP limits (TIME_WAIT)">

<p>A client and a server that open a large number of TCP connections can
run into operating system/TCP limits.  If mod_caucho isn't configured
properly, it can use too many connections to Resin.  When the limit is
reached, mod_caucho will report "can't connect" errors until a timeout
is reached.  Load testing or benchmarking can run into the same
limits, causing apparent connection failures even though the Resin
process is running fine.</p>

<p>The TCP limit is the TIME_WAIT timeout.  When the TCP socket
closes, the side starting the close puts the socket into the TIME_WAIT
state.  A <var>netstat</var> will short the sockets in the TIME_WAIT
state.  The following shows an example of the TIME_WAIT sockets
generated while benchmarking.  Each client connection has a unique
ephemeral port and the server always uses its public port:</p>

<example title="Typical Benchmarking Netstat">
unix&gt; netstat
...
tcp   0   0 localhost:25033  localhost:8080  TIME_WAIT   
tcp   0   0 localhost:25032  localhost:8080  TIME_WAIT   
tcp   0   0 localhost:25031  localhost:8080  TIME_WAIT   
tcp   0   0 localhost:25030  localhost:8080  TIME_WAIT   
tcp   0   0 localhost:25029  localhost:8080  TIME_WAIT   
tcp   0   0 localhost:25028  localhost:8080  TIME_WAIT
...
</example>

<p>The socket will remain in the TIME_WAIT state for a
system-dependent time, generally 120 seconds, but usually
configurable.  Since there are less than 32k ephemeral socket available to
the client, the client will eventually run out and start seeing
connection failures.  On some operating systems, including RedHat
Linux, the default limit is only 4k sockets.  The full 32k sockets
with a 120 second timeout limits the number of connections to about
250 connections per second.</p>

<p>If mod_caucho or isapi_srun are misconfigured, they can use too
many connections and run into the TIME_WAIT limits.  Using keepalives
effectively avoids this problem.  Since keepalive connections are
reused, they won't go into the TIME_WAIT state until they're finally
closed.  A site can maximize the keepalives by setting
<var>thread-keepalive</var> large and setting <var>live-time</var> and
<var>request-timeout</var> to large values.  <var>thread-keepalive</var> limits
the maximum number of keepalive connections.  <var>live-time</var> and
<var>request-timeout</var> will configure how long the connection will be
reused.</p>

<example title="Configuration for a medium-loaded Apache">
&lt;resin xmlns="http://caucho.com/ns/resin">
  &lt;cluster id="app-tier"&gt;

    &lt;server-default>
      &lt;thread-max&gt;250&lt;/thread-max&gt;

      &lt;keepalive-max&gt;250&lt;/keepalive-max&gt;
      &lt;keepalive-timeout&gt;120s&lt;/keepalive-timeout&gt;

      &lt;load-balance-idle-time&gt;100s&lt;/load-balance-idle-time&gt;
    &lt;/server-default>

    &lt;server id="app-a" address="192.168.2.1"/&gt;

    ...
  &lt;/cluster&gt;
&lt;/resin&gt;
</example>

<p><var>socket-timeout</var> must always be larger than
<var>load-balance-idle-time</var>.
In addition, <var>keepalive-max</var> should be larger than
the maximum number of Apache processes.</p>

</s2>

</s1>  
  </body>
</document>