Blogs
JBoss Clustering and Replication
The following Pre-requisites are required before enabling session Replication:
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:
- Making Liferay DXP distributable
- Enabling Clustering in JBoss App Server
- Adding Outbound socket to configure with Web Server (Optional)
- 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.