Tomcat In-Memory Clustering
Tomcat provides built-in in-memory clustering via SimpleTcpCluster, which replicates sessions between servers in real time. You can implement session sharing through Tomcat configuration alone, without any external storage.
Clustering Architecture
The Tomcat cluster uses multicast or unicast to automatically discover members and replicates session changes to other servers in the cluster whenever they occur.
[App1: 10.0.0.1]
Session A changes
│
├──▶ [App2: 10.0.0.2] Session A replicated
└──▶ [App3: 10.0.0.3] Session A replicated
DeltaManager vs BackupManager
| Feature | DeltaManager | BackupManager |
|---|---|---|
| Replication | All-to-All | Primary + Backup |
| Replication target | All nodes | 1 backup node only |
| Best for | Small scale (2~4 servers) | Medium scale (4+ servers) |
| On failure | Any server can take over | Backup takes over from Primary |
| Memory/Network load | High | Low |
DeltaManager Configuration
Replicates sessions to all servers. Simplest and most reliable.
server.xml (Apply identically to each Tomcat)
<Engine name="Catalina" defaultHost="localhost" jvmRoute="server1">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="10.0.0.1"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpeg;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
<Host name="localhost" appBase="webapps" ...>
</Host>
</Engine>
Tomcat 2 and 3 (change address only)
<!-- Tomcat 2 -->
<Engine jvmRoute="server2">
<Cluster ...>
<Channel>
<Receiver address="10.0.0.2" port="4000" .../>
</Channel>
</Cluster>
</Engine>
web.xml: Declare Distributable (Required)
Add the <distributable/> tag to WEB-INF/web.xml for any web application using clustering:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://jakarta.ee/xml/ns/jakartaee" version="6.0">
<!-- This tag is required to enable session replication -->
<distributable/>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
Unicast Configuration (When Multicast is Blocked)
Multicast is blocked in cloud environments and some networks. Use static unicast membership instead.
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor">
<Member className="org.apache.catalina.tribes.membership.StaticMember"
host="10.0.0.2"
port="4000"
uniqueId="{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}"/>
<Member className="org.apache.catalina.tribes.membership.StaticMember"
host="10.0.0.3"
port="4000"
uniqueId="{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3}"/>
</Interceptor>
<Receiver address="10.0.0.1" port="4000"
className="org.apache.catalina.tribes.transport.nio.NioReceiver"
autoBind="100" selectorTimeout="5000" maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
</Channel>
Session Serialization: Serializable Required
Cluster-to-cluster session replication uses Java serialization. All objects stored in the session must implement java.io.Serializable.
public class UserSession implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long userId;
private String username;
private String role;
private LocalDateTime loginTime;
// Exclude non-serializable fields with transient
private transient HttpSession httpSession;
// Default constructor required for deserialization
public UserSession() {}
// ...
}
Verifying Cluster Operation
# Check cluster member detection in Tomcat logs
grep "McastService" /opt/tomcat/logs/catalina.out
# INFO: Added member [/10.0.0.2:4000]
# INFO: Added member [/10.0.0.3:4000]
# Test session replication
# 1. Login on App1
curl -c cookies.txt -X POST http://app1:8080/app/login \
-d "user=admin&pass=secret"
# 2. Access App2 directly — session should still be valid
curl -b cookies.txt http://app2:8080/app/profile
# 3. Stop App1 and verify session survives
sudo systemctl stop tomcat1
curl -b cookies.txt http://lb.example.com/app/profile
# Should still be logged in because sessions were replicated
Limits of In-Memory Clustering
Replication Load Grows with Server Count
DeltaManager replicates N-1 times for each session change across N servers.
3 servers: 1 session change → 2 replications (manageable)
10 servers: 1 session change → 9 replications (growing burden)
50 servers: 1 session change → 49 replications (severe burden)
Recommendation: Switch to BackupManager or Redis sessions for 4+ servers.
Network Partition Risk
If the network between cluster nodes is temporarily severed, each node operates independently and session data can diverge. Conflicts may occur when the network is restored.
The next page covers Redis-based external session sharing to overcome these limitations.