Oracle® Fusion Middleware Solution Guide for Oracle TopLink 11g Release 1 (11.1.1) Part Number E25034-01 |
|
|
PDF · Mobi · ePub |
This chapter provides instructions for configuring TopLink applications to ensure scalability in clustered application server environments. The instructions are generic and can be applied to any clustered application server environment; however, additional content is provided for WebLogic server and GlassFish server. Consult your vendor's documentation as required.
This chapter contains the following sections:
TopLink applications that are deployed to clustered application server environments benefit from cluster scalability, load balancing, and failover. These capabilities ensure that TopLink applications are highly available and can scale as application demand increases. TopLink applications are deployed the same way in clustered server environments as they are in standalone server environments. However, TopLink applications must consider cache consistency in clustered environments.
TopLink utilizes a shared (L2) object cache that avoids database access for objects and their relationships. The cache is enabled by default and enhances application performance. In clustered environments, caching can result in consistency issues (such as stale data) as changes made on one server are not reflected on objects cached in other servers. Cache consistency is only problematic for objects that are frequently updated. Read-only objects are not affected by cache consistency. See the EclipseLink documentation for detailed information on caching:
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Caching_Overview
Various options are available for addressing cache consistency:
Use distributed caching. TopLink includes an integration with Oracle Coherence that addresses many cache consistency issues that result from operating in a distributed environment. The integration is beyond the scope of this documentation. See Oracle Coherence Integration Guide for Oracle TopLink with Coherence Grid for additional details.
Use cache coordination to broadcast changes between the servers in the cluster to update or invalidate changed objects.
Use optimistic locking to prevent updates to stale objects and trigger the objects to be invalidated in the cache.
Use object/query refreshing when fresh data is required
Disable the shared cache or only cache read-only objects
The tasks in this section provide general instructions for ensuring that a TopLink application can scale in an application server cluster environment. These tasks must be completed prior to deploying an application.
This section contains the following tasks:
This task includes different configuration options that mitigate the possibility or chance that an application might use stale data when deployed to an application server cluster environment. The cache coordination option is specifically designed for clustered applications; however, evaluate all the options and use them together (if applicable) to create a solution that results in the best application performance. Properly configuring a cache can, in some cases, eliminate the need to use cache coordination. For additional details on these options, see:
http://wiki.eclipse.org/Introduction_to_Cache_%28ELUG%29#Handling_Stale_Data
The following topics are included in this section:
Note:
Oracle provides a TopLink and Coherence integration that allows TopLink to use Coherence as the L2 cache. The integration is beyond the scope of this documentation. See Oracle Coherence Integration Guide for Oracle TopLink with Coherence Grid for additional details.Cache consistency can be avoided by disabling the shared cache if an application does not require shared caching. To disable the shared cache for all objects, use the <shared-cache-mode>
element in the persistence.xml
file. For example:
<shared-cache-mode>NONE</shared-cache-mode>
To selectively enable or disable the shared cache, use the shared
attribute of the @Cache
annotation when defining an entity. For example:
... @Entity @Cache(shared=false) public class Employee { ... }
Refreshing a cache reloads the cache from the database to ensure that an application is using current data. This section describes different ways to refresh a cache.
The @cache
annotation provides the alwaysRefresh
and refreshOnlyIfNewer
attributes which force all queries that go to the database to refresh the cache:
... @Entity @Cache( alwaysRefresh=true, refreshOnlyIfNewer=true) public class Employee { ... }
The org.eclipse.persistence.jpa.JpaCache
interface includes several methods that remove stale objects if the cache is out of date:
The evictAll
method invalidates all of the objects in the cache. For example:
em.getEntityManagerFactory().getCache().evictAll();
Use the evict
method to invalidate specific classes.
em.getEntityManagerFactory().getCache().evict(MyClass);
The clear
method also refreshes a cache; however, clearing the cache can cause object identity issues if any of the cached objects are in use. Use this method only if the application knows that it no longer has references to objects held in the cache.
The preceding methods are passive and only refresh objects the next time the cache is accessed. To actively refresh an object, use the EntityManager.
refresh
method. The method refreshes a single object at a time.
Any of the following APIs also refresh a cache:
Session.refreshObject
DatabaseSession
and UnitOfWork
: refreshAndLockObject
methods
ObjectLevelReadQuery
: refreshIdentityMapResult
and refreshRemoteIdentityMapResult
methods
The ClassDescriptor
class also provides methods that refresh a cache:
setShouldAlwaysRefreshCache
setShouldAlwaysRefreshCacheOnRemote
setShouldDisableCacheHits
setShouldDisableCacheHitsOnRemote
setShouldOnlyRefreshCacheIfNewerVersion
Use these methods in a descriptor amendment method. For example:
public void addToDescriptor(ClassDescriptor descriptor) { descriptor.setShouldRefreshCacheOnRemote(true); descriptor.setShouldDisableCacheHitsOnRemote(true); }
Lastly, a query hint triggers a query to refresh the cache. For example:
Query query = em.createQuery("Select e from Employee e"); query.setHint("javax.persistence.cache.storeMode", "REFRESH");
Cache expiration makes a cached object instance invalid after a specified amount of time. Any attempt to use the object causes the most up-to-date version of the object to be reloaded from the data source. Expiration can help ensure that an application is always using the most recent data. This section describes different ways to set expiration.
The @cache
annotation provides the expiry
and expiryTimeOfDay
attributes which remove cache instances after a specific amount of time. The expiry
attribute is entered in milliseconds. The default value if no value is specified is -1
which indicates that expiry is disabled. The expiryTimeOfDay
attribute is an instance of the org.eclipse.persistence.annotations.TimeOfDay
interface. The following example sets the object to expire after 5 minutes:
... @Entity @Cache(expiry=300000) public class Employee { ... }
At the descriptor level, use the ClassDescriptor.setCacheInvalidationPolicy
method to set a CacheInvalidationPolicy
instance. The following invalidation policies are available:
DailyCacheInvalidationPolicy
: the object is automatically flagged as invalid at a specified time of day.
NoExpiryCacheInvalidationPolicy
: the object can only be flagged as invalid by explicitly calling IdentityMapAccessor.invalidateObject
method.
TimeToLiveCacheInvalidationPolicy
: the object is automatically flagged as invalid after a specified time period has elapsed since the object was read.
Optimistic locking prevents one user from writing over another user's work. Locking is important when multiple servers or multiple applications access the same data and is relevant in both single-server and multiple-server environments. In a multiple-server environment, locking is still required if an application uses cache refreshing or cache coordination. This section describes different ways to set optimistic locking.
The @OptimisticLocking
annotation specifies the type of optimistic locking to use when updating or deleting entities. Optimistic locking is supported on an @Entity
or @MappedSuperclass
annotation. The following attributes are available:
ALL_COLUMNS
: This policy compares every field in the table in the WHERE
clause when doing an update or a delete.
CHANGED_COLUMNS
: This policy compares only the changed fields in the WHERE
clause when doing an update. A delete operation will only compare the primary key.
SELECTED_COLUMNS
: This policy compares selected fields in the WHERE
clause when doing an update or a delete. The fields specified must be mapped and not be primary keys.
VERSION_COLUMN
: (default) This policy allows a single version number to be used for optimistic locking. The version field must be mapped and not be the primary key. To automatically force a version field update on a parent object when its privately owned child object's version field changes, use the cascaded
method set to true
. The method is set to false
by default.
At the descriptor level, configure optimistic locking by using the ClassDescriptor.setOptimisticLockingPolicy
method to set an optimistic FieldsLockingPolicy
instance. As with the annotation, the following policies are included:
AllFieldsLockingPolicy
: This policy compares every field in the table in the WHERE
clause when doing an update or a delete.
ChangedFieldsLockingPolicy
: This policy compares only the changed fields in the WHERE
clause when doing an update. A delete operation will only compare the primary key.
SelectedFieldsLockingPolicy
: This policy compares selected fields in the WHERE
clause when doing an update or a delete. The fields specified must be mapped and not be primary keys.
VersionLockingPolicy
: This policy is used to allow a single version number to be used for optimistic locking. To automatically force a version field update on a parent object when its privately owned child object's version field changes, use the VersionLockingPolicy.setIsCascaded
method set to true
.
TimestampLockingPolicy
: This policy is used to allow a single version timestamp to be used for optimistic locking.
Cache coordination synchronizes changes among distributed sessions. Cache coordination is most useful in application server clusters where the need to maintain consistent data for all applications can be challenging. Moreover, cache consistency becomes increasingly more difficult as the number of servers within an environment increases.
Cache coordination works by broadcasting notifications of transactional object changes among sessions (ServerSession
or persistence unit) in the cluster. Cache coordination is most useful for application that are primarily read-based and when changes are performed by the same application operating with multiple, distributed sessions.
Cache coordination significantly minimizes stale data, but does not completely eliminate the possibility that stale data might occur. In addition, cache coordination reduces the number of optimistic lock exceptions encountered in a distributed architecture, and decreases the number of failed or repeated transactions in an application. However, cache coordination in no way eliminates the need for an effective locking policy. To ensure the most current data, use cache coordination with optimistic or pessimistic locking; optimistic locking is preferred.
Cache coordination is supported over RMI and JMS and can be configured either declaratively by using persistence properties in a persistence.xml
file or by using the cache coordination API. System properties that match the persistence properties are available as well.
For additional details on cache coordination see:
http://wiki.eclipse.org/Introduction_to_Cache_%28ELUG%29#Cache_Coordination_2
Configuring JMS Cache Coordination Using Persistence Properties
The following example demonstrates how to configure cache coordination in the persistence.xml
file and uses JMS for broadcast notification. For JMS, provide a JMS topic JNDI name and topic connection factory JNDI name in addition to the protocol. The JMS topic should not be JTA enabled and should not have persistent messages.
<property name="eclipselink.cache.coordination.protocol" value="jms" /> <property name="eclipselink.cache.coordination.jms.topic" value="jms/EmployeeTopic" /> <property name="eclipselink.cache.coordination.jms.factory" value="jms/EmployeeTopicConnectionFactory" />
Applications that run in a cluster generally do not require a URL as the topic is enough to locate and use the resource. For applications that run outside the cluster, a URL is required. The following example is a URL for a WebLogic server cluster:
<property name="eclipselink.cache.coordination.jms.host" value="t3://myserver:7001/" />
A user name and password for accessing the servers can also be set if required. For example:
<property name="eclipselink.cache.coordination.jndi.user" value="user" />
<property name="eclipselink.cache.coordination.jndi.password" value="password" />
Configuring RMI Cache Coordination Using Persistence Properties
The following example demonstrates how to configure cache coordination in the persistence.xml
file and uses RMI for broadcast notification.
<property name="eclipselink.cache.coordination.protocol" value="rmi" />
Applications that run in a cluster generally do not require a URL because JNDI is replicated and each server can look up each others listener. If an application runs outside of a cluster, or if JNDI is not replicated, then each server must provide its URL. This could be done through the persistence.xml
file; however, different persistence.xml
files (thus JAR or EAR) for each server is required, which is normally not desirable. A second option is to set the URL programmatically using the cache coordination API. See "Configuring Cache Coordination Using the Cache Coordination API". The final option is to set the URL as a system property on each application server. The following example sets the URL for a WebLogic server cluster using a system property:
-Declipselink.cache.coordination.jms.host=t3://myserver:7001/
A user name and password for accessing the servers can also be set if required; for example:
<property name="eclipselink.cache.coordination.jndi.user" value="user" /><property name="eclipselink.cache.coordination.jndi.password" value="password" />
RMI cache coordination can use either asynchronous or synchronous broadcasting; asynchronous is the default. Synchronous broadcasting ensures that all of the servers are updated before the request returns. The following example configures synchronous broadcasting.
<property name="eclipselink.cache.coordination.propagate-asynchronously" value="false" />
If multiple applications on the same server or network use cache coordination a separate channel can be used for each application. For example:
<property name="eclipselink.cache.coordination.channel" value="EmployeeChannel" />
Lastly, if required, change the default RMI multicast socket address that allows servers to find each other. The following example explicitly configures the multicast settings:
<property name="eclipselink.cache.coordination.rmi.announcement-delay" value="1000" /> <property name="eclipselink.cache.coordination.rmi.multicast-group" value="239.192.0.0" /> <property name="eclipselink.cache.coordination.rmi.multicast-group.port" value="3121" /> <property name="eclipselink.cache.coordination.packet-time-to-live" value="2" />
Configuring Cache Coordination Using the Cache Coordination API
Use the CommandManager
interface to programmatically configure cache coordination for a session. The following example configures RMI cache configuration:
Session.getCommandManager().setShouldPropagateAsynchronously(boolean)
Session.getCommandManager().getDiscoveryManager().
setAnnouncementDelay()
setMulticastGroupAddress()
setMulticastPort()
setPacketTimeToLive()
Session.getCommandManager().getTransportManager().
setEncryptedPassword()
setInitialContextFactoryName()
setLocalContextProperties(Hashtable)
setNamingServiceType() //passing in one of:
TransportManager.JNDI_NAMING_SERVICE
TransportManager.REGISTRY_NAMING_SERVICE
setPassword()
setRemoteContextProperties(Hashtable)
setShouldRemoveConnectionOnError()
setUserName()
Setting Cache Synchronization
Cache synchronization determines how objects changes are broadcast among session members. The following synchronization modes are available:
SEND_OBJECT_CHANGES
: (Default) This option sends a list of changed objects including data about the changes. This data is merged into the receiving cache.
INVALIDATE_CHANGED_OBJECTS
: This option sends a list of the identities of the objects that have changed. The receiving cache invalidates the objects rather than changing any of the data.
SEND_NEW_OBJECTS_WITH_CHANGES
: This option is the same as the SEND_OBJECT_CHANGES
option except it also includes any newly created objects from the transaction.
NONE
: This option does no cache coordination.
The @cache
annotation coordinationType
attribute is used to specify the synchronization mode. For example:
... @Entity @Cache(CacheCoordinationType.SEND_NEW_OBJECTS_CHANGES) public class Employee { ... }
The ObjectChangeSet.setCacheSynchronizationType
method can also be used to set the synchronization mode. For example
setCacheSynchronizationType() // passing in one of:
ClassDescriptor.DO_NOT_SEND_CHANGES
ClassDescriptor.INVALIDATE_CHANGED_OBJECTS
ClassDescriptor.SEND_NEW_OBJECTS_WITH_CHANGES
ClassDescriptor.SEND_OBJECT_CHANGES
Ensure the TopLink JAR files are included on the classpath of each application server in the cluster to which the TopLink application is deployed and configure TopLink as the persistence provider. See Chapter 2, "Using TopLink with WebLogic Server," and Chapter 3, "Using TopLink with GlassFish Server," for detailed instructions on setting up TopLink with WebLogic server and GlassFish, respectively.
Configure an application server cluster that includes each application server that hosts the TopLink application:
For WLS clustering see Oracle Fusion Middleware Using Clusters for Oracle WebLogic Server.
For GlassFish clustering, see:
http://download.oracle.com/docs/cd/E18930_01/html/821-2426/index.html
The following additional resources are available:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/CacheCoordination
For more information, see the following APIs in Oracle Fusion Middleware Java API Reference for EclipseLink.
org.eclipse.persistence.annotations.OptimisticLocking
org.eclipse.persistence.annotations.Cache
org.eclipse.persistence.descriptors.ClassDescriptor
org.eclipse.persistence.sessions.coordination