EhCache Hibernate 2nd level cache maxBytesLocalHea

2020-04-11 05:37发布

问题:

I have a pretty standard persistence layer setup in my Spring driven application using Hibernate (4.2.15.Final) with EhCache (2.6.9) as 2nd level cache.

Everything works as expected. However, putting entries into the 2nd level cache sometimes takes ages.

I've configured caching of my domain model classes in an explicit ehcache.xml file (I didn't configure a default cache):

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         name="hibernate"
         updateCheck="false" 
         monitoring="autodetect"
         dynamicConfig="false"
         maxBytesLocalHeap="300M"
         maxBytesLocalDisk="500M">

   <cache
    name="org.mycorp.model.MyEntity" 
    eternal="true"
    overflowToDisk="false"
    diskPersistent="false"
    maxBytesLocalHeap="5M" />

   ...

</ehcache>

I get the following INFO message logged at startup of the persistence context:

DefaultSizeOfEngine | using Agent sizeof engine

and the following WARNING during execution

ObjectGraphWalker | The configured limit of 1,000 object references was reached while attempting to calculate the size of the object graph. Severe performance degradation could occur if the sizing operation continues. [...]

AFAIK the ObjectGraphWalker has to size the entities that are put into the cache, because I configured the single cache regions with maxBytesLocalHeap.

My domain model is quite complex and I know that I can limit the walking of the graph with @IgnoreSizeOf annotations, but I'm uncertain how to tackle the problem:

  • Do I have to ignore one side of a bidirectional association to avoid cycles?
  • Do I have to explicitly ignore transient members of my domain model classes?
  • In general, is it wise to go with maxBytesLocalHeap when using EhCache together with Hibernate or should I settle for maxEntriesLocalHeap, because Hibernate is keeping a separate cache region for each entity anyway?

[UPDATE]: I discovered, that transient members will not be cached by Hibernate (see Hibernate: Is it possible to save a transient field in second level cache?), so they should not be regarded by ehcache anyway. Correct?

回答1:

Short answer

Turns out that the problem I'm having is a result of using Joda-Time instances in my model (I'm using Jadira's UserType library to map Joda types).

Joda types keep all sorts of internal references (including references to chronology information resulting in a huge object graph) and Ehcache's SizeOfEngine walks these references leading to my original warning.

I found no clean way how to configure the SizeOfEngine engine to exclude these references, but then again I guess a cleaner approach would be to force Hibernate to only put the relevant info into the 2nd level cache in the first place (a time instance in my case of LocalDateTimes).

Update

Jadira took a poor choice when implementing its custom types: See my answer here

More Details

Here's what I found regarding my OP (using Hibernate 4.2.15.Final, EhCache 2.6.9 and UserType 3.2.0.GA):

First of all, I had a misconception about how Hibernate stores entities in it's 2nd-Level cache. After reading Lorimer's blog entry about Truly Understanding the Second-Level and Query Caches a lot of things made more sense to me:

  • You don't have to worry about bidirectional associations (or cyclic graphs for that matter), because Hibernate will only put IDs for your associations into the cache. And even if it would put a reference to the whole entity into the cache - which it doesn't - EhCache's SizeOf Engine would track objects in the graph already visited and would not size them twice.
  • Again, you don't have to worry about transient fields, because Hibernate will not put them into the cache
  • In theory there shouldn't be any problem going with a maxBytesLocalHeap configuration. Currently problems arise when you use custom user types which are not measured correctly by EhCache's SizeOf engine.


回答2:

I know that it is an old question. But it might be useful for somebody. I've got the same warning. I spent a lot of time to solve this issue. In my case EhCache doesn't ignore all hibernate proxy classes. My entity have some fields with lazy association and during sizeof measurement EhCache walk through whole hibernate graph.

Finally I found this page and solve it.