My Profile Photo

Ionut Gavrilut


DevOps Enthusiast | Linux System Administrator | Certified Jenkins Engineer


Hybris with Tomcat Session Replication and Failover

This was tested on a 6.7 Hybris Commerce cluster setup, with b2c_acc_plus recipe.

Prerequisites:

  • Two Hybris installed (Recommended on two different machines. For Windows, Tomcat clustering doesn’t work when the nodes are on the same machine)
  • Load Balancer (Optional, for test. If you have it, make sure it has sticky session enabled)
  • EditThisCookie extension for Chrome (For testing purposes)

What need to be configured:

  1. Hybris cluster
  2. Tomcat cluster (with replication)
  3. Session Failover (with sync)
  4. Enable Session Manager

1. Hybris Cluster

These properties are set in local.properties

#Cluster
clustermode=true
cluster.id=0
# enable the new method by name
cluster.broadcast.methods=unicast
# define server host name or ip ( use a public ip here)
cluster.broadcast.method.unicast.serveraddress=1.2.3.4
# define the server port
cluster.broadcast.method.unicast.port=54321
# define all known nodes as hostnameOrIp:port
cluster.broadcast.method.unicast.clusternodes=1.2.3.4:54321;1.2.3.5:54321
#1 the interval value is higher than 0 , the platform synchronizes its list of known nodes with all the cluster members,
#negative values mean that the service is disabled
cluster.broadcast.method.unicast.sync.nodes.interval=-1

Please change cluster.id, serveraddress and clusternodes properties with your values.

2. Tomcat Cluster

It is a simple multicast, on 4000 port, where Tomcat nodes discover each other. The replication is done with DeltaManager; means that replicates the deltas in data. DeltaManager works well with small clusters. For wider clusters, please research about Tomcat replication with BackupManager.

Cluster Manager is set in config/tomcat/conf/server.xml, in 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"/>
 
    <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

You don’t have to change nothing here, maybe addresses (if getAddress doesn’t work properly with ‘auto’, you can update with the private IP), or dropTime (for a slow network).

3. Session Failover

This means that every session is stored in database, for high availability. You need to enable it globally and then for each extension.

These properties are set in local.properties.

#Enabling Session Failover for an Extension
spring.session.enabled=true
spring.session.yacceleratorstorefront.save=sync
spring.session.yacceleratorstorefront.cookie.name=JSESSIONID
spring.session.yacceleratorstorefront.cookie.path=/shop
 
spring.session.hac.save=sync
spring.session.hac.cookie.name=JSESSIONID
spring.session.hac.cookie.path=/admin
 
spring.session.backoffice.save=sync
spring.session.backoffice.cookie.name=JSESSIONID
spring.session.backoffice.cookie.path=/backoffice
 
#Enabling Session Serialization Checking (Disable for Production!)
session.serialization.check=true
session.serialization.check.extensions=hac,backoffice,yacceleratorstorefront

You need to change your extensions here. For custom extensions, make sure that everthing you put in the session, is serializable.

Before 4th step, you should build the platform to update /opt/hybris/bin/platform/tomcat/conf/server.xml

4. Session Manager

Enable Session Manager for all extensions you want replication. In /opt/hybris/bin/platform/tomcat/conf/server.xml, replace Manager pathname=”” with this:

<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" />

Configuration files from bin/platform are overwritten by files from config/ directory, after build, so make sure you update this Manager before starting Hybris server.

/opt/hybris/config/tomcat/conf/server.xml overwrites /opt/hybris/bin/platform/tomcat/conf/server.xml

Cluster testing

You can test it with a load balancer (make sure it has sticky sessions enabled) Or, you can manipulate your cookies in browser, changing the JSESSIONID cookie. Steps:

  • Go to https://your-first-node:9002/backoffice
  • Login with your credentials
  • Save your JSESSIONID (Simplest way to find this cookie is to press the cookie button, provided by EditThisCookie extension)
  • Open a new browser tab, go to https://your-second-node:9002/backoffice
  • Change your JSESSIONID from second node with the first one (that you saved from first node)
  • Refresh the page and you should be logged in.

Do not test storefront session replication with this method because you will be soft logged in, and will require a new HardLogin. Test storefront with a load balancer, to have the same URL.