« Scary fact: 1 java class out of 70 is a Node!Tomcat, JSessionID, and subdomains... »

Jdbc Jutsu Saves Heap Memory Against Wicket's Stateful Ajax


Permalink 02:41:44 pm, by nogunner Email , 740 words   English (US)
Categories: Misc

Jdbc Jutsu Saves Heap Memory Against Wicket's Stateful Ajax

Hey, I hope Quentin Tarantino won't steal my title and make a movie out of it! Anyway, the Wicket's implementation of Ajax is so good that I just stopped using anything else to make my web client communicate with my server. There's this one thing however, that prevents the fine scaling of Wicket sites, that's namely memory consumption. Wicket by itself does not consume that much memory though, but if you want to use the sweet Ajax components, you're stuck with stateful pages. And using stateful pages + lots of visitors usually implies memory issues: it's not just your own data contained in the WebSession object that is stored in memory, but also the current page hosting the ajax components, and the n last pages visited. If your pages are big, the session are big, that's the point.

Add to that a specific need to make the session last longer than usual, to allow users to stop using the site, then going back after a long period of time, and still have their session available, and you'd rapidly be waiting your users with fear.

So, to conciliate long sessions, limited-memory servers, and stateful wicket, the best possible solution, besides asking your users not to tell their friends, is to apply a Jdbc Jutsu to the session management of your servlet container. At least, that's how I solve my issue.

Tomcat provides a JDBCStore for its PersistentManager class (which is responsible for managing the sessions): this java jutsu just saved my server's memory from going out of control. Unlike the default org.apache.catalina.session.StandardManager that stores everything in your precious heap memory, the PersistentManager provides a lot of flexibility regarding the session storage. For instance, a typical configuration would keep the sessions in-memory, but passivate them into a database after a few minutes of inactivity (instead of consuming all this good memory for idle or disconnected users until their session expires).

The Tomcat documentation lacks a few examples, so here's mine: I wanted unlimited sessions, and passivate idle sessions in the JDBC database after 120 seconds of inactivity (lines to customize are yellow).

  <Host ......
	  <Context path="/MYPATH" docBase="MY-APPLICATION.WAR">
	    <Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true" 
	      <Store className="org.apache.catalina.session.JDBCStore"



Note: Remember to put your jdbc driver jar in the lib/ folder of Tomcat, or the connection won't work.

Then in the database and schema specified in the configuration above, just add the following table:
(from the Tomcat Manual at http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html):

create table tomcat_sessions (
  session_id     varchar(100) not null primary key,
  valid_session  char(1) not null,
  max_inactive   int not null,
  last_access    bigint not null,
  app_name       varchar(255),
  session_data   mediumblob,
  KEY kapp_name(app_name)

Well, that's it, no more wicket-related memory issues.

Update after Thyzz comment (see below)

Wicket can actually use either its original HttpSessionStore (that stores everything in the servlet http session), or its new SecondLevelCacheSessionStore that stores the PageMap on disk. Here is below some metrics I made that compare the memory usage with and without the tomcat's JDBCStore:

(click to enlarge)

To get those metrics, I used a web application that makes a moderate memory usage, and changed it so that the SessionStore can be either the HttpSessionStore or the SecondLevelCacheSessionStore. Additionnally, I added a new byte[1024*500] allocation into the session object, so that the memory consumption be artificially higher (for the purpose of testing in this specific configuration, applications with a really low memory footprint of their session behave totally differently, and are unlikely to have any memory-related issue). Then I ran a script on another computer that would make a loop over an http request for the frontpage (and all the resources of that page).

As a result, both HttpSessionStore and SecondLevelCacheSessionStore end up with an OutOfMemoryException. The memory usage is slightly better when using the SecondLevelCacheSessionStore, but I did not test the http latency; a real benchmark would require to compare both memory and speed, but at least the figures shows that the memory issue is prevented.


Comment from: Thyzz [Visitor]
ThyzzNice post.
But what session store are you using?
The default or the httpsessionstore? (Default being the SecondLevelCacheSessionStore that serializes pages to disk)

And what is the 'lag' you get when the session has to be read from the database?
06/24/09 @ 10:28
Comment from: nogunner [Member] Email
nogunnerHi Thyzz,

That's a good point, I should have mentionned both stores. I've used SecondLevelCachesSession, but that does not really change much, because AFAIK it only stores the PageMaps into files, not the session itself.

I'll update the article with some metrics I have that compares that.

Regarding the lag you mention, I don't have any measure for that, but an interesting feature of the JDBCStore is that it does not persist the session immediatly, the persistance is actually delayed until it reaches a (configurable) time limit. In my tests, I used 30 seconds, but that depends on the kind of web site and service.

Regarding pure performance, I suspect the most optimized combination is pure HttpSession with a JDBCStore backend, because the SecondLevelCacheSessionStore writes to the filesystem and uses a separate index file, and this is unlikely to be faster than what MySQL does, even with the Jdbc layer in-between (but, again, I've made no measure, that's only a technical intuition).
06/24/09 @ 12:58
Comment from: Thyzz [Visitor]
ThyzzBut what happens to the PageMap that is serialized to disk while the session is persisted to mysql? Will the pages still exist when a user finally does something?

Or will the pagemap persist as long as the session is valid (until the session times-out)?
06/24/09 @ 14:12
Comment from: nogunner [Member] Email
nogunnerWhat happens to the pagemap with the second level cache is not altered by the session being stored by tomcat in memory or in a jdbc store. How Tomcat manages its servlet session happens on a totally different layer.

Consequently, when the second level cache and the jdbc store are both used, pagemaps are still stored on the filesystem, and the session still contains a simple reference to this pagemaps, used by the second level cache to load it back in memory when needed.

The only difference is that without the jdbc store, the session always reside in memory, while it can be persisted in the database after a while when the jdbc store is used. PageMaps are just a specific data of the sessions, that happens to be managed differently by Wicket's HttpSessionStore (pagemaps always stored in the session) and SecondLevelCacheSessionStore (pagemaps always stored on disk, only a reference is kept in the session)
06/24/09 @ 14:58
Comment from: jazz [Visitor]
jazzi use the way named JDBCStore.But i find nothing from the table tomcat_sessions.what's the reason ?
05/20/10 @ 09:49

This post has 34641 feedbacks awaiting moderation...

nogunner's blog
Pointless technical stuffs are the bomb diggity of life.
July 2015
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  


XML Feeds

Web Monitoring

Be sure to check my LinkLogics web monitoring application if you happen to need external monitoring.
blogging tool