The purpose of this article is to provide an example of how to set up a basic Tomcat cluster that has session replication, using built-in Tomcat features.
Please note: This example is provided as a courtesy. This configuration is not supported by Liferay Support as it deals with Tomcat, and thus falls under architecture support. This is also not the only way to achieve session replication with Tomcat; other methods leveraging third-party distributed caching solutions (e.g. memcached) are also available.
For true session replication, there must be a load balancer that redirects the traffic to the live nodes. This article does not provide an example of how to set up a load balancer. For an example of to set up a load balancer, please refer to the load balancer vendor's documentation (e.g. Apache, F5).
This article does not cover Liferay clustering, which includes distributed caching or index replication, which are necessary for Liferay itself to work properly in a clustered environment. Please refer to the article: Installing Liferay DXP in a Clustered Environment.
Make sure that all nodes have the same time and sync with a Network Time Protocol (NTP) service.
Resolution
The following instructions will guide through the proper setup protocol.
- In
${TOMCAT_HOME}/conf/server.xmladd thejvmRoutevalue to the Engine section.It will look something like this:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="worker1">
To clarify,
worker1is the name assigned to it, and can be any alphanumeric value; for example: [a-z][A-Z][0-9][_\-]If the Tomcat instances are running on the same machine, make sure the
tcpListenPortattribute is unique for each instance. In most cases Tomcat is smart enough to resolve this on its own by auto-detecting available ports in the range 4000-4100. This is set in theserver.xml. - Replace
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" />with the following lines in the Engine:<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="auto"
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=""/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster> - In
${APACHE_HOME}/conf/workers.properties, add in the worker information.It should look something like this:
worker.list=balancer worker.worker1.port=8009 worker.worker1.host=${WORKER1_IP_ADDRESS/DOMAIN} worker.worker1.type=ajp13 worker.worker1.lbfactor=1 worker.worker2.port=8009 worker.worker2.host=${WORKER2_IP_ADDRESS/DOMAIN} worker.worker2.type=ajp13 worker.worker2.lbfactor=1 worker.balancer.type=lb worker.balancer.balance_workers=worker1,worker2 worker.loadbalancer.sticky_session=1 worker.balancer.method=BPlease note the use of
worker1in the names. This is the same value as thejvmRoutevalue set in the first step. As stated previously, this value can be any alphanumeric value but must remain consistent throughout the configuration.If there are going to be more than 2 nodes, then create additional entries with the appropriate values, like
worker3,worker4, etc... - In the
portal-ext.propertiesfile of the Liferay bundle, add the following:cluster.link.enabled=true redirect.url.security.mode=domain web.server.display.node=true
Please note: The second property will allow things like AUI buttons to function with the Apache Server. The third property will make the node IDs visible as footers. These two properties are independent of session replication. Liferay Support assistance with further session replication configuration is limited.
- Repeat the steps for the second node and all other nodes. Set the same database connections such that all nodes point to the same database. The choice of database is up to the user and Liferay Support can give only basic assistance in this matter.
- Start servers sequentially. Cluster nodes cannot be started simultaneously because the process takes time to determine which node is the master node.
- Start the load balancer Web Server.
- Access the Web Server's IP Address or Domain Name. The web server will redirect the request to one node. Create a page, a user, or an asset.
- Shut down one node. Verify that the traffic has redirected automatically to the second node, and that the page, user, and asset appear on the second node.
Notes
- Session state is tracked by a cookie, so the URL must look the same from the outside, otherwise a new session will be created.
- All session attributes must implement
java.io.Serializable - If there are custom cluster valves defined, make sure the ReplicationValve is defined as well under the Cluster element in
server.xml - The Cluster module uses the Tomcat JULI logging framework, so logging can be configured through the regular
logging.propertiesfile. To track messages, enable logging on the key:org.apache.catalina.tribes.MESSAGES - The property
<distributable />has been deprecated in Apache Tomcat 8.x onwards. It is no longer necessary to add this to the Manager element ofconf/web.xml. You only need to add this to the Context element in WEB-INF/web.xml.