Skip to main content

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

FeatureDeltaManagerBackupManager
ReplicationAll-to-AllPrimary + Backup
Replication targetAll nodes1 backup node only
Best forSmall scale (2~4 servers)Medium scale (4+ servers)
On failureAny server can take overBackup takes over from Primary
Memory/Network loadHighLow

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.