caucho
Resin
FAQ
Reference Guide
Demo
Tutorial

Getting Started
Configuration
IDE
Topics
JSP
XML/XSLT

Virtual Hosts
Balancing
Distributed Sessions
Caching
JavaScript
Filters
Servlets
Admin
WebDAV
Velocity
EJB Clients
JMX
Burlap
Hessian
 Reliability and Load Balancing

Virtual Hosts
Topics
Distributed Sessions

  1. Hardware Load Balancing
  2. Using Resin as the Load Balancer
  3. Balancing with the Apache/IIS plugin
  4. Single Machine
    1. Summary
  5. Single Web Server Load Balancing
    1. Summary
  6. What about sessions?
  7. Multiple Web Servers
  8. Multiple Web Servers, Single JVM
  9. When everything fails

As traffic increases, web sites need to add additional web servers and servlet engines. Distributing the traffic across the servers and coping when a server restarts is the challenge of load balancing.

  • What is balancing the load?
    • Hardware load-balancer
    • Resin web server using LoadBalanceServlet
    • Web Server (Apache/IIS) with plugin
  • How is session consistency maintained?

In general, the hardware load-balancer will have the best results while using the Resin or Apache/IIS is a low-cost alternative for medium sites.

Hardware Load Balancing

Sites with a hardware load balancer will generally put one Resin JVM on each server and configure the load balancer to distribute the load across those JVMs. Although it's possible to configure Resin with Apache/IIS in this configuration, it's not necessary and running the Resin as a web server reduces the configuration complexity.

Sites using sessions will configure distributed sessions to make sure the users see the same session values. The IP-based sticky sessions provided by hardware load balancers should be used to increase efficiency. The IP-sessions will usually send the request to the right server, but there are clients behind firewalls and proxies which will have different IPs for each request even though the session is the same. IP-sessions are only mostly sticky.

A typical configuration will use the same resin.conf for all servers and use the -server flag to start the correct one:

resin.conf for all servers
<http-server>
  <srun id='a' host='192.168.0.1' port='6802' srun-index='1'/>
  <srun id='b' host='192.168.0.2' port='6802' srun-index='2'/>
  <srun id='c' host='192.168.0.3' port='6802' srun-index='3'/>
  <srun id='d' host='192.168.0.4' port='6802' srun-index='4'/>

  <session-config>
    <tcp-store/>
  </session-config>

  ...
</http-server>

On Unix, the servers will generally be started using some startup script. Each server will have a different value for -server and for -pid.

Starting each server on Unix
unix> bin/resin -server a -pid server-a.pid start
Installing each server on Windows
resin> bin/httpd -server a -install-as resin-a
resin> net start resin-a

Using Resin as the Load Balancer

Resin 2.1 includes a LoadBalanceServlet which will balance requests to backend servers. Because it's implemented as a servlet, this configuration is the most flexible. A site might send all requests for /foo to the backend host 192.168.0.1 and all requests to /bar to the backend host 192.168.0.2. Since Resin has an integrated HTTP proxy cache, the front-end machine can cache results for the backend servers.

Using Resin as the load balancing web server, requires a minimum of two configuration files: one for the load balancing server, and one for the backend servers. The front configuration will dispatch several url-patterns to the backend servers, while the backend will need to actually serve the requests.

The following example sends all URLs starting with /foo to one of the servers in srun-group a.

front.conf
<http-server>
  <http port='80'/>

  <srun id='back1' srun-group='a' srun-index='1'
           host='192.168.0.1' port='6802'/>
  <srun id='back2' srun-group='a' srun-index='2'
           host='192.168.0.2' port='6802'/>
  <srun id='back3' srun-group='b' srun-index='3'
           host='192.168.0.3' port='6802'/>

  <servlet>
    <servlet-name>balance-a</servlet-name>
    <servlet-class>com.caucho.http.servlet.LoadBalanceServlet</servlet-class>
    <init-param srun-group='a'/>
  </servlet>

  <servlet-mapping url-pattern='/foo/*' servlet-name='balance-a'/>
</http-server>
  • The <http> and <srun> must have different values for id.
  • The <srun> must have an id so they will not be started along with the <http>.
  • Since the <http> configuration has no id it will be used when you start Resin without a -server configuration.
  • The srun-index is important and must match the srun-index in the backend configuration.

The backend server configuration is identical to the server configuration for the hardware load balancer. In general, most sites will use some form of distributed session management.

back.conf for all backend servers
<http-server>
  <srun id='a' host='192.168.0.1' port='6802' srun-index='1'/>
  <srun id='b' host='192.168.0.2' port='6802' srun-index='2'/>

  <session-config>
    <tcp-store>
  </session-config>

  ...
</http-server>

Balancing with the Apache/IIS plugin

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:

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

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 <srun> and <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.

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.

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.

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.

resin.conf
<caucho.com>
<http-server>

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

  ...
  
</http-server>
</caucho.com>
Use /caucho-status to check your configuration

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

Here's how to start them on unix:

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

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

Use the -install-as to install them on NT.

Note: The -install-as must occur before the -server

.

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

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

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

Summary

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

Single Web Server Load Balancing

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.

<caucho.com>
<http-server>

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

  ...
  
</http-server>
</caucho.com>

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.

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 <srun> hosts and enough servlet-mappings to tell the plugin where to send the requests.

Summary

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

What about sessions?

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.

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:

srun-indexcookie prefix
1axxx
2bxxx
3cxxx

Note: srun-index only exists in Resin 1.2.3. If unspecified, it defaults to the index of the srun in the srun list.

On the web server, mod_caucho will decode the cookie and send it to the appropriate host. So bX8ZwooOz would go to host2.

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 distributed sessions. Also take a look at tcp sessions.

The following example is a typical configuration for a distributed server using an external hardware load-balancer, i.e. where each Resin is acting as the HTTP server. Each server will be started as -server a or -server b to grab its specific configuration.

In this example, sessions will only be stored when the server shuts down, either for maintenance or with a new version of the server. This is the most lightweight configuration, and doesn't affect performance significantly. If the hardware or the JVM crashes, however, the sessions will be lost. (If you want to save sessions for hardware or JVM crashes, remove the <save-on-shutdown/> flag.)

resin.conf
<caucho.com>
<http-server>
  <http id='a' port='80'/>
  <srun id='a' port='6802' host='192.168.0.1' srun-index='1'/>

  <http id='b' port='80'/>
  <srun id='b' port='6802' host='192.168.0.2' srun-index='2'/>

  <http id='c' port='80'/>
  <srun id='c' port='6802' host='192.168.0.3' srun-index='3'/>

  <!-- enable tcp-store for all hosts/web-apps -->
  <session-config>
    <tcp-store/>
    <save-on-shutdown/>
  </session-config>

  ...
</http-server>
</caucho.com>

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.

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.

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.

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

<caucho.com>
<http-server>

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

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

host1 httpd.conf
CauchoConfigFile /home/www/resin/conf/resin.conf
CauchoHost host1 6802
CauchoBackup host2 6802
host2 httpd.conf
CauchoConfigFile /home/www/resin/conf/resin.conf
CauchoBackup host1 6802
CauchoHost host2 6802

The order must be consistent for all servers so sessions will always go to the correct machine. bXXX must always go to host2.

Multiple Web Servers, Single JVM

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.

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

When everything fails

By default, if 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.

In the resin.conf, you'll use:

<caucho.com>
<http-server>
  <error-page exception-type='connection'
               location='/error.html'/>
</http-server>
</caucho.com>

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.


Virtual Hosts
Topics
Distributed Sessions
Copyright © 1998-2002 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.