distributed entity cache (invalidation based)
josey Jun 8, 2009 4:24 PMI am trying to deploy distributed caching for a single entity. I am running JBoss AS 5.1.0 with jdk 1.5. I have two nodes running on two separate servers in a single partition.
I see the caching work fine on each single node but the cache does not replicate/invalidate between the two nodes (I'd like to use invalidation).
Test case:
1. Ran a JUnit test that loaded the entity on node1 and node2 so it was in the cache on each node in the partition.
2. Ran a JUnit test that changed the entity on node1.
3. Ran a JUnit test that loaded the entity on node1 and node2.
From looking at logging in both of the servers I can tell that node2 has the stale version (grabbed the entity from its cache instead of reloading it). I also have looked at the database log to verify that node2 did not try to load the entity when I requested it after it was changed by node1.
I added this to my entity class:
import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @Cache (usage=CacheConcurrencyStrategy.TRANSACTIONAL)
I added this to my persistence unit.
<property name="hibernate.cache.use_second_level_cache" value="true"/> <property name="hibernate.cache.use_query_cache" value="true"/> <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.jbc2.JndiMultiplexedJBossCacheRegionFactory"/> <property name="hibernate.cache.region.jbc2.cachefactory" value="java:CacheManager"/> <property name="hibernate.cache.region.jbc2.cfg.entity" value="mvcc-entity"/> <!-- Removing this had no effect <property name="hibernate.cache.region.jbc2.cfg.query" value="timestamps-cache"/> -->
Is there some other attribute that must be set in order to have a node notify the other nodes in the partition when a cached entity has changed? mvcc-entity has the property cacheMode set to INVALIDATION_SYNC. I figured that would do it. I also tried using pessimistic-entity but had no luck.
The only change that I have made to jboss-cache-manager-jboss-beans.xml is to set the multiplexer property to ${jboss.default.jgroups.stack:tcp} (did not want to use udp). I did this for each cache entry in this file.
For example,
<!-- A config appropriate for entity/collection caching that uses MVCC locking -->
<entry><key>mvcc-entity</key>
<value>
<bean name="MVCCEntityCache" class="org.jboss.cache.config.Configuration">
<!-- Node locking scheme -->
<property name="nodeLockingScheme">MVCC</property>
<!-- READ_COMMITTED is as strong as necessary for most
2nd Level Cache use cases. -->
<property name="isolationLevel">READ_COMMITTED</property>
<property name="useLockStriping">false</property>
<!-- Mode of communication with peer caches.
INVALIDATION_SYNC is highly recommended as the mode for use
with entity and collection caches. -->
<property name="cacheMode">INVALIDATION_SYNC</property>
<!-- Name of cluster. Needs to be the same for all members -->
<property name="clusterName">${jboss.partition.name:DefaultPartition}-mvcc-entity</property>
<!-- Use a UDP (multicast) based stack. A udp-sync stack might be
slightly better (no JGroups FC) but we stick with udp to
help ensure this cache and others like timestamps-cache
that require FC can use the same underlying JGroups resources.
<property name="multiplexerStack">${jboss.default.jgroups.stack:udp}</property>
-->
<!-- Use TCP -->
<property name="multiplexerStack">${jboss.default.jgroups.stack:tcp}</property>
<!-- Whether or not to fetch state on joining a cluster. -->
<property name="fetchInMemoryState">false</property>
<!-- The max amount of time (in milliseconds) we wait until the
state (ie. the contents of the cache) are retrieved from
existing members at startup. Ignored if FetchInMemoryState=false. -->
<property name="stateRetrievalTimeout">60000</property>
<!-- Number of milliseconds to wait until all responses for a
synchronous call have been received. -->
<property name="syncReplTimeout">17500</property>
<!-- Max number of milliseconds to wait for a lock acquisition -->
<property name="lockAcquisitionTimeout">15000</property>
<!-- Hibernate 2LC can replicate custom types, so we use marshalling -->
<property name="useRegionBasedMarshalling">true</property>
<!-- Must match the value of "useRegionBasedMarshalling" -->
<property name="inactiveOnStartup">true</property>
<!-- Disable asynchronous RPC marshalling/sending -->
<property name="serializationExecutorPoolSize">0</property>
<!-- We have no asynchronous notification listeners -->
<property name="listenerAsyncPoolSize">0</property>
<property name="evictionConfig">
<bean class="org.jboss.cache.config.EvictionConfig">
<property name="wakeupInterval">5000</property>
<!-- Overall default -->
<property name="defaultEvictionRegionConfig">
<bean class="org.jboss.cache.config.EvictionRegionConfig">
<property name="regionName">/</property>
<property name="evictionAlgorithmConfig">
<bean class="org.jboss.cache.eviction.LRUAlgorithmConfig">
<!-- Evict LRU node once we have more than this number of nodes -->
<property name="maxNodes">10000</property>
<!-- And, evict any node that hasn't been accessed in this many seconds -->
<property name="timeToLiveSeconds">1000</property>
<!-- Don't evict a node that's been accessed within this many seconds.
Set this to a value greater than your max expected transaction length. -->
<property name="minTimeToLiveSeconds">120</property>
</bean>
</property>
</bean>
</property>
<property name="evictionRegionConfigs">
<list>
<!-- Don't ever evict modification timestamps -->
<bean class="org.jboss.cache.config.EvictionRegionConfig">
<property name="regionName">/TS</property>
<property name="evictionAlgorithmConfig">
<bean class="org.jboss.cache.eviction.NullEvictionAlgorithmConfig"/>
</property>
</bean>
</list>
</property>
</bean>
</property>
</bean>
</value>
</entry>
Thanks.