Liferay's Architecture: Caching (Part 1)

Here I am again with another in the series about Liferay's architecture. If you haven't read them yet, the four previous entries covered: Overview, Services Layer, Web Services and Service Builder.

This time I'm going to cover a very important concept: caching. In today's web, it's impossible for a web application to provide even good enough performance in the web unless it has a well designed caching system. So what I'm going to cover here is not only useful to understand Liferay's architecture better but might also be beneficial for anyone writting Java web applications, specially if they are large.

Liferay is known to provide very good performance (check the Performance Whitepaper in the whitepapers section of this website for details) and its caching system is a key factor in achieving that performance. This caching system spans through all three layers. The following diagram shows the main caching components in each layer:

Let's cover each of them one by one, starting with the lower layer.

At the persistance layer Liferay relies on Hibernate to do most of its database access. Hibernate has two cache layers called Level 1 (L1) and Level 2 (L2). Level 1 is used to cache objects retrieved from the database within the current datababase session. In the case of Liferay a session is tied to an invocation to a service layer. So when the frontend layer (or a web service) invokes a service a db session is opened and reused until the service method returns. All operations performed until that point will share the L1 cache so the same object won't be retrieved twice from the database.

Hibernate's cache Level 2 is able to span across database sessions and stores database objects (Entity Cache) and results of queries (Query Cache). For example if any logic retrieves from the database all users that belong to a certain organization, the result will be stored in the cache. Note that what is really stored is the list of "references" to the actual objects which are stored in the Entity Cache. This is done to ensure that there aren't several copies of the same object in the cache.

Besides using Hibernate, Liferay's code also performs some complex database queries directly (although reusing the database conneciton). For these queries Liferay has its own Entity and Query cache. In fact thanks to the work of Shuyang these two caches are extremely efficient and as a result, for Liferay 6.2, we have decided to disable Hibernate's level 2 cache by default leaving Liferay's Query cache as responsible for that task to improve performance.

One final important aspect is that all of these caches use an underlying cache provider to manage the objects in memory. By default Liferay uses ehcache to do that, but it is also possible to change the caching provider through portal.properties.  The configuration is done within hibernate-clustered.xml which defines  and configures several cache areas.

Finetunning these configuration files is a very important task for any high-profile site. But don't try to do it based on guesses. You should always do it while running a performance test suite that can help you find bottlenecks and verify changes in the configuration.

Since I want to try and keep these blog entries shorter and more frequent, I'm dividing it in two parts. In the next one I'll cover the caching mechanisms of the services and the frontend layer.

Blogs
Great !! :-) !!!

Please write more on Caching, as it is quite difficult to understand the bigger picture to start off. I have been struggling with EhCache for past 2 weeks.

Thanks
Hi Jorge!

Great article. I hope the next entry explains a lot more. What performance test suite do you use or recommend?
Una sugerencia.Este blog podria ser multidioma, o por lo menos tener una versión en castellano
Muy buen articulo! Todo queda muy claro. Gracias de parte de los que aun somos unos novatos!
I am currently facing some EhCache Replication issue with My 6.0.6 implementation.

I would like to know which of the following Cache would be used, for a custom entity object.
L1 or L2.

Say I created a Custom Entity Object and retrieve it using the CustomEntityLocalService from my front end, which Cache will be used L1 or L2.
Hi Manovinaya, as explained by Jorge: "Level 1 is used to cache objects retrieved from the database within the current datababase session. In the case of Liferay a session is tied to an invocation to a service layer. So when the frontend layer (or a web service) invokes a service a db session is opened and reused until the service method returns. All operations performed until that point will share the L1 cache so the same object won't be retrieved twice from the database."

Ehcache is used to manage the 2nd level cache. Second level cache allows to mantain a object reference across multiple calls from your front end.
Hi jorge,
It is a great series on liferay architecture
Could share some knowledge on Workflow Framework part of the liferay?
Hi Jorge,

waiting your next part about caching.

In the meantime, can you give us some links where we can find explanations about the front end (mainly) an service layers caching mechanisms ?

For a proposal, I have to argue on the caching management in Liferay...

Thanks
Hi Jorge,

Got a chance to write next series of this article?
Hey Vipin,

Sorry I got side track and never found the time to continue.

I do plan to blog more about Liferay's architecture later this year but with a focus on the new modular architecture of Liferay 7. I hope you find that info useful as well.
Hi Jorge,
you say: "One final important aspect is that all of these caches use an underlying cache provider to manage the objects in memory. By default Liferay uses ehcache to do that, but it is also possible to change the caching provider through portal.properties. The configuration is done within hibernate-clustered.xml which defines and configures several cache areas."
But also that. "Besides using Hibernate, Liferay's code also performs some complex database queries directly (although reusing the database conneciton). For these queries Liferay has its own Entity and Query cache."
My question is:
is it possible to switch from ehcache implementation to another one both for hibernate and for liferay level cache?
It is potentially possible, although you will probably have to do a bit of research since it's not a common operation and thus it's not documented.

Out of curiosity, what implementation are you looking to use instead of ehcache?