10.2 The Communication Sequence of an HTTP Request
In order to configure and run a Tomcat
cluster, you will need to set up more than just Tomcat. For example,
you will need to provide a facility that causes requests coming into
Tomcat to be spread across multiple instances. This involves software
that runs in addition to your Tomcat installations.
To identify the points in the system where clustering features may be
implemented to distribute the requests, let's take a
look at the steps of the average HTTP client request. Figure 10-1 shows a typical nonclustered server running
Apache httpd, mod_jk2, and
Tomcat. The figure shows the steps of one HTTP
client's request through the system.
Depending on how your web application is written, you may not need to
use Apache httpd or mod_jk2
to set up and use a Tomcat cluster. We're showing
these components so that you can see how using them affects the HTTP
request communication sequence, and so you can determine which types
of clustering features you may want to use. If you use Apache
httpd, then httpd is your
web server. If you use Tomcat standalone, then Tomcat is your web
server.
Any user's HTTP request
to the server follows these steps:
|
These steps assume the more complex setup of using Apache
httpd as a frontend for Tomcat, largely because
this is the most common scenario for handling high-volume traffic
(where clustering would be a concern). If you aren't
using Apache httpd, simply replace
"Apache httpd"
with "Tomcat" in your reading.
|
|
Local DNS request. The user's web browser attempts
to resolve the web site's IP address from its name
via a DNS lookup network request to the user's local
DNS server (usually their ISP's DNS server or their
own company's DNS server). Most web browsers ask for
this IP address only once per run of the browser. Subsequent HTTP
requests from the same browser are likely to skip this step as well
as the next step.
Authoritative DNS request. Usually, the user's local
DNS server will not have the web site's IP address
in its cache (from a prior request), so it must ask the web
site's authoritative DNS server for the IP address
of the web site that the user wishes to view. The authoritative DNS
server will reply to the local DNS server with the IP address that it
should use for the web server. The local DNS server will attempt to
cache this answer, so that it won't need to make the
same request to the authoritative DNS server again anytime soon.
Subsequent requests from other browsers in the same network as the
first browser are likely to skip this step because the local DNS
server will already have the answer in its cache.
Local DNS response. The local DNS server replies, giving the browser
the IP address of the Apache httpd web server.
HTTP request. The browser makes an HTTP request to the IP address
given by DNS. This request may utilize HTTP keep-alive connections
for network efficiency, and therefore this single TCP socket
connection may be the only socket connection made from the browser to
Apache httpd for the entire duration of the
browser's HTTP session. If the browser does not
implement or use HTTP keep-alive, then each request for a document,
image, or other content file will create a separate TCP socket
connection into Apache httpd.
Apache httpd forwards all servlet/JSP requests
to mod_jk2 to be sent on to Tomcat. Apache
httpd may serve a number of static files by
itself, however, depending on how it's configured.
mod_jk2 forwards all requests on to Tomcat.
Tomcat sends one or more requests to backend server(s). Tomcat may
depend on other servers to create the dynamic content response that
it forwards back to the browser. It may connect to a database by way
of JDBC, or it may use JNDI to look up other objects such as
Enterprise JavaBeans and call one or more methods on the objects
before being able to assemble the dynamic content that makes up the
response.
Upon completion of these necessary steps, the direction of flow
reverses, and replies to each step are made in the reverse order that
the request steps were made, working back through the already-open
network connections.
In order for your cluster to be fault-tolerant, so that it is still
100% usable when any single hardware or software component fails,
your cluster must have no single point of failure. You must have two
or more of each component that is necessary to process any request.
For instance, you can't set up just one Apache
httpd with mod_jk2 and two
Tomcat instances behind it, since if httpd or
mod_jk2 fails, no requests will ever make it to
either of the Tomcat instances. In that case, Apache
httpd is a single point of failure.
To support a cluster of Apache httpd and Tomcat
instances, you can implement clustering features in multiple spots
along this request sequence. Figure 10-2 shows the
same request sequence, only this time the web site is served on a
cluster of Apache httpd and Tomcat instances.
Here are some of the clustering technologies that you could set up
and run:
- DNS request distribution
Instead of configuring your DNS server to give out one IP address to
one Apache httpd server instance, you can
configure it to give out three IP addresses that each go to a
separate Apache httpd or Tomcat instance.
- TCP Network Address Translation (NAT) request distribution
Regardless of how many IP addresses DNS gives to the
client's browser, the web server's
first contact IP address(es) can be answered by a TCP NAT request
distributor, which acts as a gateway to two or more web servers
behind it. You can use the NAT request distributor for both load
balancing and failover.
- mod_jk2 load balancing and failover
If you run two or more Tomcat instances behind one or more Apache
httpd instances, you can use
mod_jk2 load balancing and failover to
distribute requests across your Tomcat cluster and to keep requests
from being distributed to any failed Tomcat instance.
- JDBC request distribution and failover
You could use a clustered database and a JDBC driver that load
balances connections among the machines in the database cluster, or
you could use a replicated database with a JDBC driver that knows
when to fail over to the secondary database server.
10.2.1 DNS Request Distribution
Request distribution can
be done at the authoritative DNS server. This is a Wide Area Network
(WAN) clustering solution that can distribute requests across server
machines at one or more data centers.
|
If you do not have authoritative control for at least one fully
qualified host name in your domain and can use at least two static IP
addresses, then you cannot take advantage of DNS request
distribution. You may, however, be able to take advantage of other
request distribution methods.
|
|
When the browser's local DNS asks for an IP address
from the web site's authoritative DNS, and there are
two machines in the cluster that run web servers, which IP address
should the authoritative DNS reply with? DNS can give both IP
addresses to the browser, but the browser will use only one of them.
Most of the time, system administrators set up general-purpose DNS
server software (such as BIND, for example) for their authoritative
DNS servers, and any local DNS asking for the IP address to the
cluster of web servers will be given all of the IP addresses that are
mapped to the web server host name. It's up to the
browser to choose which of the returned addresses to use. The browser
typically uses the first address in the list of addresses given to it
by its local DNS.
In order to balance the load a bit, most DNS server software will
give out the list of IP addresses in a different, circular order
every time a request is made. This means that no specific IP address
stays at the top of the list, and therefore the browsers will use the
IP addresses in a circular order. This is commonly known as
DNS
round-robin. DNS round-robin is simple and
relatively easy to configure, but it has many drawbacks:
It does not take load into account. General-purpose DNS software such
as BIND isn't written to know anything about content
server load. So, round-robin will eventually send clients to a server
machine that is overloaded, resulting in failed requests.
It is not fault-tolerant. It won't know anything
about machines that are down or have been temporarily removed from
the cluster's service pool. So, round-robin will
eventually send clients to a server machine that is down. If an
online store's web site has 10 machines in the
cluster and one machine goes down, 10% of the purchases (and the
revenue for those purchases) are lost until an administrator
intervenes.
It knows nothing about congested networks or downed network links. If
the authoritative DNS is providing IP addresses to server machines
residing in two different data centers, and the high-bandwidth link
to the first data center goes down, DNS round-robin may in fact send
half of a web site's clients to unreachable IP
addresses.
The best you can hope for is random distribution of requests among
all of the servers in the cluster, due to DNS caching and varying
browser implementations. Usually the distribution is random, but
there is no guarantee that it will be evenly random. Although DNS
round-robin can break up requests to different server machines in the
cluster, there still might be times when one server machine gets most
of the cluster's load. The more a service needs to
scale, the larger this problem becomes.
In order to perform
load balancing with DNS without the problems of DNS round-robin, the
DNS software must be specially written to monitor things such as
server load, congested or down network links, down server machines,
etc. Smart DNS request distributors such as Eddie (http://eddie.sourceforge.net), Foundry
Networks's ServerIron (http://www.foundrynetworks.com/products/webswitches),
and Cisco's
DistributedDirector
(http://www.cisco.com/warp/public/cc/pd/cxsr/dd/index.shtml)
can be configured to monitor many metrics (including server load) and
use them for request distribution criteria. For instance, if one of
the data centers loses connectivity to the public Internet, these
smart DNS request distributors could monitor the link and be aware of
the outage, and not distribute any requests to those servers until
the link is working again. With such great fault tolerance features,
DNS request distribution is a great way to initially distribute your
request load.
10.2.2 TCP NAT Request Distribution
Once DNS has given the
user's web browser at least one IP address, the web
browser opens a TCP connection to that IP address. The web browser
will send an HTTP request over this TCP socket connection. In a
nonclustered setup, this IP address goes to the one and only web
server instance (it could be Apache httpd,
Tomcat's web server, or even some other HTTP server
implementation). But, in a clustered environment, you should be
running more than one web server instance, and requests should be
balanced across them. You can use a DNS request distributor to
distribute requests directly to these web server instances, or you
can point DNS to a TCP NAT request distributor, which will distribute
requests across your web servers.
Figure 10-3 shows a NAT request distributor in front of three web
server instances, each on their own server computer.
NAT request distributors
can be used for load balancing, fault tolerance, or both. When a
browser makes a TCP connection to the NAT request distributor, it can
use one of many possible request distribution algorithms to decide
which internal web server instance to hand off the connection to.
When you initially set up and configure a NAT request distributor,
you will choose the algorithm you want to use for distributing
requests. The available algorithms vary with the different NAT
request distributor implementations. Generally, all distributors will
offer at least a round-robin algorithm. Some can monitor the load on
the web server machines and distribute requests to the least-loaded
server, and some allow the administrator to give each web server
machine a weighted value representing the capacity of each server and
distribute requests based on the relative capacity differences.
Most NAT request distributors also offer fault tolerance by detecting
various kinds of web server faults, and then will stop distributing
requests to any server that is down. For example, in Figure 10-3, if
web server 2's operating system crashes and does not
reboot on its own, the NAT request distributor will stop distributing
requests to web server 2 and will evenly balance all of the request
load across web servers 1 and 3. The users of the site
won't notice that web server 2 has crashed, and they
may continue using the site while the system administrator reboots
web server 2's machine and brings it back online.
Once server 2 is back, the NAT request distributor will automatically
notice that it's back and resume sending requests to
it.
There are many NAT request distributor implementations available,
both commercially and as open source software that runs on commodity
computer hardware. Here are several examples:
- The Linux Virtual Server Project's VS-NAT
The Linux Virtual Server Project (http://www.linuxvirtualserver.org)
distributes an open source software package called VS-NAT that runs
only on the Linux operating system, but it is feature-rich and comes
with good documentation. See http://www.linuxvirtualserver.org/VS-NAT.html
for details.
- IP Filter
This is another open source software package, and it runs on most
Unix-like operating systems, with the exception of Linux. It is used
for many packet-filtering purposes, but can be used as a round-robin
NAT request distributor as well. The IPF home page is http://cheops.anu.edu.au/~avalon, and you can
find information about how to use it as a request distributor at
http://www.obfuscation.org/ipf/ipf-howto.html#TOC_38.
- Foundry Networks's ServerIron
This commercial hardware solution is known to be one of the best
request distributors in the industry. It is packed with features and
robustness, and many large corporate clusters already use it. See
http://www.foundrynetworks.com/products/webswitches
for further information.
- Cisco Systems's LocalDirector
This is another commercial hardware solution, and it was one of the
first load-balancing hardware solutions available. LocalDirector also
implements a large number of useful features and is in use at many
large corporations. Read about it on Cisco's web
site at http://www.cisco.com/warp/public/cc/pd/cxsr/400/index.shtml.
10.2.3 mod_jk2 Load Balancing and Failover
If you decide to
use Apache httpd as your web server, and
you're using mod_jk2 to send
requests to Tomcat, you can take advantage of
mod_jk2's load-balancing and
fault-tolerance features.
Here are some of the things that each Apache
httpd with mod_jk2 in your
cluster can do:
- Distribute requests to one or more Tomcat instances
You can configure many Tomcat instances in your
mod_jk2's
workers.properties file, giving each one an
lb_factor value that functions as a weighted
request distribution metric.
- Detect Tomcat instance failure
mod_jk2 will detect when a Tomcat
instance's connector service is no longer responding
and will stop sending requests to it. Any remaining Tomcat instances
will take the additional load for the failed instance.
- Detect when a Tomcat instance comes back up after failing
After it has stopped distributing requests to a Tomcat instance due
to the instance's connector service failure,
mod_jk2 periodically checks to see if
it's available again and will automatically converge
it into the pool of active Tomcat instances when this happens.
The following steps outline how to set up one Apache
httpd's
mod_jk2 (on a server computer called
apache1) to do TCP load balancing across two
Tomcat instances that reside on two separate server computers called
tc1 and tc2.
First, configure your
apache2/conf/workers2.properties file to include
information about both Tomcat instances and map some requests
(we're mapping the examples web
application), like this:
#---- workers2.properties
# Define the TCP socket communication channel for Tomcat #1
[channel.socket:tc1:8009]
info=Ajp13 forwarding over a TCP socket
tomcatId=tomcat1
debug=0
lb_factor=1
# Define the TCP socket communication channel for Tomcat #2
[channel.socket:tc2:8009]
info=Ajp13 forwarding over a TCP socket
tomcatId=tomcat2
debug=0
lb_factor=1
[status:]
info=Status worker, displays runtime information.
[uri:/jkstatus/*]
info=Display status information and checks the config file for changes.
group=status:
# Map the Tomcat "examples" webapp to the Web server uri space
[uri:/examples/*]
info=Map the entire "examples" webapp
debug=0
# Configure the shared memory file
[shm]
file=/usr/local/apache2/logs/shm.file
size=1048576
debug=0
#---- end of workers2.properties
You can set the lb_factors to any integer values
you want. The lower the number you use, the more preferred the Tomcat
instance is; the higher the lb_factor, the less
requests that Tomcat instance will be given. An
lb_factor of 0 means that all
requests go to that Tomcat instance unless it's not
responding. If it's not responding, then
mod_jk2 fails over to the next instance in the
list.
Next, configure and run the Tomcat instances on the Tomcat server
computers. Set up your Java environment on tc1 and
tc2:
$ JAVA_HOME=/usr/local/j2sdk1.4.1_02
$ export JAVA_HOME
$ PATH=$JAVA_HOME/bin:$PATH
$ export PATH
$ java -version
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)
Make sure that CATALINA_HOME is set on
tc1 and tc2:
$ CATALINA_HOME=/usr/local/jakarta-tomcat-4.1.23
$ export CATALINA_HOME
$ cd $CATALINA_HOME
Then, on each of the Tomcat instance machines, configure the
$CATALINA_HOME/conf/server.xml file so that the
Engine's
jmvRoute is set to the same string you set the
Tomcat instance's tomcatId to in
the workers2.properties file:
<!-- Define the top level container in our container hierarchy -->
<Engine name="Standalone" defaultHost="localhost" debug="0"
jvmRoute="tomcat1">
|
Each Tomcat instance's jvmRoute
value must be unique.
|
|
Also, in the same file, make sure that the Coyote/JK2 AJP 1.3
Connector on port 8009 is configured:
<!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009 -->
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8009" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"
acceptCount="10" debug="0" connectionTimeout="0"
useURIValidationHack="false"
protocolHandlerClassName=
"org.apache.jk.server.JkCoyoteHandler"
/>
To test that the request distribution is indeed working,
we'll add some test content. In each Tomcat
instance's webapps/ROOT/
directory, do the following:
$ cd $CATALINA_HOME/webapps/examples
$ echo 'Tomcat1' > instance.txt
Do the same in the second Tomcat's
webapps/ROOT/ directory, labeling it as
"Tomcat2":
$ cd $CATALINA_HOME/webapps/examples
$ echo 'Tomcat2' > instance.txt
Then start up each of the two Tomcat instances:
$ cd $CATALINA_HOME
$ bin/catalina.sh start
Once it's all running, access the Apache
httpd instance on the apache1
machine, and request the instance.txt page by
loading the URL http://apache1/examples/instance.txt in your
browser. The first request will likely be slow because Tomcat
initializes everything on the first request. The page will display
either "Tomcat1" or
"Tomcat2", depending on which
Tomcat instance mod_jk2 sent you to. Reloads of
the same URL should send you back and forth between them, proving
that mod_jk2 is indeed balancing the load.
Try accessing mod_jk2's
jkstatus page by loading the URL http://apache1/jkstatus in your browser. It
shows quite a bit of information about mod_jk2,
the instances, the requests, etc. Figure 10-4 shows
what ours looks like, running one Apache httpd
with mod_jk2 that is load balancing across two
Tomcat instances, all running on the same computer.
10.2.4 Distributed Java Servlet Containers
The Java Servlet
Specification 2.2 defines and specifies the semantics of
distributed servlet containers, and
the Servlet Specification 2.3 further clarifies the semantics. The
specifications define the behavior and leave much of the
implementation detail up to the servlet container authors. Part of
what they specify is behavior that can only be implemented as part of
the core of any servlet container: a distributed-aware facility built
into that core. Specification-compliant distributed servlet container
functionality can never be implemented without the servlet container
core being aware of the distributed servlet container behavior that
the Java Servlet Specifications describe.
Tomcat 4.1 was originally architected as a nondistributed servlet
container, although work is being done to bring it ever closer to
implementing all of the required features that will allow it to
operate as a distributed servlet container when it is properly
installed and configured for that purpose. Even if you run Tomcat in
a specification-compliant distributed servlet container, your web
applications may not be able to take advantage of these distribution
features, unless they are written to be distributed web applications.
Here is how the specification describes a distributable web
application:
A web application that is written so that it can be deployed in a web
container distributed across multiple Java virtual machines running
on the same host or different hosts. The deployment descriptor for
such an application uses the distributable
element.
Marking the web application as being distributable
in the application's web.xml
file means that it will be deployed and run in a special way on a
distributed servlet container. Typically, this means that the author
of the web application knows how the distributed servlet container
will deploy and run the application, as opposed to how it would be
deployed and run in a nondistributed servlet container.
A distributed servlet container will generally deploy and run one
instance of the application per servlet container, with each servlet
container and web application in a separate JVM, and requests will be
processed in parallel. Each JVM may be on its own server
computer�in Tomcat's case, the administrator
does the deployment, either through the Manager or Admin
applications, or through moving WAR files around and restarting the
Tomcat instances. Additionally, each Tomcat instance runs its own
instance of the web application, and treats the application instance
as if it is the only instance running.
10.2.4.1 Servlet sessions
Because there are at least a couple of
ways to distribute requests to multiple servlet container instances,
the Java Servlet Specification chose one request distribution model
for web applications that are marked
distributable:
Within an application marked as distributable, all
requests that are part of a session must be handled by one VM at a
time.
This means that requests are handled in parallel by any and all
server instances in the cluster, but all requests belonging to the
same session from a single client must be processed by the same
servlet container instance.
|
You can have multiple JVMs, each handling requests concurrently, for
any given distributable web application.
|
|
Conversely, this means that if a client makes several
concurrent requests for a
distributable web application, your cluster must
not distribute those requests to different
servlet container instances. Specifying this model for
specification-compliant distributable web
applications makes it easier for everyone, since developers
don't need to worry about concurrent servlet
Session object modifications that occur across
multiple server computers and multiple JVMs. Also, since all requests
that belong to one servlet session must be processed by the same
servlet container instance, this makes Session
object replication an optional feature of distributed servlet
containers. Here's what the specification says about
that:
The Container Provider can ensure scalability and quality of service
features like load-balancing and failover by having the ability to
move a session object, and its contents, from any active node of the
distributed system to a different node of the system.
Note that the "can" in the above
sentence implies that session replication is an optional feature, so
it is not mandatory for distributed servlet containers to implement
session replication. However, it's such a handy
feature that almost all distributed servlet containers do. Just keep
in mind that when you write a distributable web application, the
servlet container may not replicate the session data among all
servlet container JVM instances. Additionally, the specification goes
on to say:
Context attributes are local to the VM in which they were created.
This prevents ServletContext attributes from being a shared memory
store in a distributed container. When information needs to be shared
between servlets running in a distributed environment, the
information should be placed into a session (See Chapter SRV.7,
"Sessions"), stored in a database,
or set in an Enterprise JavaBean.
With these exceptions, the behavior of a distributed servlet
container is the same as a nondistributed servlet container. For web
application authors, it's important to understand
that you probably need to treat user state data differently in
distributed applications.
10.2.4.2 Session affinity
When you have your cluster set up to
examine the HTTP session cookie and jvmRoute and
send all dynamic content requests from the same session to the same
Tomcat instance, you're using the session
affinity request distribution model. This just means that
all requests from the same session are served by the same Tomcat
instance.
|
The terms session affinity and sticky
sessions are usually used interchangeably.
|
|
mod_jk2 supports Tomcat session affinity. By
default, when Apache httpd forwards a request on
to mod_jk2, mod_jk2
examines the session cookie and the jvmRoute, and
forwards the request to the same Tomcat instance that created the
session.
For web applications that are marked
distributable, this model is the only one that
should be used, per the Java Servlet Specification. When all requests
belonging to one HTTP session are served by one Tomcat instance,
session replication is not necessary for the
application to function under normal circumstances. Of course, if the
Tomcat instance or the server machine it runs on fails, the servlet
session data is lost. Even if there are more Tomcat instances running
in the cluster, the session data was never replicated anywhere; as a
result, on the next HTTP request (handled by another Tomcat
instance), the user will find that their session state data is gone.
Session affinity by itself without session replication is a
clusterable solution, but it is not completely fault-tolerant.
10.2.4.3 Replicated sessions
With replicated sessions, if one
Tomcat instance crashes, the session state data is not lost because
at least one other Tomcat instance has been sent a copy of that data.
There are many ways that distributed servlet containers can replicate
session data. Some servlet session replication implementations
replicate all sessions to all servlet container instances in the
cluster, whereas other implementations replicate one servlet
container instance's sessions to only one or two
"buddy" servlet container instances
in the cluster. The network protocol over which session data is
replicated also varies. Any replication implementation may offer one
or more of the following protocol choices:
- TCP unicast
This is a reliable protocol, but it generates quite a bit of network
traffic overhead. It's also a one-to-one
communication protocol, which requires sending duplicate network
packet data to each instance that will receive session data.
It's probably the easiest protocol to set up and
run, but the most demanding on network bandwidth resources.
- Unreliable multicast datagram
This protocol has no built-in error correction, delivery guarantee,
or delivery ordering, but it's a one-to-many
protocol that can greatly reduce network traffic. Each instance in
the multicast group receives everything sent to that multicast group
by any group member. Because each Tomcat instance receives all
communication traffic, each server machine's CPU may
become busied with listening in on the group's
chatter.
- Reliable multicast datagram
This is the same as the
unreliable multicast, but with an added reliability layer. There is
no single industry standard for it�every reliable multicast
library implements the algorithm somewhat differently.
Implementations can add data to the multicast packets to keep track
of delivery ordering, delivery priority, delivery acknowledgements,
resend requests, resend replies, etc. The CPU overhead is higher for
this than for unreliable multicast because of the extra layer of code
that handles reliability, and the network utilization is a little
higher as well because of the extra reliability data in the network
packets. But, unlike TCP unicast, this protocol can do one-to-many
communications without duplicating the packets for each server in the
cluster.
Over these protocols, session replicators speak their own
higher-level custom application protocol that is all about exchanging
session data updates. For instance, one kind of message sent from one
Tomcat instance to all other Tomcat instances in the cluster could
mean "I've created a new empty
session numbered 123456," and all of the instances
that receive this message know to duplicate that session in their
JVMs.
Tomcat 4.1 has at least a couple of session replication
implementations. By the time you read this, there might be more
implementations with varying features. Tomcat 5 will come with
session replication code, but it wasn't stable as of
this writing. Ask around to find out the current availability of
these implementations whenever you plan to set it up because your
implementation options may change without notice.
Before you begin working with the session replicator, if
you're going to be using multicast, you must set up
and test the mulitcast to make sure that it works.
10.2.4.3.1 Configuring and testing IP multicast
You cannot assume that multicast will just work. Not all operating
systems support it, neither do some network devices. It will likely
work well on popular Unix-like operating systems, however.
On Solaris, it's probably already set up and working
in a stock installation:
# ifconfig -a
lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
hme0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2
inet 10.1.0.1 netmask ffff0000 broadcast 10.1.255.255
The hme0 ethernet interface shows
MULTICAST on a computer we tested, and it just
worked.
Getting IP multicast working on Linux is a little tougher because it
may require a kernel recompile. To see if your kernel supports
multicast, try this:
# cat /proc/net/dev_mcast
9 eth1 1 0 01005e000001
If the indicated file doesn't exist, you will likely
need to recompile your kernel to support multicast.
It's one kernel option:
CONFIG_IP_MULTICAST. Turn the option on,
recompile, and reboot.
|
Kernel recompilation is well beyond the scope of this book. There are
several excellent O'Reilly Linux texts detailed at
http://linux.oreilly.com.
|
|
If your kernel already supports multicast, then you need to make sure
that multicast is enabled on your network device. Regardless of
whether you're doing multicast over
eth0, eth1, or local loopback
(lo), you must use ifconfig to
enable multicast on that device. To find out if multicast is enabled,
just use ifconfig to examine the settings of the
device:
# ifconfig -a
eth0 Link encap:Ethernet HWaddr 00:10:A4:8E:65:D6
inet addr:10.1.0.1 Bcast:10.1.255.255 Mask:255.255.0.0
UP BROADCAST MTU:1500 Metric:1
RX packets:338825 errors:0 dropped:0 overruns:0 frame:0
TX packets:132580 errors:0 dropped:0 overruns:38 carrier:0
collisions:0 txqueuelen:100
Interrupt:11
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:27174 errors:0 dropped:0 overruns:0 frame:0
TX packets:27174 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
Looking at eth0, we don't see
MULTICAST listed, so we use
ifconfig to enable it:
# ifconfig eth0 multicast
# ifconfig -a
eth0 Link encap:Ethernet HWaddr 00:10:A4:8E:65:D6
inet addr:10.1.0.1 Bcast:10.1.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:338825 errors:0 dropped:0 overruns:0 frame:0
TX packets:132580 errors:0 dropped:0 overruns:38 carrier:0
collisions:0 txqueuelen:100
Interrupt:11
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:27224 errors:0 dropped:0 overruns:0 frame:0
TX packets:27224 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
Now that multicast is enabled, add the IP route for the multicast
class D network. On the multicast-enabled device that you want to
handle the multicast traffic, add a route like this:
# route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
Feel free to change the eth0 on the end to the
device of your choice, but if you change anything else in this
command line, multicast probably won't work.
|
If route complains about the netmask, then
you're probably not adding the route with the
-net option.
|
|
Next,
you should test multicasting. Example 10-1 is a Java
program that you can use to test IP multicast on a single machine or
between two machines on a LAN.
Example 10-1. MulticastNode.java
import java.io.*;
import java.net.*;
/**
* MulticastNode is a very simple program to test multicast. It starts
* up and joins the multicast group 224.0.0.1 on port 12345. It uses the
* first argument as a message to send into the multicast group, and then
* spends the remainder of its time listening for messages from other
* nodes and printing those messages to standard output.
*/
public class MulticastNode {
InetAddress group = null;
MulticastSocket s = null;
/**
* Pass this program a string argument that it should send to the
* multicast group.
*/
public static void main(String[] args) {
if (args.length > 0) {
System.out.println("Sending message: " + args[0]);
// Start up this MulticastNode
MulticastNode node = new MulticastNode( );
// Send the message
node.send(args[0]);
// Listen in on the multicast group, and print all messages
node.receive( );
}
else {
System.out.println("Need an argument string to send.");
System.exit(1);
}
}
/**
* Construct a MulticastNode on group 224.0.0.1 and port 12345.
*/
public MulticastNode( ) {
try {
group = InetAddress.getByName("224.0.0.1");
s = new MulticastSocket(12345);
s.joinGroup(group);
}
catch (Exception e) {
e.printStackTrace( );
}
}
/**
* Send a string message to the multicast group for all to see.
*
* @param msg the message string to send to the multicast group.
*/
public void send(String msg) {
try {
DatagramPacket hi = new DatagramPacket(
msg.getBytes(), msg.length( ), group, 12345);
s.send(hi);
}
catch (Exception e) {
e.printStackTrace( );
}
}
/**
* Loop forever, listening to the multicast group for messages sent
* from other nodes as DatagramPackets. When one comes in, print it
* to standard output, then go back to listening again.
*/
public void receive( ) {
byte[] buf;
// Loop forever
while (true) {
try {
buf = new byte[1000];
DatagramPacket recv = new DatagramPacket(buf, buf.length);
s.receive(recv);
System.out.println("Received: " + new String(buf));
}
catch (Exception e) {
e.printStackTrace( );
}
}
}
}
Compile this class:
$ javac MulticastNode.java
Then run the first node:
$ java MulticastNode NodeOne
Sending message: NodeOne
Received: NodeOne
The "Received: NodeOne" message
indicates that NodeOne is receiving its own
multicast group join message. It will receive everything sent to the
multicast group, including everything it transmits to the group.
In another shell, run the second node:
$ java MulticastNode NodeTwo
Sending message: NodeTwo
Received: NodeTwo
Then look back at the output of NodeOne; it should
look like this once NodeTwo joins
NodeOne's multicast group:
Sending message: NodeOne
Received: NodeOne
Received: NodeTwo
This means that NodeOne received
NodeTwo's join message via IP
multicast! If that works, you should be able to stop
NodeTwo (with a Ctrl-C), and then restart it and
see another "Received: NodeTwo"
message in NodeOne's output. If
all that works, then your OS's multicast is ready to
use.
10.2.4.3.2 Installing, configuring, and testing session replication
Filip
Hanik back-ported his Tomcat 5.0 session replication code to Tomcat
4.1, and that's the implementation
we're using. It provides replication over unreliable
multicast datagram and will soon offer TCP unicast as well.
|
At the time of this writing, the Tomcat 4.1 session replication code
was new and subject to rapid evolution. The specifics about where to
get it, how to configure it, and the features it implements will
likely be different by the time you read this. The following
information is meant to demonstrate the general process of getting
replication running on Tomcat, and specific details may vary.
|
|
You should be able to find the project page for the back-ported
session replicator at http://www.filip.net/tomcat. Navigate to the
Tomcat 4.1 implementation page, which describes the implementation,
offers it for download, and shows how to install and configure it.
Follow the installation and configuration directions, performing them
on each of your Tomcat installations.
Once you have session replication setup and running, try the URL
http://<yoursite>/examples/servlet/SessionExample.
This example allows you to type in session attributes and their
associated values, and then stores the values in your session and
displays the session's contents. You should now be
able to enter session data on one Tomcat instance, shut down that
instance, and request the page again from another Tomcat instance
wihtout losing any of your session data. Figure 10-5 shows the
SessionExample page as served by our
tomcat1 instance after we created the session on
tomcat2, entered a session attribute called
"JasonsTestAttribute", and then
issued a catalina.sh stop command for
tomcat2.
You should be able to stop any single Tomcat instance and still have
access to all active sessions and their data. Your Tomcat cluster is
now tolerant to Tomcat instance faults, as long as at least one
Tomcat instance stays functioning.
10.2.5 JDBC Request Distribution and Failover
Typical relational database
configurations have one database server instance running on one
server computer. Even if all of the other components of the system
are clustered, a single database server instance could crash and
cause the entire site running on the cluster to become unusable. So,
some sort of clustering must also be done for the database in order
for it to not be a single point of failure.
There are relational database servers that support replication but
not parallel use, and some that support both replication and parallel
use.
In the case where the database supports replication but not
parallelization, the database instance that is replicated to becomes
a secondary server to which the cluster could fail over. In this
case, the database driver code (commonly a JDBC driver) would need to
know how to connect to each database instance and when to fail over
to a secondary (replicated) server.
In the case where the database supports parallelization, then the
database driver could load balance across several database server
instances, and detect failures. Here are some products and projects
that might interest you:
- Oracle RAC
One nice commercial parallel relational database server
implementation is Oracle Corporation's
Oracle9i Real Application Clusters (RAC).
See http://www.oracle.com/ip/index.html?rac_home.html
for product information.
- MySQL 4
A popular open source replicated relational database is the
MySQL 4
database server. See http://www.mysql.com/doc/en/Replication.html
for information about how MySQL replication works.
- C-JDBC
An interesting open source project that has set out to make JDBC
clustering available to the masses is
C-JDBC, a JDBC
clustering library by ObjectWeb (http://www.objectweb.org). As of this
writing, the project was just getting started, but by the time you
read this it might be usable. The project's home
page is http://www.objectweb.org/c-jdbc.
|
No comments:
Post a Comment