This website uses cookies to ensure you get the best experience. Learn More.
Tomcat Session Replication with Redis in 7.4
Things have changed in 7.4 since the previous post was written. While all the explanation regarding Redis is still valid, classloader configuration is a bit different in Liferay 7.4. Anyway we'll perform a similar introduction. This way if someone directly lands in his blog he/she can find everything self-contained.
Redis is an in-memory store that can be used to provide a central and external place to save the application session information. It can be very useful in cloud environments or to handle node crashes without losing session information.
Redisson appears as an alternative in order to provide integration between Redis and Tomcat:
It has some advantages like writing only the modified attribute instead of serializing the whole session each time. You have more information in Redisson Tomcat.
The following steps are needed for a basic installation:
<Manager className="org.redisson.tomcat.RedissonSessionManager" configPath="${catalina.base}/redisson.conf" readMode="REDIS" updateMode="DEFAULT" broadcastSessionEvents="false"/>
{ "singleServerConfig":{ "address": "redis://127.0.0.1:6379" }, "threads":0, "nettyThreads":0, "transportMode":"NIO" }
When starting the portal and perform a log in with any user you'll get a ClassNotFoundException like the following one:
Caused by: java.io.IOException: java.lang .ClassNotFoundException: com.liferay.portlet.PortalPreferencesImpl cannot be found by com.liferay.product.navigation.user.personal.bar.web_6.0.13 at org.redisson.codec.MarshallingCodec.lambda$new$0(MarshallingCodec.java:148) ~[redisson-all-3.18.0.jar:3.18.0] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:383) ~[redisson-all-3.18.0.jar:3.18.0] at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:198) ~[redisson-all-3.18.0.jar:3.18.0] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:137) ~[redisson-all-3.18.0.jar:3.18.0] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:113) ~[redisson-all-3.18.0.jar:3.18.0] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:519) ~[redisson-all-3.18.0.jar:3.18.0] at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366) ~[redisson-all-3.18.0.jar:3.18.0]
Because Liferay usually programs to an interface not to the implementation the attribute usually will be retrieved and assigned to an interface. So, from the module's point of view there is no need to know how to "reach" the implementation object classloader.
This will cause that the generated MANIFEST.MF for the module (in this case com.liferay.product.navigation.user.personal.bar.web) will only contain Import-Package directives pointing to the interface package, not to the implementation. This is:
This will be resolved by LiferayRedissonSessionManagerHelper (will talk about it later) saving the context name of the object implementation module classloader during the serialization process. Afterwards, during the deserialization, the classloader can be retrieved from the ClassLoaderPool using that saved context name.
In previous versions files like portal-kernel.jar were deployed in $TOMCAT_HOME/lib/ext folder. This made all these libraries available to each Tomcat deployed application, or even to Tomcat configuration itself, since they were part of the Tomcat classloader. This has completely changed in 7.4 with the aim of having an even more OSGi oriented architecture. More information can be found in Liferay Classloader Hierarchy.
Now the shielded container takes care of making these libraries available to the different modules, but not to outside applications.
Shielded container related stuff can be found in a couple of directories:
This would normally not affect your own developments or your infrastructure configuration. At much you should consider making the database drivers available globally moving them to the Tomcat lib, just in case you need to share them between applications.
So, at this point, you only need to remember that Liferay non OSGi application jars are no longer deployed in $TOMCAT_HOME/lib/ext. That makes them not shared globally. The only Liferay classes that DXP web application interacts with are Liferay’s Shielded Container JAR files: com.liferay.shielded.container.api.jar, com.liferay.shielded.container.impl.jar
Previous solution was based in LiferayRedissonSessionManager. Adding it as a manager in context.xml or server.xml files made it possible to handle serialization/deserialization between Liferay and Tomcat.
Unfortunately Liferay classes needed by LiferayRedissonSessionManager aren't visible anymore from the Tomcat lib classloader. And because the LiferayRedissonSessionManager is configured through Tomcat configuration Liferay classes used by the manager aren't accessible.
So, somehow, the new idea is oriented towards the need to coordinate Tomcat and Liferay communication decoupling, as much as possible, Liferay classloader code from Tomcat Redisson integration code.
The idea is to let Redisson handle how to save/retrieve data from Redis letting Liferay manage the serialization/deserialization process since Liferay knows how to reach each module appropriate classloader.
All code can be downloaded from Liferay Session Replication with Redis in 7.4.
Next steps are needed to make the integration work:
$TOMCAT_HOME/conf/Catalina/localhost/ROOT.xml
<Manager className="com.liferay.redis.redisson.integration.tomcat.LiferayDelegatedRedissonSessionManager" configPath="${catalina.base}/redisson.conf" readMode="REDIS" updateMode="DEFAULT" broadcastSessionEvents="false" broadcastSessionUpdates="false"/>
$CATALINA_BASE/redisson.conf
$TOMCAT_HOME/webapps/ROOT/WEB-INF/shielded-container-lib
$TOMCAT_HOME/lib
If you want to avoid annoying Redisson INFO traces like the following ones:
28-Nov-2022 15:49:04.702 INFO [http-nio-8080-exec-6] org.redisson.tomcat.RedissonSessionManager.findSession Session 8040B36EC63A98DCDC21865401E1FF1E can't be found 28-Nov-2022 15:49:39.180 INFO [http-nio-8080-exec-2] org.redisson.tomcat.RedissonSessionManager.findSession Session B0D46572F74B0BD4CE9DE0E9552BD0CD can't be found 28-Nov-2022 15:49:39.196 INFO [http-nio-8080-exec-2] org.redisson.tomcat.RedissonSessionManager.findSession Session B0D46572F74B0BD4CE9DE0E9552BD0CD can't be found 28-Nov-2022 15:49:39.214 INFO [http-nio-8080-exec-2] org.redisson.tomcat.RedissonSessionManager.findSession Session B0D46572F74B0BD4CE9DE0E9552BD0CD can't be found 28-Nov-2022 15:49:39.299 INFO [http-nio-8080-exec-9] org.redisson.tomcat.RedissonSessionManager.findSession Session B0D46572F74B0BD4CE9DE0E9552BD0CD can't be found 28-Nov-2022 15:49:39.299 INFO [http-nio-8080-exec-9] org.redisson.tomcat.RedissonSessionManager.findSession Session B0D46572F74B0BD4CE9DE0E9552BD0CD can't be found
You can configure your Tomcat logging to display only WARNING level traces in $TOMCAT_HOME/conf/logging.properties
$TOMCAT_HOME/conf/logging.properties
org.redisson.tomcat.level=WARNING