Hi,
When I use inetd superserver in the unix environment, I can upgrade
the launched server program by replacing the inode with "mv" command.
This is an atomic operation. The listener socket is kept by the inetd
process so that "Connection refused" will not occur.
How do I accomplish the same action in a Java server program? The
target is vanilla tcp/udp servers, so Web Application containers are
not enough. Is there any appropriate framework or library?
--
Hiroki Sakagami
Oliver Wong - 07 Jun 2006 17:19 GMT
> Hi,
>
[quoted text clipped - 6 lines]
> target is vanilla tcp/udp servers, so Web Application containers are
> not enough. Is there any appropriate framework or library?
To clarify, you want to know of a design pattern, technique, API, or
some other mechanism to do the following:
Allow your Java application, which acts as a server, to be upgraded
while it is running, and without ever emitting a connection refused to any
clients trying to connect. I.e. you want zero downtime due to software
upgrades.
If so, I don't know of any tutorial or online recipe you can follow. I
think the general strategy is to use a fancy class loader so that you can
have two versions of your server loaded into memory at once. All newly
connecting clients will connect to the new server, while your old clients
will remain connected to your old server. As the old clients disconnect,
eventually, the old server will become idle, at which point it can be killed
off completely.
I'm guessing that the part of your code which actually waits on a socket
for a connection cannot be hotswapped this way, or else you risk a (perhaps
only a few millisecond wide) window during which connections may be refused.
Instead, you could only hotswap the logic that handles the connections once
they're made, perhaps via some sort of factory method which uses whatever
the latest version of the code is available, according to your custom class
loader.
- Oliver
Martin Gregorie - 07 Jun 2006 17:23 GMT
> When I use inetd superserver in the unix environment, I can upgrade
> the launched server program by replacing the inode with "mv" command.
> This is an atomic operation. The listener socket is kept by the inetd
> process so that "Connection refused" will not occur.
I think you'll find that mv updates the inode to point to your new image
file but the original server image continues to run: its copy of the
image file is preserved until it terminates in just the same way as:
$ myapp >afile &
$ rm afile
doesn't delete 'afile" until 'myapp' has terminated.
xinetd continues to listen to the same port after your mv operation, but
it handed off the connection to your server when it forked it and it
takes no more notice of that connection unless you've set "wait=yes".
The next incoming connection will cause xinetd to fork a copy of the
server from your new image file so, if the old server was still running
when the new connection request was fielded by xinetd, you'll have the
old server version running alongside the new version.
> How do I accomplish the same action in a Java server program?
by using xinetd to run your Java server, which should accept input from
stdin and send responses to stdout.
> The target is vanilla tcp/udp servers, so Web Application containers are
> not enough. Is there any appropriate framework or library?
Not that I know of, but its not difficult to implement. Try this:
- Start your server at boot time using the normal mechanism of a
script in /etc/rc.d/init.d. This is made known to the boot-time
system via the chkconfig command
- control and monitor its status in the usual way via the 'service'
command and/or changing the runlevel
- extend your server's controlling script to accept an 'upgrade'
argument which carries out the mv. Then you can switch versions
via the commands:
service myserver upgrade new_version
service myserver restart
You should keep the mv separate from 'restart' or the system admins
will be confused when 'restart' doesn't do exactly what its
expected to do.
Of course, if you want your old server to stay alive until its last
connection is closed while the new version picks up all new connection
requests you'll need to add code to the server. This would accept a
command to switch its state into a closedown mode. In closedown mode it
to should close its listener socket immediately, so the new copy of the
server can use it, and terminate when its last client connection is
closed. Using a small command line client program to issue the state
switch request via a socket connection is probably the easiest way to do
it for a multi threaded Java server (if it was a C server I'd consider
using a signal). You'd need to run the client from the control script in
response to the 'restart' argument instead of using the code connected
with the 'stop' argument.
If your Linux or SVR4 UNIX doesn't implement the chkconfig and service
commands then use its equivalents. These commands are correct for Fedora
Core 4.

Signature
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |