Java web apps can be efficient because they are multithreaded and you only need to run one copy of the process to serve multiple conconcurrent requests.
This is in constrast to Ruby apps where you often need multiple processes to serve multiple requests. Using one process instead of ~8 will save you a lot of memory on the system.
The downside of one process is dealing with rolling restarts. In the case of Ruby app servers like Unicorn, multiple processes are ran and thus can be setup to provide rolling restarts.
If you are using a web container such as Tomcat 7, it can support hot reload in place.
But let’s assume your Java JVM web app is ran with a single command(e.g. java -jar backend-1.0.jar &). The idea of this setup is that it can be abstract to any single process web service.
To get rolling restarts out of this setup, we can use capistrano with haproxy.
We want to:
* start two difference servers with one process each(or use two processes on one server, this won’t provide failover though)
* use an haproxy as a load balancer to these servers
In your Java web service apps, add a health check endpoint(/haproxy-bdh3t.txt) and have it serve an empty text file.
[It's important to use a random string as your endpoint if you are running in the public cloud since the load balancer could be referencing an old server address and haproxy could think a server is up but isn't. ]
In your haproxy.cfg, add
option httpchk HEAD /haproxy-bdh3t.txt HTTP/1.0
as your check condition to the backend services.
In your capistrano script, let’s add two servers set as the app role
server "XXX1", :app
server "XXX2", :app
and alter the restart task to:
* remove the check file for one server. This will remove the server from the load balancer
* restart server.
* ping the server.
* add the check file back to the started server which haproxy will add back into the load balancer.
* repeat as a loop for each server.
desc "Restart"
task :restart, :roles => :web do
haproxy_health_file = "#{current_path}/path-static-files-dir/haproxy-bdh3t.txt"
# Restart each host serially
self.roles[:app].each do |host|
# take out the app from the load balancer
run "rm #{haproxy_health_file}", :hosts => host
# let existing connections finish
sleep(5)
# restart the app using upstart
run "sudo restart backend_server", :hosts => host
# give it sometime to startup
sleep(5)
# add the check file back to readd the server to the load balancer
run "touch #{haproxy_health_file}", :hosts => host
end
end