Q1. EhCache works very well as the Hibernate L2 Cache, distributed.
We are using this for our project.
Q2. Several caches are possible.
- All database are already doing a lot of caching internally, so don't worry about this part.
However, the problem with the database
cache is that it is physically on the
database server, so each query
involves a network call (latency,
bandwith ..). That's the whole point
of the caches on the application
server.
- The Hibernate L2 cache has some specifics:
- very easy to work with (no code, little configuration)
- conceptually at the entity level (which is pretty fine-grained, we sometimes need to cache bigger grains, to make less database requests),
- working by id or collection (for example, caching a query result is deactivated by default, because it is impossible to make it useful in the general case).
- When the Hibernate L2 is inappropriate, we use the same EhCache library to cache data (that is not exactly entities). Examples of use-cases:
- when a table is big (record length and number), memory usage would not permit to cache it completely, but caching only three fields for all records is okay. It could be that these fields are the ones accessed often, or immutable...
- when we have many read accesses to the cache, and each would trigger a computation (on L2 cache) given the entities we have : the computation result can be stored in the cache. (typical exemple where the computation requires details from other tables, but the details are not used in the final result, so the cache doesn't store these details)
- when entities in a table are logically grouped by categories, and we want to request and cache one category at a time, instead of the regular L2 Cache policy that would be one entity at a time.
In a distributed context, this often
translates into invalidating a
category at a time when one of their
entities is modified, which is functionally
logical for us (and essential for
performance, as otherwise we would
have to invalidate all of these
entities ; this is because the cache
invalidates a whole region, or a
specific object, but in
between you have to loop which is bad for performance)
And others I'm sure ...
So this case is not closely database-related, it usually doesn't store our Hibernate entities. We put it in the Business Tier (and not the Data Access or Daos), make it available directly to business codes. Note that for us, it is not a transparent cache, but a call to an explicit business service (responsible for this cache : loading it if the data is not present, invalidating as needed) that does operations or deliver values.
A fun Threading issue in this cache : because this cache is accessed by our hundred web threads, it needs to be thread-safe. You probably know why a thread-safe value is either immutable or cloned at each call (which often is a performance problem). So all our business caches use immutable objects, and performance is great.