Jetspeed Distributed Cache Configuration

Jetspeed can be optionally configured to use distributed cache replication with ehcache. By default, distributed cache replication is disabled but it can be enabled through the Jetspeed configuration. The assembly folder contains cache.xml to control the ehcache configuration via Spring.

Jetspeed uses cache-replication for managing all of its distributed caches, such as the page-manager and preferences caches. The ehcache.xml (found in /WEB-INF/classes/) has more detailed cache configuration details. It has been modified to enable distributed cache replication for all caches including the page manager and preferences caches.

The following examples are taken from the distributed-ehcache.xml (in /WEB-INF/classes/). If you want to switch to complete distributed cache usage, it is easier to swap the usages of ehache.xml with the distributed.ehcache.xml completely in cache.xml (in /WEB-INF/assembly/) as shown below.

<!-- Cache Manager -->
<bean id="cacheManagerConfig" class="org.apache.jetspeed.cache.impl.EhCacheConfigResource">
	<!-- <property name="defaultConfigResource" value="distributed-ehcache.xml"/> -->
	<property name="defaultConfigResource" value="ehcache.xml"/>
</bean>

The Listener and Provider factory caches are required for cache replication. You shouldn't have to enter values in this file but instead use the jetspeed override.properties to set them. Below are parameters which can be set for configuring the distributed cache. The port and hostname can be the same for all nodes in the cluster under most default configurations.

ListenerFactory

<cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
                                 properties="hostName=${org.apache.jetspeed.ehcache.hostname},
                                 port=${org.apache.jetspeed.ehcache.port}"/>

ProviderFactory

<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
                                 properties="peerDiscovery=automatic,
                                 multicastGroupAddress=${org.apache.jetspeed.ehcache.group.address},
                                 multicastGroupPort=${org.apache.jetspeed.ehcache.group.port},
                                 timeToLive=${org.apache.jetspeed.ehcache.group.ttl}"/>

preferencesCache

<cache name="preferencesCache"
       maxElementsInMemory="10000"
       maxElementsOnDisk="1000"
       eternal="false"
       overflowToDisk="false"
       timeToIdleSeconds="28800"
       timeToLiveSeconds="28800"
       memoryStoreEvictionPolicy="LFU">
	<cacheEventListenerFactory
	        class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
	        properties="replicateAsynchronously=true, replicatePuts=false,
	                    replicateUpdates=false, replicateUpdatesViaCopy=false,
	                    replicateRemovals=true"/>
 </cache>

pageManagerPathCache

<cache name="pageManagerPathCache"
       maxElementsInMemory="${org.apache.jetspeed.ehcache.pagemanager.maxelements}"
       eternal="false"
       overflowToDisk="false"
       timeToIdleSeconds="${org.apache.jetspeed.ehcache.pagemanager.element.ttl}"
       timeToLiveSeconds="${org.apache.jetspeed.ehcache.pagemanager.element.ttl}"
       memoryStoreEvictionPolicy="LFU">
	<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
	                           properties="replicateAsynchronously=true,
	                                       replicatePuts=false,
	                                       replicateUpdates=false,
	                                       replicateUpdatesViaCopy=false,
	                                       replicateRemovals=true"/>
</cache>

Hostnames

The host name, represented by the org.apache.jetspeed.ehcache.hostname property, is the host the listener is running on. The host name defaults to the host name of the default interface if not specified. You will be required to specify a host name for each node when the host is multi-homed and you want to control the interface over which cluster messages are received. For instance, if you happen to setup your network so that the cache to cache communication is not on the default interface, then you have to set that host name property on each machine. This requires a custom jetspeed.property file for each node.

Configuring a different hostname per node can be done through the Cache Manager configuration Spring bean combined with setting a Java System property. In the cache.xml, you can configure the CacheManagerConfig to use a system property, in this case a property named server.ref. This argument is populated at runtime in the portal framework via the following setting in cache.xml:

    <!-- Cache Manager -->
    <bean id="cacheManagerConfig" class="org.apache.jetspeed.cache.impl.EhCacheConfigResource">
        <!-- <property name="defaultConfigResource" value="distributed-ehcache.xml"/> -->
        <property name="defaultConfigResource" value="ehcache${server.ref}.xml"/>
    </bean> 	

Make sure to set the system property, for example at startup:

java .... -Dserver.ref=_NODE56 

Cache Properties

Following are the default settings for using the distributed cache. These can be set/modified in the jetspeed.properties or override.properties:

Cache (commented out by default)
Cache page manager override properties.
Property Default Description
#org.apache.jetspeed.ehcache.pagemanager.maxelements 128 Database page manager cache size
#org.apache.jetspeed.ehcache.pagemanager.element.ttl 150 Database page manager cache element expiration in seconds, (infinite = 0)
#org.apache.jetspeed.ehcache.pagemanager.maxfiles 1000 PSML page manager file cache size
#org.apache.jetspeed.ehcache.config.resource ehcache.xml Cache configuration resource, ('ehcache.xml' or 'distributed-ehcache.xml' supported by default)
#org.apache.jetspeed.ehcache.group.address 230.0.0.1 Distributed cache peer discovery multicast address
#org.apache.jetspeed.ehcache.group.port 4446 Distributed cache peer discovery multicast port
#org.apache.jetspeed.ehcache.group.ttl 1 Distributed cache peer discovery multicast TTL. Choose based on the nodes locations.
  • 0 - restricted to the same host
  • 1 - restricted to the same subnet
  • 32 - restricted to the same site
  • 64 - restricted to the same region
  • 128 - restricted to the same continent
  • 255 - unrestricted
#org.apache.jetspeed.ehcache.hostname Distributed cache peer hostname, (set to listen on specific interface). Hostname will need to be entered for every node in some cases, see section above on Hostnames, otherwise leave blank.
#org.apache.jetspeed.ehcache.port 40001 Distributed cache peer port. Port should be different for each node if they are running on the same machine.

These settings are specific for the page manger cache:

  • #org.apache.jetspeed.ehcache.pagemanager.maxelements=128
  • #org.apache.jetspeed.ehcache.pagemanager.element.ttl=150
  • #org.apache.jetspeed.ehcache.pagemanager.maxfiles=1000

Testing Jetspeed Distributed Cache

First, verify that the following page-manager test works on your development machine:

mvn test -P test -Dtest=TestDatabasePageManagerCache

Not only must this test pass, but the following message should not appear in the console/shell or in the test log files:

"Server page managers not distributed: possible system limitation... test skipped"

If you see the above message, check firewall settings to allow UDP/4446. That is sometimes needed on Lunix systems if firewalls are enabled to allow UDP multicast loopback. Some older TCP stacks do not support UDP multicast loopback at all. This is why this test does not outright fail even though distributed caches can not be setup.

Now for the full test: setup two independent tomcat J2 images. Edit webapps/jetspeed/WEB-INF/assembly/cache.xml for Tomcat image #1:

<bean id="cacheManagerConfig" class="org.apache.jetspeed.cache.impl.EhCacheConfigResource">
    <property name="defaultConfigResource" value="distributed-ehcache.xml"/>
    <property name="defaultHostname" value="localhost"/>
    <property name="defaultPort" value="40001"/>
</bean>

Edit webapps/jetspeed/WEB-INF/assembly/cache.xml for Tomcat image #2:

<bean id="cacheManagerConfig" class="org.apache.jetspeed.cache.impl.EhCacheConfigResource">
    <property name="defaultConfigResource" value="distributed-ehcache.xml"/>
    <property name="defaultHostname" value="localhost"/>
    <property name="defaultPort" value="40002"/>
</bean>

Startup browsers against each server. Use different host names to ensure cookies are managed separately (i.e. '127.0.0.1' and 'localhost'). View the same page in each browser. Edit the page in one browser. Upon refresh, changes should be visible in second browser.

When distributed caches are run on multiple virtual or physical servers, the default port assigned above does not need to be incremented for each machine. If the servers are deployed on multiple networks, care must be taken to ensure multicast traffic on UDP/4446/230.0.0.1 and TCP/40001 is routed between the servers. Additionally, multicast propagation TTL may have to be specified to enable the UDP packets to jump between networks. The default value is "1", which is supposed to limit packets to one subnet. (See the org.apache.jetspeed.ehcache.group.ttl property).

Here is a fully specified cacheManagerConfig bean with its distributed cache default values for normal installation:

<bean id="cacheManagerConfig" class="org.apache.jetspeed.cache.impl.EhCacheConfigResource">
	<property name="defaultConfigResource" value="distributed-ehcache.xml"/>
	<property name="defaultGroupAddress" value="230.0.0.1"/>
	<property name="defaultGroupPort" value="4446"/>
	<property name="defaultGroupTTL" value="1"/>
	<property name="defaultHostname" value="localhost"/>
	<property name="defaultPort" value="40001"/>
</bean>

Any of these can be configured to reflect requirements of the production network.