Feb 09 2008

Configuring NHibernate Caches

Tag: NHibernate,ORMSymon Rottem @ 3:05 pm

A little while ago I decided it would be prudent to start using the second level cache in NHibernate to improve performance in a couple of web applications my team and I had written. The database was taking quite a bit of punishment and performance was degrading while the data being queried was often fairly static in nature so caching seemed like the right choice.

I’d seen some samples out there where people had added the cache configuration directives in their .hbm files so off I went and started adding the <cache> element to my class and collection mappings, configured the SysCache provider in my configuration file and voila, we were off and running with the first application. Then I sat down and started thinking…

Now you are probably asking yourself the same question I was – why didn’t I sit down and think first? An excellent question – one I’ll sit down and think about. Hmmm.

The problem was that the applications in question share the same domain model assembly, which in turn share the same NHibernate mapping files but each application has it’s own caching requirements so I couldn’t reuse the new cache settings between applications. For one application we don’t intend to ever write values to a particular class so they could be mapped to the cache as read-only, while in another application the cached value for the same class should be read-write. Since we were looking at using caching for performance reasons it certainly seemed to make sense that we use the cache in the most performant way possible.

After doing a bit of extra reading of the NHibernate docs I realized that you don’t have to add you cache directives to your mapping classes; there’s a single line in the documentation I had missed:

Alternatively (preferrably?), you may specify <class-cache> and <collection-cache> elements in hibernate.cfg.xml.

I guess the lesson here is read the documentation more carefully…

So, after adding the class and collection cache mappings to our NHibernate configuration we also added some cache regions with appropriate expiry periods for each application and turned on the query cache and started up the applications again. The performance difference is quite something – the database load, which was moderately heavy, dropped significantly and the response times for the applications in question suddenly jumped. I never did do any real comparison measurements but the difference was significant enough.

I have noticed, however, that when using the SysCache provider and setting expiration that sometimes the objects aren’t expired from the cache as promptly as I would have expected. I haven’t yet investigated this issue in depth, but it’s nagging at me. I’ll report back when I have more concrete data, but if there’s anyone out there who can shed some light I’d be glad for some feedback.