Session Replication in Liferay DXP 7.4 with JBoss EAP 7.4.0

JBoss Clustering and Replication

The following Pre-requisites are required before enabling session Replication:

  1. Working Liferay with JBoss bundle (Reference Link)
  2. Liferay Clustering Enabled                  (Reference Link)

Session Replication Overview

Session replication ensures that client sessions of distributable applications are not disrupted by failovers of nodes in a cluster. Each node in the cluster shares information about ongoing sessions and can take over sessions if a node disappears.

Session replication is the mechanism by which mod_cluster, mod_jk, mod_proxy, ISAPI, and NSAPI clusters provide high availability.

(More information regarding JBoss Session Replication can be found here )

We will be covering the below points:

  1. Making Liferay DXP distributable
  2. Enabling Clustering in JBoss App Server 
  3. Adding Outbound socket to configure with Web Server (Optional)
  4. Session Replication Validation

Note: All the above points from 1 - 4 shall be followed in both the nodes

Making Liferay DXP Distributable:

  • Add the <distributable/> element just before the </web-app> inside $JBoss_Home/standalone/deployments/ROOT.war/WEB-INF/web.xml
  • Open $Liferay_Home/portal-ext.properties and add the below property
    portlet.session.replicate.enabled=true

Enabling Clustering in JBoss App Server:

For Clustering/HA JBoss Documentation suggests using standalone-ha.xml/standalone-full-ha.xml. We will be using standalone-full-ha.xml because it includes support for every possible subsystem, including those required for high availability. Also, it contains all the interfaces which are required for clustering and session replication. JBoss uses multicast, mod cluster, and UDP/TCP protocol for internode communications.

  • Open $JBoss_Home/standalone/configuration/standalone-full-ha.xml file and find the following tag 
    <cache-container name="web" default-cache="dist" modules="org.wildfly.clustering.web.infinispan">
    Inside the above tag find the following tag <distributed-cache name="dist"> .Comment the sub-tags mentioned inside this tag 
                        <!-- <locking isolation="REPEATABLE_READ"/> -->
                        <!-- <transaction mode="BATCH"/> --> 
    (This is a known issue in JBoss and can be referred here)
     
  • In standalone-full-ha.xml find the following tag: 
    <subsystem xmlns="urn:jboss:domain:webservices:2.0" statistics-enabled="${wildfly.webservices.statistics-enabled:${wildfly.statistics-enabled:false}}">

    Inside this tag, there will be a sub-tag
    <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
    Replace 127.0.0.1 with the current Node Liferay Server Internal IP Address
     
  • In standalone-full-ha.xml find the below tags, and change the IP address from 127.0.0.1 to the current Node Liferay Server Internal IP Address  
     <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
    <inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
    <inet-address value="${jboss.bind.address:127.0.0.1}"/>
    <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/>

    inet address bounds the Application server to the specified IP Address so that it can be accessed/referred via http://IPAddress:8080 instead of http://localhost:8080
     
  • Open $JBoss_Home/bin/standalone.conf.bat (for Linux open standalone.conf.sh) and add the below jvm property.
    -Djboss.server.default.config=standalone-full-ha.xml

    By default, when a JBoss server starts, it loads standalone.xml file as it configurations. But, to load standalone-full-ha.xml instead of default we added the above property (another way would be specifying standalone-full-ha.xml at runtime like ./standalone.sh -c standalone-full-ha.xml

Adding Outbound socket to configure with Web Server (Optional):

The following steps are basic and can be amended as per the real-time requirements. We have used the basic setup of JBoss with JBCS HTTPD server with mod_cluster setup. You can use the Apache HTTPD web server, etc with mod_cluster setup, and can configure a similar kind of setup.

  • Open standalone-full-ha.xml and find the following tag 

    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">

    Just before the closing of the above tag i.e. </socket-binding-group> add the outbound socket, so that the App server is able to recognize the Frontend Server.
     <outbound-socket-binding name="lb1">
                <remote-destination host="x.x.x.x" port="80"/>
    </outbound-socket-binding>

    where x.x.x.x is the Web server IP and 80 is the port on which it is Running. (You can change to 443 or another port as per the Web server Setup)

     

  • Now find the following tag <proxy name="default" advertise-socket="modcluster" listener="ajp"> in standalone-full-ha.xml and add the following attribute to the above tag proxies="lb1"

    Final tag will look like this: <proxy name="default" advertise-socket="modcluster" listener="ajp" proxies="lb1">

    Make sure the proxies="value" is the same as the name attribute mentioned in the outbound socket in the previous step. 

     

  • Below is a sample Virtual Host setting done in httpd.conf which is configured on the Web server.
    Listen x.x.x.x:80
    <VirtualHost x.x.x.x:80>  
          <Location />
              Order deny,allow
              Require all granted
              Allow from tomcat
          </Location>
          KeepAliveTimeout 60
          MaxKeepAliveRequests 0
          EnableMCPMReceive On
          ManagerBalancerName lb1
          ServerAdvertise On
    </VirtualHost>

    Note: Above settings are basic/generic, feel free to do changes as per the Web Server Admin's suggestions.

Session Replication Validation:

Once all the above changes are in place, we can now start both the nodes and web server to validate the Session replication behavior.

  • To Start JBoss run the following command in the terminal, or you can prepare a script/batch file to decrease the overheads :) 

              For Windows:
              standalone.bat -u 230.0.0.4 -Djboss.messaging.cluster.password=*****

              For Linux:
              ./standalone.sh -u 230.0.0.4 -Djboss.messaging.cluster.password=*****
             (Remember to make standalone.sh as executable if it is not already)

            where 230.0.0.4 is the default multicast address (refer standalone-full-ha.xml)

  • Once the servers are started, Login into Portal and post login note down the JSESSIONID from Application Tab in Browser "inspect element" window.
    (Now the concept for session replication here will be that if one of the nodes goes down then the Session must be passed on to the current UP node and user shall not face any issue viz. Logged out, etc). 

    For Example:

    In snapshot 1, you can see the JSESSIONID which at the end has ".shubhpc", this shubhpc refers to the JBoss second node. So, currently my session is on Node2. 


    Now, after shutting down this node abruptly (Node2 also named "shubhpc" ) my current session shall be transferred to another node with the same JSESSIONID but only change in node name (i.e. another running node)

    (here desktop-ctq5ko3 is my Current Node to which the same session is passed on)



    NOTE: When specifying the -DJboss.node.name/jvmRoute property in standalone.conf and/or in standalone-full-ha.xml explicitly, the session replication won't work hence, it is better to use them without bounding each node to a specified node name.

There may be ample ways to configure Session Replication, the above is one of them

If you are getting error like the following: 

Caused by: java.lang.IllegalArgumentException
'exmapleBean' attribute with type 'com.demo.portlet.example.' cannot be replicated
at org.jboss.as.web.session.ClusteredSession.setAttribute(ClusteredSession.java:824)
at org.apache.catalina.session.StandardSessionFacade.setAttribute(StandardSessionFacade.java:130)
at com.liferay.portlet.PortletSessionImpl.setAttribute(PortletSessionImpl.java:200)


Make sure all session objects and their attributes/variables are made Serializable.