JCache session persistence
When running applications in production, offering high availability to the end users is important. One aspect of high availability in web applications is failover of non-persistent user session data (e.g. a shopping cart). Currently, Open Liberty offers the sessionDatabase-1.0
feature for persisting HttpSession data into a relational database. However, not all applications may have a database available to them, so a more lightweight solution is needed.
Introducing sessionCache-1.0
Recently we released a new feature in Open Liberty called sessionCache-1.0
which provides distributed in-memory HttpSession caching. The sessionCache-1.0
feature builds on top of an existing technology called JCache (JSR 107), which offers a standardized distributed in-memory caching API. However, even though the feature builds on top of JCache, no direct usage of JCache API is necessary in your application, since Liberty handles the session caching in its HttpSession implementation. In fact, if your application is already using HttpSession caching, it can benefit from sessionCache-1.0
without making any code changes.
Here is a diagram of how the JCache Session Persistence feature works with two Liberty servers:
How to configure session caching
The sessionCache-1.0
feature does not include a JCache implementation, so you need to pick one and reference it as a <library>
in your server.xml
. For development, we have mainly been testing with the open source implementation Hazelcast but here are some JCache implementations that you could use:
-
Hazelcast
-
WebSphere eXtreme Scale
-
Infinispan
-
Ehcache
Ultimately, the sessionCache-1.0
feature should work with anything that complies with the JCache specification.
To configure the JCache Session Persistence feature, include the following configuration in your server.xml
:
<server>
<featureManager>
<feature>sessionCache-1.0</feature>
<feature>servlet-4.0</feature>
</featureManager>
<!-- reference the library containing a JCache implementation -->
<httpSessionCache libraryRef="JCacheLib"/>
<!-- In this example we are using Hazelcast as the JCache implementation -->
<library id="JCacheLib">
<file name="/usr/lib/hazelcast.jar"/>
</library>
</server>
How to use session caching in your application
From an application perspective, using distributed session caching with sessionCache-1.0
works the same way as non-distributed session caching. So if you have applications that are already caching data in HTTP sessions, no code changes should be needed in order to benefit from sessionCache-1.0
. To illustrate the point, here is what HTTP session caching might look like:
@WebServlet("/ExampleServlet")
public class ExampleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
Object dbThing = session.getAttribute("dbThing");
// If object is not found in session, obtain it and cache it for future use
if (dbThing == null) {
dbThing = getFromDB(); // Some expensive operation
session.setAttribute("dbThing", dbThing);
}
}
}
How to join multiple servers together
The sessionCache-1.0
feature is only valuable when it is connected to at least one other member. There are two different ways a Liberty server can behave in a cluster:
-
Client-Server model: A Liberty server can act as the JCache client and connect to a dedicated JCache server.
-
Peer-to-Peer model: A Liberty server can connect with other Liberty servers that are also running with the
sessionCache-1.0
feature and configured to be part of the same cluster.
The following code shows a simple example of how two Liberty servers might share information that has been cached in an HttpSession:
// Running on ServerA
@WebServlet("/ServiceA")
public class ServiceA extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("foo", "bar");
}
}
// Running on ServerB
@WebServlet("/ServiceB")
public class ServiceB extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String result = session.getAttribute("foo"); // will be "bar"
System.out.println("Session attribute foo=" + result);
}
}
Each JCache implementation has its own way of configuring cluster instances. For Hazelcast, a simple configuration file might look like the following example (though you don’t need to specify any Hazelcast configuration file if you are happy with the default Hazelcast configuration):
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.9.xsd"
xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Specifying a group name of 'myCluster' will cause the Hazelcast instance to
only connect with other instances that are also named 'myCluster' -->
<group>
<name>myCluster</name>
<password>super-secret</password>
</group>
</hazelcast>
Then reference the Hazelcast XML configuration file in your server.xml
:
<server>
<featureManager>
<feature>sessionCache-1.0</feature>
<feature>servlet-4.0</feature>
</featureManager>
<!-- point to the Hazelcast configuration file with the 'uri' attribute -->
<httpSessionCache libraryRef="JCacheLib" uri="file:${server.config.dir}/hazelcast-config.xml"/>
<library id="JCacheLib">
<file name="/usr/lib/hazelcast.jar"/>
</library>
</server>
Check the documentation for the implementation you use. So far we have been testing with Hazelcast Core which has some nice auto-discovery capabilities out of the box.
If you want to try out the sessionCache-1.0
feature, download the latest official release of Open Liberty.