この章では、クラスタ化されたアプリケーション・サーバー環境でスケーラビリティを確保しながらTopLinkアプリケーションを構成する手順を説明します。この手順は一般的なもので、どのアプリケーション・サーバー環境にも適用できますが、WebLogicサーバーおよびGlassFishサーバーには、追加の内容が用意されています。必要に応じて、ベンダーのドキュメントを参照してください。
この章には次の項が含まれます:
クラスタ化されたアプリケーション・サーバー環境にデプロイされたTopLinkアプリケーションは、クラスタのスケーラビリティ、負荷分散およびフェイルオーバーを利用できます。これらの機能は、TopLinkアプリケーションの可用性を高め、アプリケーションの需要拡大に伴ってスケーリングできます。TopLinkのアプリケーションは、クラスタ化されたサーバー環境でも、スタンドアロンのサーバー環境と同様にデプロイされます。ただし、クラスタ化された環境では、キャッシュの整合性をTopLinkのアプリケーションで考慮する必要があります。
TopLinkでは、オブジェクトおよびその関係を取得する際にデータベースへのアクセスを回避する共有(L2)オブジェクト・キャッシュを利用します。このキャッシュはデフォルトで有効になり、アプリケーションのパフォーマンスが向上します。クラスタ化された環境でキャッシングを使用すると、1つのサーバーで行われた変更が、他のサーバーでキャッシュされているオブジェクトに反映されないために、整合性の問題(失効データなど)が発生する場合があります。キャッシュの整合性が問題になるのは、頻繁に更新されるオブジェクトのみです。読取り専用のオブジェクトは、キャッシュの整合性の影響を受けません。キャッシングの詳細は、EclipseLinkの次のドキュメントを参照してください。
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Caching_Overview
キャッシュの整合性に対処するには、次のように様々な方法があります。
分散キャッシングを使用します。TopLinkには、分散環境で運用した場合に発生するキャッシュの整合性の問題の多くに対処できるOracle Coherenceとの統合が含まれています。この統合については、このドキュメントでは説明しません。詳細は、Oracle Coherence Oracle TopLinkのためのCoherence Grid統合ガイドを参照してください。
キャッシュ・コーディネーションを使用して、クラスタ内のサーバー間で変更をブロードキャストし、変更されたオブジェクトを更新するか無効にします。
オプティミスティック・ロックを使用して、失効オブジェクトの変更を防止し、キャッシュ内のオブジェクトの無効化をトリガーします。
フレッシュなデータが必要な場合に、オブジェクトまたは問合せのリフレッシュを使用します。
共有キャッシュを無効にするか、読取り専用オブジェクトのみをキャッシュします。
この項のタスクでは、アプリケーション・サーバーのクラスタ環境でTopLinkアプリケーションをスケーリングできるようにするための一般的な手順を説明します。これらのタスクは、アプリケーションをデプロイする前に完了する必要があります。
この項の内容は次のとおりです。
このタスクには、アプリケーション・サーバーのクラスタ環境にアプリケーションがデプロイされた場合に、アプリケーションが失効データを使用する可能性を少なくする様々な構成オプションが含まれています。キャッシュ・コーディネーション・オプションは、クラスタ化されたアプリケーション用に特に設計されていますが、すべてのオプションを評価し、(適用可能な場合は)一緒に使用して、アプリケーションのパフォーマンスが最高になるようなソリューションを作成します。キャッシュを適切に構成すれば、キャッシュ・コーディネーションを使用する必要がなくなる場合もあります。これらのオプションの詳細は、次を参照してください。
http://wiki.eclipse.org/Introduction_to_Cache_%28ELUG%29#Handling_Stale_Data
この項の内容は次のとおりです。
注意: TopLinkでCoherenceをL2キャッシュとして使用できるようにするTopLinkとCoherenceの統合が提供されています。この統合については、このドキュメントでは説明しません。詳細は、Oracle Coherence Oracle TopLinkのためのCoherence Grid統合ガイドを参照してください。 |
アプリケーションに共有キャッシュが不要な場合は、共有キャッシュを無効にすれば、キャッシュの整合性の問題を回避できます。すべてのオブジェクトの共有キャッシュを無効にするには、persistence.xml
ファイルの<shared-cache-mode>
要素を使用します。次に例を示します。
<shared-cache-mode>NONE</shared-cache-mode>
共有キャッシュを選択的に有効または無効にするには、エンティティを定義する際に、@Cache
注釈のshared
属性を使用します。次に例を示します。
... @Entity @Cache(shared=false) public class Employee { ... }
アプリケーションが現在のデータの使用を確実にするために、キャッシュをリフレッシュするとデータベースからキャッシュがリロードされます。ここでは、キャッシュの様々なリフレッシュ方法について説明します。
@cache
注釈には、すべての問合せを強制的にデータベースに向かわせてキャッシュをリフレッシュするalwaysRefresh
属性とrefreshOnlyIfNewer
属性が用意されています。
... @Entity @Cache( alwaysRefresh=true, refreshOnlyIfNewer=true) public class Employee { ... }
org.eclipse.persistence.jpa.JpaCache
インタフェースには、キャッシュが最新でない場合に失効オブジェクトを削除するメソッドがいくつか含まれています。
evictAll
メソッドは、キャッシュ内のすべてのオブジェクトを無効にします。次に例を示します。
em.getEntityManagerFactory().getCache().evictAll();
特定のクラスを無効にするには、evict
メソッドを使用します。
em.getEntityManagerFactory().getCache().evict(MyClass);
clear
メソッドもキャッシュをリフレッシュしますが、キャッシュをクリアすると、キャッシュされているオブジェクトが使用中の場合に、オブジェクトIDの問題が発生する可能性があります。このメソッドは、キャッシュに保持されているオブジェクトに対する参照がアプリケーションにもう存在しないことがわかっている場合にのみ使用してください。
これまでに説明したメソッドは受動的で、次回にキャッシュにアクセスしたときにのみオブジェクトがリフレッシュされます。オブジェクトを能動的にリフレッシュするには、EntityManager.
refresh
メソッドを使用します。このメソッドは1回に1つのオブジェクトをリフレッシュします。
次のAPIでも、キャッシュがリフレッシュされます。
Session.refreshObject
DatabaseSession
およびUnitOfWork
: refreshAndLockObject
メソッド
ObjectLevelReadQuery
: refreshIdentityMapResult
およびrefreshRemoteIdentityMapResult
メソッド
ClassDescriptor
クラスにも、キャッシュをリフレッシュするメソッドが用意されています。
setShouldAlwaysRefreshCache
setShouldAlwaysRefreshCacheOnRemote
setShouldDisableCacheHits
setShouldDisableCacheHitsOnRemote
setShouldOnlyRefreshCacheIfNewerVersion
これらのメソッドはディスクリプタ修正メソッド内で使用します。次に例を示します。
public void addToDescriptor(ClassDescriptor descriptor) { descriptor.setShouldRefreshCacheOnRemote(true); descriptor.setShouldDisableCacheHitsOnRemote(true); }
最後に、問合せヒントは、キャッシュをリフレッシュする問合せをトリガーします。次に例を示します。
Query query = em.createQuery("Select e from Employee e"); query.setHint("javax.persistence.cache.storeMode", "REFRESH");
キャッシュ有効期限を設定した場合、指定時間が経過すると、キャッシュされたオブジェクト・インスタンスが無効になります。そのオブジェクトを使用しようとすると、最新バージョンのオブジェクトがデータ・ソースからリロードされます。有効期限は、アプリケーションが確実に最新データを使用するようにするのに便利です。ここでは、有効期限の様々な設定方法について説明します。
@cache
注釈には、特定の時間が経つとキャッシュ・インスタンスを削除するexpiry
およびexpiryTimeOfDay
属性が用意されています。expiry
属性は、ミリ秒単位で入力します。値を指定しない場合のデフォルト値は-1
で、有効期限が無効になっていることを示します。expiryTimeOfDay
属性は、org.eclipse.persistence.annotations.TimeOfDay
インタフェースのインスタンスです。次の例では、5分後にオブジェクトが期限切れになるように設定しています。
... @Entity @Cache(expiry=300000) public class Employee { ... }
ディスクリプタ・レベルで、ClassDescriptor.setCacheInvalidationPolicy
メソッドを使用して、CacheInvalidationPolicy
インスタンスを設定します。次の無効化ポリシーを使用できます。
DailyCacheInvalidationPolicy
: 毎日指定の時間に無効フラグがオブジェクトに自動的に設定されます。
NoExpiryCacheInvalidationPolicy
: IdentityMapAccessor.invalidateObject
メソッドを明示的にコールした場合にのみ、オブジェクトに無効フラグを設定できます。
TimeToLiveCacheInvalidationPolicy
: オブジェクトの読取りから指定時間が経過した後に、無効フラグがオブジェクトに自動的に設定されます。
オプティミスティック・ロックでは、あるユーザーが別のユーザーの作業を上書きできないようにします。ロックは、複数のサーバーまたは複数のアプリケーションが同じデータにアクセスする場合に重要で、単一サーバーとマルチサーバーの両方の環境に関係があります。マルチサーバー環境においては、アプリケーションがキャッシュ・リフレッシュやキャッシュ・コーディネーションを使用している場合であっても、やはりロックは必要です。ここでは、オプティミスティック・ロックの様々な設定方法について説明します。
@OptimisticLocking
注釈には、エンティティを更新または削除する際に使用するオプティミスティック・ロックのタイプを指定します。オプティミスティック・ロックは、@Entity
または@MappedSuperclass
注釈でサポートされています。次の属性を使用できます。
ALL_COLUMNS
: このポリシーでは、更新または削除を実行する際に、WHERE
句の表のすべてのフィールドが比較されます。
CHANGED_COLUMNS
: このポリシーでは、更新を実行する際に、WHERE
句の変更されたフィールドのみが比較されます。削除操作では、主キーのみが比較されます。
SELECTED_COLUMNS
: このポリシーでは、更新または削除を実行する際に、WHERE
句の選択されたフィールドが比較されます。指定されたフィールドはマップされている必要があり、主キーではない必要があります。
VERSION_COLUMN
: (デフォルト)このポリシーでは、単一のバージョン番号をオプティミスティック・ロックに使用できます。バージョン・フィールドはマップされている必要があり、主キーではない必要があります。親オブジェクトが私有する子オブジェクトのバージョン・フィールドが変更された場合に、その親オブジェクトのバージョン・フィールドが強制的に自動更新されるようにするには、cascaded
メソッドをtrue
に設定します。デフォルトでは、このメソッドはfalse
に設定されます。
ディスクリプタ・レベルで、ClassDescriptor.setOptimisticLockingPolicy
メソッドを使用してオプティミスティック・ロックを構成し、オプティミスティックなFieldsLockingPolicy
インスタンスを設定します。注釈と同様に、次のポリシーが含まれています。
AllFieldsLockingPolicy
: このポリシーでは、更新または削除を実行する際に、WHERE
句の表のすべてのフィールドが比較されます。
ChangedFieldsLockingPolicy
: このポリシーでは、更新を実行する際に、WHERE
句の変更されたフィールドのみが比較されます。削除操作では、主キーのみが比較されます。
SelectedFieldsLockingPolicy
: このポリシーでは、更新または削除を実行する際に、WHERE
句の選択されたフィールドが比較されます。指定されたフィールドはマップされている必要があり、主キーではない必要があります。
VersionLockingPolicy
: このポリシーを使用すれば、単一のバージョン番号をオプティミスティック・ロックに使用できます。親オブジェクトが私有する子オブジェクトのバージョン・フィールドが変更された場合に、その親オブジェクトのバージョン・フィールドが強制的に自動更新されるようにするには、VersionLockingPolicy.setIsCascaded
メソッドをtrue
に設定します。
TimestampLockingPolicy
: このポリシーを使用すれば、単一のバージョン・タイムスタンプをオプティミスティック・ロックに使用できます。
キャッシュ・コーディネーションは、分散セッション間で変更を同期します。すべてのアプリケーションに対してデータの整合性を維持するのが困難なアプリケーション・サーバー・クラスタでは、キャッシュ・コーディネーションが最も有効です。さらに、1つの環境内のサーバー数が増えるにつれて、キャッシュの整合性を保つのはますます難しくなります。
キャッシュ・コーディネーションは、クラスタ内のセッション(ServerSession
または永続性ユニット)間のトランザクション・オブジェクトの変更通知をブロードキャストすることにより動作します。アプリケーションが読取り中心で、複数の分散セッションで運用される同一アプリケーションによって変更が実行される場合に、キャッシュ・コーディネーションは最も有効です。
キャッシュ・コーディネーションを使用すると、失効データが大幅に減少しますが、失効データが発生する可能性を完全になくすことはできません。さらに、キャッシュ・コーディネーションにより、分散アーキテクチャで発生するオプティミスティック・ロック例外の数は減少し、アプリケーションで失敗するトランザクションや繰り返されるトランザクションの数も減少します。とはいえ、キャッシュ・コーディネーションを行っても、効果的なロック・ポリシーが不要になることはありません。現在のデータを確実に使用するには、オプティミスティック・ロックまたはペシミスティック・ロックとともにキャッシュ・コーディネーションを使用しますが、オプティミスティック・ロックの使用の方をお薦めします。
キャッシュ・コーディネーションはRMIおよびJMS上でサポートされており、persistence.xml
ファイルの永続性プロパティを使用して宣言的に構成することも、キャッシュ・コーディネーションのAPIを使用することもできます。永続性プロパティに一致するシステム・プロパティも使用できます。
キャッシュ・コーディネーションの詳細は、次を参照してください。
http://wiki.eclipse.org/Introduction_to_Cache_%28ELUG%29#Cache_Coordination_2
永続性プロパティを使用したJMSキャッシュ・コーディネーションの構成
次の例は、persistence.xml
ファイルでキャッシュ・コーディネーションを構成する方法を示しており、通知のブロードキャストにJMSを使用しています。JMSでは、プロトコルに加えて、JMSトピック、JNDI名およびトピック接続ファクトリのJNDI名を指定します。JMSトピックでは、JTAを有効にせず、永続性メッセージを指定しないでください。
<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" />
クラスタで実行されるアプリケーションでは、リソースを探して使用にはトピックで十分なので、URLは通常不要です。クラスタ外部で実行されるアプリケーションの場合は、URLが必要です。WebLogicサーバー・クラスタのURLの例を次に示します。
<property name="eclipselink.cache.coordination.jms.host" value="t3://myserver:7001/" />
必要な場合は、サーバーにアクセスするために必要なユーザー名とパスワードも設定できます。次に例を示します。
<property name="eclipselink.cache.coordination.jndi.user" value="user" />
<property name="eclipselink.cache.coordination.jndi.password" value="password" />
永続性プロパティを使用したRMIキャッシュ・コーディネーションの構成
次の例は、persistence.xml
ファイルでキャッシュ・コーディネーションを構成する方法を示しており、通知のブロードキャストにRMIを使用しています。
<property name="eclipselink.cache.coordination.protocol" value="rmi" />
クラスタで実行されるアプリケーションでは、JNDIがレプリケートされて各サーバーが相互のリスナーを参照できるので、URLは通常不要です。アプリケーションがクラスタ外部で実行される場合またはJNDIがレプリケートされない場合は、各サーバーでURLを指定する必要があります。これは、persistence.xml
ファイルを使用して行えますが、各サーバーに対して別のpersistence.xml
ファイル(たとえばJARまたはEAR)が必要になり、通常は望ましくありません。2番目のオプションとしては、キャッシュ・コーディネーションAPIを使用して、URLをプログラムで設定します。「キャッシュ・コーディネーションAPIを使用したキャッシュ・コーディネーションの構成」を参照してください。最後のオプションは、各アプリケーション・サーバーのシステム・プロパティとしてURLを設定する方法です。次の例では、システム・プロパティを使用してWebLogicサーバー・クラスタのURLを設定しています。
-Declipselink.cache.coordination.jms.host=t3://myserver:7001/
必要な場合は、サーバーにアクセスするために必要なユーザー名とパスワードも、次のように設定できます。
<property name="eclipselink.cache.coordination.jndi.user" value="user" /><property name="eclipselink.cache.coordination.jndi.password" value="password" />
RMIキャッシュ・コーディネーションでは、非同期または同期のブロードキャストを使用できます。デフォルトでは非同期になります。同期ブロードキャストでは、リクエストが返される前に、すべてのサーバーが確実に更新されます。次の例では、同期ブロードキャストを構成しています。
<property name="eclipselink.cache.coordination.propagate-asynchronously" value="false" />
同じサーバーまたはネットワーク上の複数のアプリケーションがキャッシュ・コーディネーションを使用する場合は、アプリケーションごとに別のチャネルを使用できます。次に例を示します。
<property name="eclipselink.cache.coordination.channel" value="EmployeeChannel" />
最後に、必要に応じて、サーバーが相互に検索できるようにするデフォルトのRMIマルチキャスト・ソケット・アドレスを変更します。次の例では、マルチキャスト設定を明示的に構成しています。
<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" />
キャッシュ・コーディネーションAPIを使用したキャッシュ・コーディネーションの構成
CommandManager
インタフェースを使用して、セッションのキャッシュ・コーディネーションをプログラムで構成します。次の例では、RMIキャッシュ構成を構成しています。
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()
キャッシュ同期の設定
キャッシュ同期では、オブジェクトの変更がセッション・メンバー間にブロードキャストされる方法を決定します。次の同期モードを使用できます。
SEND_OBJECT_CHANGES
: (デフォルト)このオプションでは、変更に関するデータを含む、変更されたオブジェクトのリストが送信されます。このデータは、受信キャッシュにマージされます。
INVALIDATE_CHANGED_OBJECTS
: このオプションでは、変更されたオブジェクトのIDリストが送信されます。受信キャッシュでは、データを変更するのではなく、オブジェクトが無効にされます。
SEND_NEW_OBJECTS_WITH_CHANGES
: このオプションは、トランザクションで新規作成されたオブジェクトも含まれる点以外はSEND_OBJECT_CHANGES
オプションと同じです。
NONE
: このオプションでは、キャッシュ・コーディネーションは行われません。
@cache
注釈のcoordinationType
属性は、同期モードを指定するために使用します。次に例を示します。
... @Entity @Cache(CacheCoordinationType.SEND_NEW_OBJECTS_CHANGES) public class Employee { ... }
ObjectChangeSet.setCacheSynchronizationType
メソッドを使用して、同期モードを設定することもできます。次に例を示します。
setCacheSynchronizationType() // passing in one of:
ClassDescriptor.DO_NOT_SEND_CHANGES
ClassDescriptor.INVALIDATE_CHANGED_OBJECTS
ClassDescriptor.SEND_NEW_OBJECTS_WITH_CHANGES
ClassDescriptor.SEND_OBJECT_CHANGES
TopLink JARファイルが、TopLinkアプリケーションがデプロイされているクラスタの各アプリケーション・サーバーのクラスパスに含まれていることを確認して、TopLinkを永続性プロバイダとして構成します。WebLogicサーバーおよびGlassFishでTopLinkを構成する詳細な手順は、第2章「WebLogic ServerでのTopLinkの使用」および第3章「GlassFish ServerでのTopLinkの使用」を参照してください。
TopLinkアプリケーションをホストする各アプリケーション・サーバーを含むアプリケーション・サーバー・クラスタを構成します。
WLSクラスタリングの詳細は、『Oracle Fusion Middleware Oracle WebLogic Serverクラスタの使用』を参照してください。
GlassFishのクラスタリングについては、次を参照してください。
http://download.oracle.com/docs/cd/E18930_01/html/821-2426/index.html
次の参照資料を使用できます。
詳細は、『Oracle Fusion Middleware Java API Reference for EclipseLink』の次のAPIを参照してください。
org.eclipse.persistence.annotations.OptimisticLocking
org.eclipse.persistence.annotations.Cache
org.eclipse.persistence.descriptors.ClassDescriptor
org.eclipse.persistence.sessions.coordination