Session storage in Tomcat

Knowing what is under the hood of your car, simplifies always its reparation. In this article we'll focus on session management in Tomcat to better debug our applications in the future.

Looking for a better data engineering position and skills?

You have been working as a data engineer but feel stuck? You don't have any new challenges and are still writing the same jobs all over again? You have now different options. You can try to look for a new job, now or later, or learn from the others! "Become a Better Data Engineer" initiative is one of these places where you can find online learning resources where the theory meets the practice. They will help you prepare maybe for the next job, or at least, improve your current skillset without looking for something else.

👉 I'm interested in improving my data engineering skillset

See you there, Bartosz

The article will be divided on some parts. Each part will be a response for a question posed in the part's title. We'll start by sessions lifecycle and possible storage places. After that we'll approach a interesting point on Tomcat architecture, session restoring after server restart. At the end we are talking about some Java classes used to handle sessions by Tomcat.

What is session lifecycle in Tomcat ?

Session in Java's API Servlet is represented by implementations of javax.servlet.http.HttpSession interface. It's accessible from HttpServletRequest methods getSession() or getSession(boolean create). According to chosen method, the method's invocation will cause one of following scenarios :
- retrieve current session associated with the user (session must exist before the invocation)
- create new session (if the session doesn't exist and we user getSession() method without parameter or with the parameter create equals to true)
- don't do nothing (session doesn't exist and we invoke getSession(false) method)

OK, we know already that a session is associated with current request and can be retrieved thanks to 2 different methods. Let's suppose that we retrieved needed session object. Now we can put some data into (methods putValue() or setAttribute()), get some data from (getValue()) or remove some data (removeValue() or removeAttribute()). Please note that in version 2.2 of API Servlets, value vocabulary was replaced by attribute. It's the reason why we dispose 2 methods to set or remove session informations.

Session is associated with the request and can persist through multiple requests thanks to session id. This id allows Tomcat to retrieve session corresponding to user. However, the persistence can be interrupted in three ways :
- session timeout : when session is not used during some time (30 minutes by default for Tomcat).
- server fails : when server is down, session can potentially be lost (to know more, see directly session restoring part).
- explicit session invalidation : by calling HttpSession method invalidate(), we can invalidate whole session explicitly.

All sessions are created and maintained by session manager that we specify in Tomcat's configuration file (<Manager /> element inside <Context />). The standard base implementation of session manager is org.apache.catalina.session.StandardManager. It supports session persistence across Tomcat's restarts which will be explained in the third paragraph. It handles session in ConcurrentHashMap, like this protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>(). Inside the session manager we can find some another configuration, as:
- sessions timeout (protected int maxInactiveInterval = 30 * 60)
- sessions security aspects as random algorithm (protected String secureRandomAlgorithm = "SHA1PRNG") or generator of sessions ids (protected SessionIdGenerator sessionIdGenerator = null)
- sessions stats (number of rejected sessions, number of failed session initializations)

Where session data are stored ?

Tomcat's sessions are stored according to chosen session manager. If we pick the standard manager (StandardManager class saw previously), all session data will be saved into Java heap. The storing of session data in JVM memory is a dangerous idea. The memory is one of the most important resources in Java applications and shouldn't be polluted with data which can be stored somewhere else. In catastrophic (a lot of simultaneous user requests) scenario, this storage technic can lead into memory leaks issues. And this catastrophic scenario is real when we think about web crawlers which can initialize new session on every request.

In the other side we can find two persistent manners of storage, belonging to the same package as StandardManager: FileStore and JDBCStore. The first one allows to store data of every session in separate files. These files have the .session extension and are placed into directory configured in <Store /> configuration's element.

The second persistent storage option, JDBCStore, allows to save session data into database. Each row represents one session. The configuration of this system is more complicated as in the case of file storage. We need to: configure correctly the database connection, create Tomcat sessions table and specify all columns in Tomcat's configuration file.

The last way to store session data looks like StandardManager ones but it's applied into distributed environments. The clustering session manager saves the session in memory. In additionally, it tries to synchronize saved data in all servers in the cluster. For example, when an user creates an session in server A, Tomcat's clustering session manager will dispatch this session to server B or server C.

What is restoring session after Tomcat's restart ?

By default, Tomcat will try to persist all current sessions after restart. More precisely, when Tomcat detects a shutdown or restart event, it tries to serialize current session datas into file specified in pathname configuration attribute of context's session manager. If this attribute's value equals to "" (empty string), persistent saving won't be made.

At the code level of StandardManager, presented in the first paragraph, we can find two methods in charge of this persisting mechanism. First one, protected void doLoad() is invoked every time when Tomcat starts. Inside this method we can find the "if {}" clause which looks for file with saved sessions. By default, the name of this file is SESSIONS.ser and it can be found on temporary directory associated with current context in Tomcat's configuration file.

If SESSIONS.ser exists, the doLoad() reads it and tries to restore every found session. The session is represented here as an instance of org.apache.catalina.session.StandardSession class. At the end the persistent storage file is removed from filesystem.

But how these data are saved ? This is the protected void doUnload() method which makes it. First of all, it checks if the persistent file exists. If it's the case, it iteraters through all current sessions and adds it into persistent sessions list. The iterator writes a serialized version of the session object to the specified object output stream too. At the end doUnload() method saves the sessions into storage file and marks all current sessions as expired by calling session.expire(false).

What are Java classes that we can find in Tomcat sessions ?

Tomcat's implementations of HttpSession interface, in particular org.apache.catalina.session.StandardSession, stores session data in a ConcurrentHashMap. We can find this decleration at the begin on StandardSession class :

protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

ConcurrentHashMap is an Map<K, V> implementation designed to support concurrent data access. When you discover an memory problem in your web application caused by ConcurrentHashMap, start to look for solution from Tomcat's session management.

Another key classes of Tomcat's sessions are the session listeners. By analyzing the source code of StandardSession, we can see that they are a lot of fragments which are invoking session listeners. We can find them, for example, on session activating method (activate()), attribute putting method (setAttribute()) or session destroying methods (expiry()). You can use these listeners to analyze the session lifecycle when, for exemple, you want to find the source of memory problems.

This article shows some of "under the hood" Tomcat's points. At the begin, we saw what is the sessions lifecycle. We approached here a concept of session, but also a idea of session manager. In the next paragraph, we saw diffrent ways to store sessions in Tomcat: standard and persistent. After that, we explained an session restoring process on Tomcat's restart. The last part contained some key classes in Tomcat's sessions environment. This knowledge can help to diagnose and repare memory problems.

If you liked it, you should read:

📚 Newsletter Get new posts, recommended reading and other exclusive information every week. SPAM free - no 3rd party ads, only the information about waitingforcode!