8.12. Jakarta Enterprise Bean でクラスター化されたデータベースタイマー
JBoss EAP は、クラスター環境で Jakarta Enterprise Beans タイマーを永続化するための、クラスター化されたデータベースベースのタイマーをサポートします。クラスタリングはデータベースで提供されるため、短時間以内にタイマーの数がオフになる場合、パフォーマンスが向上します。refresh-interval
を使用し、ejb3/service=timer-service/database-data-store
コンポーネントの allow-execution
属性を使用すると、パフォーマンスを最適化することができます。
以下のように、クラスター化されていないモードでデータベースタイマーを使用することもできます。
-
refresh-interval
を0
に設定します。 - すべてのノードに対して一意のパーティション名を指定するか、各ノードに別のデータベースを使用します。
Jakarta Enterprise Beans-clustered データベースタイマーは以下のように機能します。
- タイマーの実行が許可されるすべてのノードは、認識しているすべてのタイマーに対してタイムアウトをスケジュールします。
このタイムアウトが期限切れになると、各ノードでタイマーの状態を更新してタイマーをロックしようとします。
状態を更新するクエリーは、以下のクエリーに似ています。
UPDATE JBOSS_EJB_TIMER SET TIMER_STATE=? WHERE ID=? AND TIMER_STATE<>? AND NEXT_DATE=?;
トランザクションと READ_COMMITTED または SERIALIZABLE の分離モードのために、1 つのノードのみが行の更新で成功し、タイマーが実行するノードになります。
8.12.1. Jakarta Enterpise Beans でクラスター化されたタイマーの設定
データベースベースのタイマーストアを追加して、Jakarta Enterprise Beans-clustered タイマーを設定できます。
要件
- データベースは READ_COMMITTED または SERIALIZABLE 分離モードをサポートしている必要があります。
手順
データベースでサポートされるタイマーストアを作成します。
/subsystem=ejb3/service=timer-service/database-data-store=my-clustered-store:add(allow-execution=true, datasource-jndi-name="java:/MyDatasource", refresh-interval=60000, database="postgresql", partition="mypartition")
以下のパラメーターを設定します。
-
allow-execution
:true
に設定して、このノードがタイマーを実行できるようになります。false
に設定すると、JBoss EAP はこのノードのタイマーを別のノードで実行するデータベースに追加します。タイマー実行をクラスター内の複数のノードだけに制限すると、データベース全体の負荷が軽減されます。 -
datasource-jndi-name
: 使用するデータソース。 refresh-interval
: このノードは、他のノードが追加する新しいタイマーについてデータベースをチェックする前に経過する必要のある期間を設定します。値はミリ秒単位です。重要値を小さく設定すると、JBoss EAP はタイマーを高速に選択し、データベースの負荷が増えることを意味します。操作が失敗したか、
allow-execution
が false であるため、タイマーを追加したノードが実行できない場合は、ノードが更新されるまでこのタイマーは実行されません。Database
: 使用中のデータベースのタイプを定義します。一部の SQL ステートメントはデータベースによってカスタマイズされます。この属性を定義しない場合、サーバーは自動的にタイプを検出しようとします。現時点では、サポートされているタイプは
postgresql
、mysql
、oracle
、db2
、hsql
、およびh2
です。SQL は
modules/system/layers/base/org/jboss/as/ejb3/main/timers/timer-sql.properties
ファイルにあります。このファイルに新しいデータベース固有の SQL ステートメントを追加すると、実行される SQL を変更したり、新しいデータベースのサポートを追加したりできます。
-
partition
: このノードを所属させるパーティションの名前に設定します。同じパーティションのノードからタイマーのみがこのノードに表示されます。パフォーマンスを向上させるために、この属性を使用して大規模なクラスターを複数の小さなクラスターに分割します。
-
クラスターされていないタイマーにこのデータベースデータストアを使用するには、refresh-interval
をゼロに設定し、すべてのノードが一意のパーティション名を持つか、各ノードに異なるデータベースを使用していることを確認します。
8.12.2. デプロイメントでの Jakarta Enterprise Beans でクラスター化されたタイマーの使用
単一のデータストアをすべてのアプリケーションのデフォルトとして使用するか、各アプリケーションに特定のデータストアを使用できます。
要件
- Jakarta Enterprise Beans でクラスター化したデータベースベースのタイマーストアを設定している。
手順
単一のデータストアをすべてのアプリケーションにデフォルトとして使用するには、以下のように
ejb3
サブシステム内でdefault-data-store
を更新します。<timer-service thread-pool-name="timer" default-data-store="clustered-store"> <data-stores> <database-data-store name="clustered-store" datasource-jndi-name="java:jboss/datasources/ExampleDS" partition="timer"/> </data-stores> </timer-service>
特定のアプリケーションに別のデータストアを使用するには、タイマーデータストア名を
jboss-ejb3.xml
ファイルに設定します。<?xml version="1.1" encoding="UTF-8"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:timer="urn:timer-service:1.0" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" impl-version="2.0"> <assembly-descriptor> <timer:timer> <ejb-name>*</ejb-name> <timer:persistence-store-name>my-clustered-store</timer:persistence-store-name> </timer:timer> </assembly-descriptor> </jboss:ejb-jar>
8.12.3. Jakarta インターセプターを使用した Jakarta Enterprise Beans でクラスタータイマーの更新
タイマーをプログラムで更新するには、ビジネスメソッドで Jakarta インターセプターを設定し、refresh-interval
が期限切れになる前にタイマーを強制的に更新することができます。
クラスター化されたデプロイメントでは、複数のノードがデータストアを短時間で更新した場合に、インメモリータイマーの状態が同期されなくなります。
要件
- データベースでサポートされるクラスター化された Jakarta Enterprise Beans を設定していること。
手順
wildfly.ejb.timer.refresh.enabled
をtrue
を有効にする Jakarta インターセプターを実装します。import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptor; import javax.interceptor.InvocationContext; /** * An interceptor to enable programmatic timer refresh across multiple nodes. */ @Interceptor public class RefreshInterceptor { @AroundInvoke public Object intercept(InvocationContext context) throws Exception { context.getContextData().put("wildfly.ejb.timer.refresh.enabled", Boolean.TRUE); return context.proceed(); } }
Jakarta インターセプターを設定します。
Jakarta Interceptors は、ターゲットのステートレスまたはシングルトン Bean ビジネスメソッドに設定できます。
wildfly.ejb.timer.refresh.enabled
がtrue
に設定された場合、タイマーを返す前にTimerService.getAllTimers()
を呼び出すと、タイマーデータストアが更新されます。@Singleton public class RefreshBean1 ... { @Interceptors(RefreshInterceptor.class) public void businessMethod1() { ... // since wildfly.ejb.timer.refresh.enabled is set to true in interceptor for this business method, // calling timerService.getAllTimers() will first refresh from timer datastore before returning timers. final Collection<Timer> allTimers = timerService.getAllTimers(); ... } }
または、専用のビジネスメソッドを実装して、必要に応じてアプリケーションの他の部分が呼び出されるタイマーをプログラム的に更新できます。
@Interceptors(RefreshInterceptor.class) public List<Timer> getAllTimerInfoWithRefresh() { return timerService.getAllTimers(); } public void businessMethod1() { final LocalBusinessInterface businessObject = sessionContext.getBusinessObject(LocalBusinessInterface.class); businessObject.getAllTimerInfoWithRefresh(); // timer has been programmatically refreshed from datastore. // continue with other business logic... }