<title>Reliability and Load Balancing</title>

<summarylist/>

<p/>Sites can increase reliability using the web server to distribute the
load to more than one JVM.  If something happens to the first JVM, Resin
will send the request to the backup without the browser even being
aware of the redirection.

<section title="Overview">

To understand how Resin's load balancing works, it's important to review
how the plugin dispatches requests to the backend JVM, i.e. the srun.  The
following sequence describes a typical request:

<ol>
<li>Request arrives at web server.
<li>Plugin (mod_caucho, mod_isapi, etc) checks if it's a Resin request
<li>Plugin selects a backend JVM, i.e. a &lt;srun>
<ul>
<li>If it's an old session, send it to the owner JVM. (sticky-sessions)
<li>If it's a new request, send it to the next &lt;srun>, using a
round-robin policy.
</ul>
<li>Plugin sends the request to the backend JVM with a TCP socket.
<li>Plugin receives the response from the backend JVM with the same TCP socket.
</ol>

<p/>The plugin needs to know which requests should go to Resin, i.e. the
servlet-mappings.  And it needs to know the TCP host/port names of the
backend machines, i.e. the &lt;srun> and &lt;srun-backup> tags.
/caucho-status shows all that information in one table.  All the
plugins and the JVMs can read the same resin.conf, making maintenance
easier.

<p/>The plugin controls the load balancing since it needs to decide
which JVM to use.  Because the plugin is key in load-balancing, looking at
the /caucho-status will tell you exactly how your system is configured.
The JVMs are just passive, waiting for the next request.  From the
JVM-perspective, a request from a plugin is identical to
an HTTP request, except it uses a slightly different encoding.  In fact, with
Resin 1.2, the same JVM can server as an srun and as an httpd listening to
port 8080, for example.  The dual srun/http configuration can be
useful for debugging.

<p/>Selecting a free JVM is done using a round-robin policy.
Although the round-robin policy is simple, in practice it is as
effective as complicated balancing policies.  In addition, because
it's simple, round-robin is more robust and faster than adaptive policies.

</section>

<section title='Single Machine'>

The cheapest backup strategy just uses a single machine for the web
server and two JVMs.  One JVM is designated as primary and the other
is a backup.  If the first fails for some reason, the second will take
over.  Because the backup is normally not used, it doesn't really take
up much system resources.

<p/><center>
<ct:img src="backup.gif"/>
</center>

<example title="resin.conf">
&lt;caucho.com>
&lt;http-server>

  &lt;srun id="a" host='localhost' port='6802' srun-index='1'/>
  &lt;srun-backup id="b" host='localhost' port='6803' srun-index='2'/>

  ...
  
&lt;/http-server>
&lt;/caucho.com>
</example>

<sidebar>Use <var//caucho-status/> to check your configuration</sidebar>

<p/>You will start the two srun processes separately.  Each srun needs to
know which port to listen to.  The <var/-server/> argument to httpd.sh selects
a srun block to start.  <var/-server a/> selects the first one, i.e.
port 6802 and <var/-server b/> selects the second one.

<p/>Here's how to start them on unix:

<example>
unix> httpd.sh -pid srun1.pid -server a start
unix> httpd.sh -pid srun2.pid -server b start
</example>

<p/>On Unix, the <var/-pid/> is used to keep track of the live srun so
a later <var/httpd.sh stop/> will work.  It just names a file that will
contain the process id (pid) of the started process.

<p/>Use the -install-as to install them on NT.  <note>The -install-as must
occur before the -server</note>.

<example>
c:\resin1.2> bin/httpd -install-as ResinA -server a
c:\resin1.2> bin/httpd -install-as ResinB -server b
</example>

<p/>On Unix, the <var/-pid/> is used to keep track of the live srun so
a later <var/httpd.sh stop/> will work.  It just names a file that will
contain the process id (pid) of the started process.

<p/>To make sure that your web server understands the configuration,
look at <var/http://host/caucho-status/>.  caucho-status will
show the current state of all the JVMs.

<subsection title="Summary">

<ul>
<li>The webserver plugin (mod_caucho, or isapi_srun) looks in the resin.conf
for &lt;srun> and &lt;srun-backup> elements.
<li><var//caucho-status/> shows all the servlet runners and backups.
<li><var/httpd.sh -server a/> start the srun with id="a".
<li>The plugin will always send a session to the same backend srun.
</ul>

</subsection>

</section>

<section title='Single Web Server Load Balancing'>

<p/>Once you start using multiple computers, you can start distributing
the load between a single web server and multiple JVMs.
This is a cheap alternative to a router-based load balancer.  Also, by
using Resin's load balancing, you can make sure that sessions stay on
the same machine.

<p/>
<center><ct:img src="sticky-sessions.gif"/></center>

<example>
&lt;caucho.com>
&lt;http-server>

  &lt;srun id="1" host='host1' port='6802' srun-index='1'/>
  &lt;srun id="2" host='host2' port='6802' srun-index='2'/>
  &lt;srun id="3" host='host3' port='6802' srun-index='3'/>

  ...
  
&lt;/http-server>
&lt;/caucho.com>
</example>

<p/>Each host and the plugin can share the same resin.conf.  Sharing the
resin.conf makes maintenance easier, since the files won't get out of sync.

<p/>However, you could use a different resin.conf for plugin and
for each of the JVMs.  The resin.conf for the plugin, e.g. mod_caucho,
just needs enough information to list the &lt;srun> hosts and enough
servlet-mappings to tell the plugin where to send the requests.

<subsection title="Summary">

<ul>
<li>The webserver plugin (mod_caucho, or isapi_srun) looks in the resin.conf
for &lt;srun> and &lt;srun-backup> elements.
<li>The webserver plugin can share the same resin.conf as the JVMs.
<li><var/httpd.sh -server a/> starts the srun with id="a".
<li>The plugin sends a session to the same backend srun.
<li>New sessions or non-session requests balance the load with a round-robin
policy.
</ul>

</subsection>

</section>

<section title='What about sessions?'>

<p/>A session needs to stay on the same JVM that started it.
Otherwise, each JVM would only see every second or third request and
get confused.

<p/>To make sure that sessions stay on the same JVM, Resin encodes the
cookie with the host number.  In the previous example, the hosts would
generate cookies like:

<deftable>
<tr><th>srun-index<th>cookie prefix
<tr><td>1<td><var/aaa/>xxx
<tr><td>2<td><var/baa/>xxx
<tr><td>3<td><var/caa/>xxx
</deftable>

<note>srun-index only exists in Resin 1.2.3.  If unspecified, it defaults
to the index of the srun in the srun list.</note>

<p/>On the web server, mod_caucho will decode the cookie and send it
to the appropriate host.  So <var/baaX8Zwoo/> would go to host2.

<p/>In the infrequent case that host2 fails, Resin will send the
request to host3.  The user will lose the session but that's a minor
problem compared to showing a connection failure error.  To save sessions,
you'll need to use <a href="sessions.xtp">distributed sessions</a>.

</section>

<section title='Multiple Web Servers'>

Many larger sites like to use multiple web servers with a JVM and a
web server on each machine.  A router will distribute the load between
the machines.

<p/>In this configuration, the site needs to take control of its own
sessions.  Because the router will distribute the load randomly, any
persistent session state needs to be handled by a centralized server
like a database or use Resin's TCP-ring storage..

<p/>Even in this configuration, you can use Resin's load balancing to
increase reliability.  Each web server should choose its own JVM
first, but use another machine as a backup.

<p/>In this case, you can use the trick that <var/localhost/> refers
to the preferred host.  The configuration would look like:

<example>
&lt;caucho.com>
&lt;http-server>

  &lt;srun id="a" host='localhost' port='6802' srun-index='1'/>
  &lt;srun-backup id="b" host='host1' port='6802' srun-index='2'/>
  &lt;srun-backup id="c" host='host2' port='6802' srun-index='3'/>
  &lt;srun-backup id="d" host='host3' port='6802' srun-index='4'/>
  ...
  
&lt;/http-server>
&lt;/caucho.com>
</example>

<p/>Alternately, if you're using Apache, you could configure the sruns
in the httpd.conf.

<example title='host1 httpd.conf'>
CauchoConfigFile /home/www/resin/conf/resin.conf
CauchoHost host1 6802
CauchoBackup host2 6802
</example>

<example title='host2 httpd.conf'>
CauchoConfigFile /home/www/resin/conf/resin.conf
CauchoBackup host1 6802
CauchoHost host2 6802
</example>

<p/>I've made the order consistent so sessions will always go to the
correct machine.  <var/baaXXX/> will always go to host2.  Normally, of
course, sites using this configuration will handle their own cookies.

</section>

<section title='Multiple Web Servers, Single JVM'>

<p/>Multiple web servers can use the same JVM.  For example, a fast
plain webserver and an SSL web server may only need a single JVM.
(Although a backup would be good.)  Since the JVM doesn't care where
the request comes from, it can treat each request identically.

<p/>This simplifies SSL development.  A servlet just needs to check
the <var/request.isSecure()/> method to see if the request is SSL or
not.  Other than that, all requests are handled identically.

</section>

<section title='When everything fails'>

<p/>By default, if <var/mod_caucho/> can't connect to any of the JVMs,
it will return a basic "can't connect" page to the user.  Sites which
want a more professional response can redirect the user to an error
page.

<p/>In the resin.conf, you'll use:

<example>
&lt;caucho.com>
&lt;http-server>
  &lt;error-page exception='connection'
               location='/error.html'/>
&lt;/http-server>
&lt;/caucho.com>
</example>

<p/>The error page must be an absolute path because it could be called
from any url.  Of course, it can't refer to a servlet or to a JSP file.

</section>
