8.12. Jakarta Enterprise Bean でクラスター化されたデータベースタイマー

JBoss EAP は、クラスター環境で Jakarta Enterprise Beans タイマーを永続化するための、クラスター化されたデータベースベースのタイマーをサポートします。クラスタリングはデータベースで提供されるため、短時間以内にタイマーの数がオフになる場合、パフォーマンスが向上します。refresh-interval を使用し、ejb3/service=timer-service/database-data-store コンポーネントの allow-execution 属性を使用すると、パフォーマンスを最適化することができます。

以下のように、クラスター化されていないモードでデータベースタイマーを使用することもできます。

  • refresh-interval0 に設定します。
  • すべてのノードに対して一意のパーティション名を指定するか、各ノードに別のデータベースを使用します。

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 ステートメントはデータベースによってカスタマイズされます。

      この属性を定義しない場合、サーバーは自動的にタイプを検出しようとします。現時点では、サポートされているタイプは postgresqlmysqloracledb2hsql、および 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 を設定していること。

手順

  1. wildfly.ejb.timer.refresh.enabledtrue を有効にする 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();
        }
    }
  2. Jakarta インターセプターを設定します。

    • Jakarta Interceptors は、ターゲットのステートレスまたはシングルトン Bean ビジネスメソッドに設定できます。wildfly.ejb.timer.refresh.enabledtrue に設定された場合、タイマーを返す前に 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...
          }