Sunday, October 25, 2009

10.2 The Communication Sequence of an HTTP Request








 

 












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.







Figure 10-1. How one HTTP request uses a typical nonclustered server






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.









  1. 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.



  2. 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.



  3. Local DNS response. The local DNS server replies, giving the browser

    the IP address of the Apache httpd web server.



  4. 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.



  5. 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.



  6. mod_jk2 forwards all requests on to Tomcat.



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







Figure 10-2. A request through 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.







Figure 10-3. A TCP NAT request distributor distributing an HTTP request






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.







Figure 10-4. The mod_jk2 /jkstatus page displaying statistics about two Tomcats










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.







Figure 10-5. Viewing session data from a replicated session






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