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.