Liferay's Clustering API

Liferay will support our API and resolve any issues and answer any questions having to do with the API itself or any other part of Liferay's software. Issues and questions regarding custom development may be handled by our Global Services team or by the developer of those customizations.

Many plugins need to be able to communicate over a cluster.  While nodes in a cluster normally share a single database that can be used, it is often desirable to transmit messages to update in memory caches on other nodes or to tell all the nodes to take some action in response to a user's actions.

This article documents basic information on three ways to transit data across a cluster:

  1. MultiVMPoolUtil
  2. Clusterable Annotation
  3. ClusterExecutorUtil

Resolution

1. MultVMPoolUtil

Example

The MultiVMPoolUtil can be used to create and fetch portal caches, these caches are basically maps that can be shared across the cluster, or used on a single node. To create/fetch a portal cache simply call:

PortalCache portalCache = MultiVMPoolUtil.getCache("MarkAppCache"); 
portalCache.put("First key", "First Value");

*Portal caches can be used much like a map (the key and value does not have to be a String, that's just what I'm using for the example):

These values can then be retrieved later, but even better we allow designating a listener on the portal cache like so:

CacheListener<String, String> myCacheListener = new MyCacheListenerImpl<String, String>();
portalCache.registerCacheListener(myCacheListener);

Configuration

These caches can be configured to allow data to be sent across different nodes in a cluster.

<cache
    eternal="false"
    maxElementsInMemory="100"
    name="TestCache"
    overflowToDisk="false"
    timeToIdleSeconds="600"
>
    <cacheEventListenerFactory
        class="com.liferay.portal.cache.ehcache.LiferayCacheEventListenerFactory"
        properties="replicatePuts=true,replicatePutsViaCopy=true,replicateUpdatesViaCopy=true"
        propertySeparator=","
    />
    <bootstrapCacheLoaderFactory class="com.liferay.portal.cache.ehcache.LiferayBootstrapCacheLoaderFactory" />
</cache>

This would be in a file indicated by the ehcache.multi.vm.config.location property.

The root for this location for Tomcat is: tomcat-home/webapps/ROOT/WEB-INF/classes.

It's important to note that the properties replicatePutsViaCopy and replicateUpdatesViaCopy have a default of false for performance reasons. The max size of the cache is indicated by maxElementsInMemory. When this cap is reached a registered cache listener can react to the eviction.

Side Note

Changing the ehcache.multi.vm.config.location is not just about setting up a caches to propagate across the cluster, it also directly changes all of Liferay's caches - this can be essential for performance tuning, so make sure to bring over elements from the default file and tune them for your specific environment (usually this involves increasing/decreasing cache sizes).

2. Clusterable Annotation

Liferay's Clusterable annotation is simple to implement and is used by the ClusterableAdvice:

@Clusterable (acceptor = MyClusterInvokeAcceptor.class, onMaster = true)
public void myMethod(Args[] args)

The cluster acceptor can implement the ClusterInvokeAcceptor which only has one method which determines if the annotated method will be fired on the node. Setting onMaster to true means only the master node will have this method called.

This annotation can be used by service classes and is useful when operations need to be run on several nodes.

3. ClusterExecutorUtil

The ClusterExecuterUtil can be used when more fine grain handling needs to be done or when needing to do this outside of a service. This not as convenient as the annotation, it can only call static methods and all the arguments must be serializable.

First we need to create a method key:

MethodKey myMethodKey = new MethodKey(MethodClass.class, "methodName", FirstSerializableArguement.class ...);

Next we create the method handler:

MethodHandler myMethodHandler = new MethodHandler(myMethodKey, myFirstArguement....);

Now we can create the cluster request (having a true skipLocal parameter allows us to skip the current node):

ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(methodHandler, true);

ClusterExecutorUtil.execute(clusterRequest);

This allows us to call methods outside of services.

Additional Information

这篇文章有帮助吗?
0 人中有 0 人觉得有帮助