Tuning for low Latency and high Throughput

You can achieve significant improvement of throughput and a high optimization of latency by using transient processes, as almost no remote calls to the database are necessary and the amount of data stored in the database is reduced. Refer to chapter Transient Processes of the Key Concepts part for details on the concept of transient processes.

Using Transient Processes

To increase performance by using transient processes, you need to perform the following steps:

  1. Enable Transient Process Execution
  2. Configure your internal in-memory Storage
  3. Exposing the in-memory Storage
  4. Defining the Provider for Cluster safe Objects
  5. Configure Fast Caching Sequence Generators

Enable Transient Process Execution

Enable transient process execution via one of the following two options:

  1. Eclipse modeler:
    Edit the process definition in your Infinity Process Platform modeler to support transient process execution. For details refer to section Audit Trail Persistence of chapter Working with Process Definitions. Make sure that transient process execution is not disabled globally.
  2. Global property:
    Enable the execution of transient processes globally via the property Carnot.Engine.Tuning.SupportTransientProcesses. Set this property in your carnot.properties file to on. For details refer to section Tuning of chapter Server Side Properties.

Configure your internal in-memory Storage

Now configure your internal in-memory storage, e.g. Hazelcast. If you are using Hazelcast, refer to section Application Server Setup in the Deployment Guide for details on how to set up Hazelcast for your requirements. Choose the description for the application server you use or the according chapter for Spring if you use Spring.

Exposing the in-memory Storage

If there is no need for exposing the in-memory storage, you can set the property Carnot.Engine.Tuning.TransientProcesses.ExposeInMemStorage in your carnot.properties file to false to achieve a performance improvement due to internal optimizations.

Per default, this property is set to true to ensure that during the execution of transient process instances the process instance in question and all related persistents are accessible via API, e.g. via WorkflowService#getProcessInstance(long) (for accesses not using any queries).

Defining the Provider for Cluster safe Objects

Per default, a cluster provider for Hazelcast is used in IPP (ClusteredEnvHazelcastObjectProvider). You have the option to write your own provider, which you can set to be used via the following server-side property Carnot.Engine.Tuning.SupportTransientProcesses.ClusterSafeObjectProvider.

The default setting for this property in Infinity uses the cluster provider for Hazelcast mentioned above:

Carnot.Engine.Tuning.SupportTransientProcesses.ClusterSafeObjectProvider =
   org.eclipse.stardust.engine.core.persistence.jdbc.transientpi.ClusteredEnvHazelcastObjectProvider

See the provided implementation for Hazelcast as example:

package org.eclipse.stardust.engine.core.persistence.jdbc.transientpi;

import java.util.Map;

import javax.resource.ResourceException;
import javax.resource.cci.ConnectionFactory;

import org.eclipse.stardust.common.config.ExtensionProviderUtils;
import org.eclipse.stardust.common.error.PublicException;
import org.eclipse.stardust.engine.core.runtime.beans.BpmRuntimeEnvironment;
import org.eclipse.stardust.engine.core.runtime.beans.interceptors.PropertyLayerProviderInterceptor;
import org.eclipse.stardust.engine.core.runtime.beans.removethis.KernelTweakingProperties;
import org.eclipse.stardust.engine.core.spi.cluster.ClusterSafeObjectProvider;
import org.eclipse.stardust.engine.core.spi.jca.HazelcastJcaConnectionFactoryProvider;

import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.Transaction;

public class ClusteredEnvHazelcastObjectProvider implements ClusterSafeObjectProvider
{
   private static final HazelcastJcaConnectionFactoryProvider CONNECTION_FACTORY_PROVIDER;
   
   static
   {
      CONNECTION_FACTORY_PROVIDER = ExtensionProviderUtils.getFirstExtensionProvider(HazelcastJcaConnectionFactoryProvider.class, KernelTweakingProperties.HZ_JCA_CONNECTION_FACTORY_PROVIDER);
      if (CONNECTION_FACTORY_PROVIDER == null)
      {
         throw new IllegalStateException("No Hazelcast JCA connection factory provider could be found.");
      }
   }
   
   @Override
   public <K, V> Map<K, V> clusterSafeMap(final String mapId)
   {
      if (mapId == null)
      {
         throw new NullPointerException("Map ID for Hazelcast map must not be null.");
      }
      
      return Hazelcast.getMap(mapId);
   }

   @Override
   public void beforeAccess()
   {
      final BpmRuntimeEnvironment rtEnv = PropertyLayerProviderInterceptor.getCurrent();
      final ConnectionFactory connectionFactory = CONNECTION_FACTORY_PROVIDER.connectionFactory();
      
      try
      {
         /* Hazelcast can only cope with one transaction per thread */
         if (Hazelcast.getTransaction().getStatus() != Transaction.TXN_STATUS_ACTIVE)
         {
            /* enlists Hazelcast objects in the current tx */
            rtEnv.retrieveJcaConnection(connectionFactory);
         }
      }
      catch (final ResourceException e)
      {
         throw new PublicException("Failed enlisting Hazelcast objects in the current transaction.", e);
      }
   }
   
   @Override
   public void exception(final Exception ignored)
   {
      /* nothing to do */
   }
   
   @Override
   public void afterAccess()
   {
      /* nothing to do */
   }
}

The location from where the (Hazelcast) JCA connection factory can be retrieved from can be defined via the SPI org.eclipse.stardust.engine.core.spi.jca.HazelcastJcaConnectionFactoryProvider. Infinity provides the following implementations:

Set the implementation to be used via the property Carnot.Engine.Hazelcast.JcaConnectionFactoryProvider in your carnot.properties file, e.g.:

Carnot.Engine.Hazelcast.JcaConnectionFactoryProvider =
   org.eclipse.stardust.engine.spring.integration.jca.SpringAppContextHazelcastJcaConnectionFactoryProvider

Configure Fast Caching Sequence Generators

Configure fast caching sequence generators to optimize database sequence fetching and achieve less database communication. Set the following properties in your carnot.properties file:

For example, set the following values:

   Carnot.Engine.Tuning.SequenceBatchSize = 5000
   AuditTrail.SequenceGenerator = org.eclipse.stardust.engine.core.persistence.jdbc.sequence.FastCachingSequenceGenerator

The FastCachingSequenceGenerator is used to retrieve sequence numbers in a batch and cache the retrieved sequences separately for every entity type.

Perform the following statements to obtain the according database schema changes:

ALTER SEQUENCE activity_instance_seq INCREMENT BY 5000;
ALTER SEQUENCE activity_instance_log_seq INCREMENT BY 5000;
ALTER SEQUENCE act_inst_property_seq INCREMENT BY 5000;
ALTER SEQUENCE trans_inst_seq  INCREMENT BY 5000;
ALTER SEQUENCE trans_token_seq INCREMENT BY 5000;
ALTER SEQUENCE daemon_log_seq INCREMENT BY 5000;
ALTER SEQUENCE data_value_seq INCREMENT BY 5000;
ALTER SEQUENCE event_binding_seq INCREMENT BY 5000;
ALTER SEQUENCE log_entry_seq INCREMENT BY 5000;
ALTER SEQUENCE link_type_seq INCREMENT BY 5000;
ALTER SEQUENCE model_dep_seq INCREMENT BY 5000;
ALTER SEQUENCE property_seq INCREMENT BY 5000;
ALTER SEQUENCE timer_log_seq INCREMENT BY 5000;
ALTER SEQUENCE usergroup_seq INCREMENT BY 5000;
ALTER SEQUENCE usergroup_property_seq INCREMENT BY 5000;
ALTER SEQUENCE user_seq INCREMENT BY 5000;
ALTER SEQUENCE user_property_seq INCREMENT BY 5000;
ALTER SEQUENCE wfuser_session_seq INCREMENT BY 5000;
ALTER SEQUENCE user_participant_seq INCREMENT BY 5000;
ALTER SEQUENCE user_usergroup_seq INCREMENT BY 5000;
ALTER SEQUENCE process_instance_seq INCREMENT BY 5000;
ALTER SEQUENCE proc_inst_property_seq INCREMENT BY 5000;
ALTER SEQUENCE structured_data_value_seq INCREMENT BY 5000;
ALTER SEQUENCE domain_seq INCREMENT BY 5000;
ALTER SEQUENCE domain_hierarchy_seq INCREMENT BY 5000;
ALTER SEQUENCE wfuser_domain_seq INCREMENT BY 5000;
ALTER SEQUENCE wfuser_realm_seq INCREMENT BY 5000;
ALTER SEQUENCE clob_data_seq INCREMENT BY 5000;
ALTER SEQUENCE model_seq INCREMENT BY 5000;
ALTER SEQUENCE STRING_DATA_SEQ INCREMENT BY 5000;
ALTER SEQUENCE partition_seq INCREMENT BY 5000;
ALTER SEQUENCE department_seq INCREMENT BY 5000;
COMMIT;

Note
Note that if you use MySQL, you need to prepare a MYSQL sequence support first as described in detail in section MySQL Sequence Support (required for using Transient Processes) of chapter MySQL Audit Trail Database Setup in the Deployment Guide.