Not every Java application can be made stateless before it needs to be highly available. Many keep real state in the HTTP session, a basket, a wizard's progress, a logged-in user, and the team has no budget to move that to Redis this quarter. Tomcat's own clustering was built for this case, and this post follows a DevOps engineer using it on MassiveGRID PaaS, which is built on Virtuozzo Application Platform, formerly Jelastic, with the Tomcat/TomEE Cluster package.
The application is a ticket-sales web app for a regional theatre group we will call Lanternhouse Theatres: a classic servlet application with a seat-selection basket in the session. The Tomcat/TomEE Cluster with High Availability deploys two or more Tomcat or TomEE nodes with session replication behind an NGINX load balancer, with auto-scaling triggers already configured.
What session replication buys you
In a plain load-balanced Tomcat pair, a user's session lives on the node that created it. Sticky sessions keep the user there, but if that node fails, the session is gone and the basket empties. Tomcat clustering adds a session replication channel between the nodes: each session change is broadcast to the other nodes over the environment's internal network, so every node holds a copy. If a node fails, the balancer sends the user to another node, which already has the session. The package enables Tomcat's clustering configuration and the replication channel on every node, including nodes added later by scaling.
The prerequisite is that everything stored in the session is serialisable, since replication serialises it. Lanternhouse's basket objects were, after one class gained implements Serializable, which the engineer found on a cloned environment rather than in production.
Sticky sessions plus replication, not one or the other
The balancer still uses sticky sessions: a user's requests go to the same node while it is healthy. This is not a contradiction. Stickiness keeps replication cheap, because a session changes on one node and is copied to the others, rather than being fought over. Replication is the insurance for when stickiness cannot be honoured. The NGINX balancer in the package is configured for both, with health checks that drop a failed node within seconds.
Testing the failure on purpose
Before go-live the engineer clones the environment, opens the ticket app on the clone, fills a basket, and stops the node his session is on from the dashboard. He reloads: the balancer routes to the surviving node, the basket is intact, and the page renders. The platform then restores the stopped container; it rejoins the cluster and starts receiving new sessions. The whole test takes ten minutes and the clone costs cents. He repeats it with three nodes and then with the balancer, since the balancer itself is a platform container on its own host that the platform will restore, but a second balancer node with a shared public IP is available for environments that want it.
| Event | Without replication | With the cluster package |
|---|---|---|
| Node fails mid-purchase | Basket lost, user logged out | Next request served by another node with the same session |
| Node added by scaling | Only new sessions land on it | Receives replicated sessions and new ones |
| Deploy to the layer | All sessions lost per node | Sequential deploy; sessions survive on other nodes |
| Balancer health check fails a node | Users on it lose sessions | Routed elsewhere, sessions intact |
Scaling for the on-sale
Ticket sales open at 10:00 on announcement days and traffic is fifty times a normal hour for twenty minutes. The package's auto-scaling triggers add Tomcat nodes on CPU load and remove them afterwards; the engineer tunes them to add two nodes at 60% CPU over one minute, up to eight, and pre-scales to four at 09:50 for announced on-sales. Replication traffic grows with node count, because each session change is sent to every node, so the engineer's rule is that this topology is right up to a handful of nodes. Beyond that, the honest answer is to move sessions to Redis, which the same balancer supports and which is the plan for next year.
Deploying without emptying baskets
WAR deployments through the Deployment Manager go to every node, sequentially: one node is drained from the balancer, redeployed, restarted, then the next. Sessions on the node being restarted are already replicated to the others, so users are served elsewhere and come back with their basket. The theatre group's marketing team can now push a homepage change on an on-sale morning, which they were previously forbidden from doing.
Cost and the alternative
One configuration detail saved a support ticket: the balancer's session cookie name and Tomcat's must agree, and the JVM route suffix that identifies a node must be set per node, which the package does. When the engineer added a node by hand on the clone without it, stickiness silently broke; the package's scaling does it correctly, and the manual case is now a note in the runbook.
Two Tomcat nodes most of the day at about 10 cloudlets each (a cloudlet is 128 MiB of RAM plus 400 MHz of CPU), a small balancer, and a MariaDB node, average roughly 30 cloudlets an hour, or about $73 a month before discounts at MassiveGRID's published $0.003372 per cloudlet-hour; on-sale mornings add a few dollars each. The alternative the group had been quoted was a rewrite to externalise sessions before they could have a second server at all. The cluster package let them have the second server this month and schedule the rewrite for when it is convenient.
Frequently Asked Questions
Tomcat or TomEE?
Tomcat is the servlet container; TomEE is Tomcat plus the Jakarta EE Web Profile (CDI, JPA, EJB Lite, JAX-RS). Choose TomEE if your application uses those APIs; choose Tomcat for plain servlet or Spring applications. The package offers both with the same clustering.
Does session replication slow the application down?
Slightly: each session change is serialised and sent to the other nodes over the internal network. Keep sessions small (identifiers, not whole objects) and the overhead is negligible for a handful of nodes. Very large sessions or many nodes are the signal to move sessions to Redis.
Can I run Spring Boot in this cluster?
As a WAR deployed to Tomcat, yes. Executable JARs are better served by the Spring Boot Cluster package on Java Engine nodes.
A second server without a rewrite
The Tomcat/TomEE Cluster with High Availability replicates HTTP sessions between nodes behind an NGINX balancer on MassiveGRID PaaS, scales on load and deploys sequentially. Per cloudlet-hour, 100% uptime SLA. Free 14-day trial.
Tomcat/TomEE Cluster on MassiveGRID PaaS