Sun Java System Application Server Enterprise Edition 8.2 パフォーマンスチューニングガイド

EJB のパフォーマンスチューニング

Application Server の高性能な EJB コンテナには、パフォーマンスに影響を及ぼす多数のパラメータがあります。個別の EJB コンポーネントにも、パフォーマンスに影響を及ぼすパラメータがあります。個別 EJB コンポーネントのパラメータの値は、EJB コンテナの同じパラメータの値に優先します。デフォルト値はシングルプロセッサのコンピュータシステム用に設計されています。それ以外のシステム構成に合わせた最適化を行うには、パラメータを変更します。

この節の内容は、次のとおりです。

目標

EJB パフォーマンスチューニングの目標は次のとおりです。

EJB コンポーネントの監視

EJB コンテナの監視を有効にした場合、Bean のプール設定とキャッシュ設定に基づいて、個別 Beans の統計を検証できます。

たとえば、次の監視コマンドにより、ステートフルセッション Bean の「Bean キャッシュ」を取得できます。

asadmin get --user admin --host e4800-241-a --port 4848 
-m specjcmp.application.SPECjAppServer.ejb-module.
   supplier_jar.stateful-session-bean.BuyerSes.bean-cache.*

監視出力のサンプルを次に示します。

resize-quantity = -1
 cache-misses = 0
 idle-timeout-in-seconds = 0
 num-passivations = 0
 cache-hits = 59
 num-passivation-errors = 0
 total-beans-in-cache = 59
 num-expired-sessions-removed = 0
 max-beans-in-cache = 4096
 num-passivation-success = 0

次の監視コマンドは、エンティティー Bean の Bean プール統計を提供します。

asadmin get --user admin --host e4800-241-a --port 4848 
-m specjcmp.application.SPECjAppServer.ejb-module.
   supplier_jar.stateful-entity-bean.ItemEnt.bean-pool.* 
idle-timeout-in-seconds = 0 
steady-pool-size = 0 
total-beans-destroyed = 0 
num-threads-waiting = 0 
num-beans-in-pool = 54 
max-pool-size = 2147483647 
pool-resize-quantity = 0 
total-beans-created = 255

次の監視コマンドは、ステートレス Bean の Bean プール統計を提供します。

asadmin get --user admin --host e4800-241-a --port 4848 
-m test.application.testEjbMon.ejb-module.slsb.stateless-session-bean.slsb.bean-pool.*
idle-timeout-in-seconds = 200
steady-pool-size = 32
total-beans-destroyed = 12
num-threads-waiting = 0
num-beans-in-pool = 4
max-pool-size = 1024
pool-resize-quantity = 12
total-beans-created = 42

Bean のチューニングでは、一定の期間を区切って、対象となる Bean のキャッシュおよびプールの動作をグラフ化します。

あまりに多くのパッシベーションが発生しており、JVM ヒープは比較的小さいままである場合は、max-cache-size または cache-idle-timeout-in-seconds の値を大きくすることができます。ガベージコレクションがあまりにも頻繁に発生しており、プールサイズが増加しているが、キャッシュヒット率が低い場合、pool-idle-timeout-in-seconds の値を小さくしてインスタンスを破棄することができます。


注 –

max-pool-size にゼロ (0) を指定すると、プールがアンバインドされます。プールされた Beans は、pool-idle-timeout-in-seconds に短い間隔を指定することによって削除される場合を除き、メモリー内に残ります。本番システムについては、アンバインドされたものとしてプールを指定することは推奨されません。


個別 EJB コンポーネントの監視

Bean 内のすべてのメソッドについてメソッド呼び出し統計を収集するには、次のコマンドを使用します。

asadmin get -m monitorableObject.*

monitorableObject は、次に示すような監視可能オブジェクトの階層からの完全指定 ID です。

serverInstance.application.applicationName.ejb-module.moduleName

moduleName は、モジュール x.jar に対しては x_jar です。

スタンドアロン Beans については、次のパターンを使用します。

serverInstance.application.applicationName.standalone-ejb-module.moduleName

指定可能な ID は、ejb-module と同じです。

たとえば、エンティティー Bean 内のメソッドについての統計を得るには、次のコマンドを使用します。

asadmin get -m serverInstance.application.appName.ejb-module.moduleName
.entity-bean.beanName.bean-method.methodName.*

監視可能なオブジェクト (アプリケーション、モジュール、Beans、およびメソッド) およびオブジェクト属性を検索するには、管理コンソールを使用します。詳細は、『Sun Java System Application Server Enterprise Edition 8.2 管理ガイド』の第 16 章「コンポーネントとサービスの監視」を参照してください。あるいは、asadmin list コマンドを使用します。詳細は、list(1) を参照してください。

ステートフルセッション Bean のパッシベーションについての統計を得るには、次のコマンドを使用します。

asadmin get -m serverInstance.application.appName.ejb-module.moduleName
.stateful-session-bean.beanName.bean-cache.*

返された属性値から、次のコマンドを使用します。

num-passivationsnum-passivation-errorsnum-passivation-success

一般的な指針

次の指針に従うことによって、EJB コンポーネントのパフォーマンスを改善できます。アプリケーションを多数の EJB コンポーネントに分解すると、オーバーヘッドが発生し、パフォーマンスが低下する可能性もあることに留意してください。EJB コンポーネントは単なる Java オブジェクトではありません。EJB コンポーネントは、プロパティーとメソッドに加えて、リモート呼び出しインタフェース、セキュリティー、およびトランザクションのセマンティクスを持つコンポーネントです。

パフォーマンスの高い Beans を使用する

アプリケーションの全体的なパフォーマンスを改善するには、できるだけパフォーマンスの高い Beans を使用します。詳細は、「特定タイプの EJB コンポーネントのチューニングのヒント」を参照してください。

EJB コンポーネントのタイプの一覧を、もっともパフォーマンスの高いものから順に示すと次のようになります。

  1. ステートレスセッション Beans およびメッセージ駆動型 Beans

  2. ステートフルセッション Beans

  3. 読み取り専用として設定されたコンテナ管理による持続性 (CMP) エンティティー Beans

  4. 読み取り専用として設定された Bean 管理による持続性 (BMP) エンティティー Beans

  5. CMP Beans

  6. BMP Beans

キャッシュの使用

キャッシュを適切に使用することで、パフォーマンスを大きく改善できます。次に例を示します。

アプリケーションスタブの使用

EJB アプリケーションで必要なスタブクラスは、実行時に EJB クライアントで必要になったときに動的に生成されます。これは、リモート EJB コンポーネントを使用してアプリケーションを配備するときに、スタブを生成したりクライアントの JAR ファイルを取得したりする必要がないことを意味します。--retrieve オプションは配備を高速化しますが、アプリケーションを配備するときにこのオプションを指定する必要はなくなりました。

CosNaming サービスを直接使用する (これは推奨される構成ではない) 従来のリッチクライアントアプリケーションがある場合、RMIC を使用して、アプリケーションに対してスタブを明示的に生成する必要があります。詳細は、『Sun Java System Application Server Enterprise Edition 8.2 トラブルシューティングガイド』を参照してください。

不必要なステートフルセッション Beans の削除

不要なステートフルセッション Bean を削除することにより、ディスク操作が必要な、その Beans のパッシベーションを回避できます。

キャッシュとプールのチューニングのヒント

EJB キャッシュとプールを使用してパフォーマンスを改善するには、次のヒントに従います。

ローカルインタフェースとリモートインタフェースの使用

この節では、ローカルおよびリモートのクライアントによって EJB コンポーネントが使用されるときの考慮事項について説明します。

ローカルインタフェースを優先する

EJB コンポーネントは、リモートインタフェースとローカルインタフェースを持つことができます。Bean と同じアプリケーションサーバーインスタンスに配置されていないクライアント (リモートクライアント) は、リモートインタフェースを使用して Bean にアクセスします。リモートインタフェースの呼び出しには、引数を整列化し、整列化したデータをネットワーク経由で転送し、引数を非整列化し、受信側の端で振り分ける一連の処理が必要です。そのため、リモートインタフェースの使用には大きなオーバーヘッドが伴います。

EJB コンポーネントがローカルインタフェースを持つ場合、同じアプリケーションサーバーインスタンス内のローカルクライアントは、そのインタフェースをリモートインタフェースの代わりに使用できます。引数の整列化、転送、および非整列化が不要になるため、ローカルインタフェースを使用するほうが効率的です。

Bean がローカルクライアントのみによって使用される予定の場合、ローカルインタフェースのみを提供する意味があります。一方、Bean を位置独立にする予定の場合は、リモートインタフェースとクライアントインタフェースの両方を提供することをお勧めします。これにより、リモートクライアントはリモートインタフェースを使用し、ローカルクライアントは効率性のためにローカルインタフェースを使用できるようになります。

参照渡しのセマンティクスの使用

Application Server のデフォルトでは、Bean のリモートインタフェースの呼び出しには、両者が同じ位置にある場合でも「値渡し」のセマンティクスが使用されます。値渡しのセマンティクスを使用するクライアントは、EJB コンポーネントに引数を渡す前に引数をコピーする必要があるため、これは負荷の大きい処理になる可能性があります。

ただし、ローカルクライアントは「参照渡し」セマンティクスを使用でき、その場合、渡されるオブジェクトをローカルインタフェースとリモートインタフェースが共有できます。しかしこれは、引数オブジェクトを共有可能にするためには、引数オブジェクトを適切に実装する必要があることを意味します。一般的には、可能な場合には参照渡しのセマンティクスを使用するほうが効率的です。

リモートインタフェースとローカルインタフェースを適切に使用することで、クライアントは EJB コンポーネントに効率的にアクセスできます。ローカルクライアントは参照渡しセマンティクスでローカルインタフェースを使用する一方で、リモートクライアントは値渡しセマンティクスでリモートインタフェースを使用します。

ただし、一部のインスタンスでは、次の例のような場合にローカルインタフェースを使用できない可能性があります。

このようなケースのために、Application Server では、同じ位置に存在する EJB コンポーネントのリモートインタフェースに参照によって引数を渡すためにクライアントが使用できる参照渡しオプションが用意されています。

参照渡しオプションは、アプリケーション全体または単一の EJB コンポーネントを対象に指定できます。アプリケーションレベルで指定された場合、アプリケーション内のすべての Beans は、そのリモートインタフェースに引数を渡すときに参照渡しセマンティクスを使用します。Bean レベルで指定された場合、Bean のリモートインタフェースへのすべての呼び出しは参照渡しセマンティクスを使用します。参照渡しフラグの詳細は、『Sun Java System Application Server Enterprise Edition 8.2 Developer’s Guide』「Value Added Features」を参照してください。

EJB コンポーネントが参照渡しセマンティクスを使用することを指定するには、配備記述子 sun-ejb-jar.xml で次のタグを使用します。

<pass-by-reference>true</pass-by-reference>.

これにより、EJB コンポーネントのメソッドが呼び出されるときの引数のコピーと、メソッドが戻るときの結果のコピーが回避されます。ただし、呼び出しの間に別のソースによってデータが変更されると問題が発生します。

EJB トランザクションのパフォーマンスの改善

この節では、トランザクションを使用するときのパフォーマンスを改善するためのヒントを示します。

コンテナ管理によるトランザクションを使用する

コンテナ管理によるトランザクションは、整合性の面で望ましく、パフォーマンスにも優れています。

ユーザー入力時間を含めない

リソースが不必要に長期間保持されることを避けるために、トランザクションにはユーザーの入力または思考時間を含めないことをお勧めします。

非トランザクションメソッドを識別する

セッション EJB コンポーネントの非トランザクションメソッドを、トランザクション属性 NotSupported または Never を使用して宣言します。これらの属性は、配備記述子ファイル ejb-jar.xml にあります。トランザクションはデータベース行をロックするため、持続時間をできるだけ短くします。

長いトランザクション連鎖に TX_REQUIRED を使用する

非常に長いトランザクション連鎖については、トランザクション属性 TX_REQUIRED を使用します。呼び出し連鎖で EJB メソッドを保証するには、同じトランザクションを使用します。

もっともコストの低いデータベースロックを使用する

任意のトランザクションと整合性のあるデータベースから使用可能なロックのうち、もっともコストが低いものを使用します。各メソッド呼び出しのあとでなく、トランザクションが完了したあとにデータをコミットします。

XA 対応データソースを必要なときにのみ使用する

複数のデータベースリソース、コネクタリソース、または JMS リソースが 1 つのトランザクションに関係するとき、分散トランザクションまたはグローバルトランザクションを実行する必要があります。これには、XA 対応のリソースマネージャーおよびデータソースが必要です。XA 対応のデータソースは、2 つ以上のデータソースがトランザクションに関係する場合にのみ使用します。データベースがいくつかの分散トランザクションに参加するが、ほとんどの参加先がローカルトランザクションまたは単一データベーストランザクションである場合、2 つの独立した JDBC リソースを登録し、アプリケーション内で適切なリソースを使用することをお勧めします。

JDBC リソースを 1 フェーズコミットリソースとして設定する

複数のリソースが関係しているトランザクションのパフォーマンスを改善するために、Application Server では最終エージェント最適化 (LAO) を使用します。これにより、分散トランザクション内のリソースのうちの 1 つを、1 フェーズコミット (1PC) リソースとして設定することが可能になります。JDBC リソースに関しては、複数リソーストランザクションのオーバーヘッドのほうがメッセージキューよりもずっと大きいため、LAO により、1 つの JDBC リソースと 1 つ以上のメッセージキューが関係する分散トランザクションのパフォーマンスが大きく改善されます。LAO を利用するには、JDBC リソースを 1PC リソースとして設定します。JMS リソースを設定するために、特別なことを行う必要はありません。

複数の JDBC リソースが関係するグローバルトランザクションでも LAO によってパフォーマンスが改善されますが、改善の度合いは 1 つの JDBC リソースの場合には及びません。この状況では、JDBC リソースのうち 1 つを 1 PC として設定し、その他すべてを XA として設定することをお勧めします。

もっとも負荷の小さいトランザクション属性を使用する

EJB 配備記述子ファイル (ejb-jar.xml) で、次のトランザクション属性を設定します。オプションの一覧は、もっともパフォーマンスの高いものから低いものの順に並んでいます。パフォーマンスを改善するには、アプリケーションに必要な機能性を提供する属性の中でもっとも負荷の小さいものを選択します。

  1. NEVER

  2. TX_NOTSUPPORTED

  3. TX_MANDATORY

  4. TX_SUPPORTS

  5. TX_REQUIRED

  6. TX_REQUIRESNEW

特殊な手法の使用

この節では、特殊なパフォーマンス強化手法について説明します。ここで紹介する手法は、バージョン整合性と要求のパーティション分割の 2 つです。

バージョン整合性

データベース内のデータの完全性を保護しながらパフォーマンスを改善するには、「バージョン整合性」を使用します。アプリケーションサーバーは EJB コンポーネントの複数のコピーを同時に使用できるので、同時アクセスを通じて EJB コンポーネントが破壊された状態になる可能性があります。

破壊を防ぐ標準的な方法は、特定の Bean に関連付けられたデータベース行をロックすることです。これは、2 つの同時トランザクションによって Bean がアクセスされることを防ぎ、結果的にデータを保護します。ただし、この方法は実質的にすべての EJB アクセスを直列化するため、パフォーマンスも低下させます。

バージョン整合性は、EJB データの完全性を保護するためのもう 1 つのアプローチです。バージョン整合性を使用するには、バージョン番号として使用するデータベース内の列を指定します。その場合、EJB ライフサイクルの進行は次のようになります。

2 回目以降の Bean の使用では、ejbLoad() メソッドがその初期データ (バージョン番号を含む) を内部キャッシュからロードすることを除いて、動作は同様です。これにより、データベースへのアクセスが省略されます。ejbStore() メソッドが呼び出されると、トランザクションで正しいデータが使用されたことを保証するためにバージョン番号がチェックされます。

バージョンが一致していると、2 つのトランザクションが同じ EJB コンポーネントを同時に使用できるため、めったに変更されない EJB コンポーネントがある場合には効果的な手法です。どちらのトランザクションもデータを変更しないため、両方のトランザクションの終了時にバージョン番号は不変のままであり、トランザクションは両方とも成功します。ただし、この時点ではトランザクションの並列実行が可能です。2 つのトランザクションが同じ EJB コンポーネントを変更する場合、一方が成功し、もう一方は失敗して、新しい値を使用して再試行することができます。これは、再試行の頻度が一定以下であれば、EJB コンポーネントへのすべてのアクセスを直列化するよりも高速です (ただし、再試行操作を実行するための新しいアプリケーションロジックを準備する必要がある)。

バージョン整合性を使用するには、特定のテーブル用のデータベーススキーマに、バージョンを格納できる列を含める必要があります。その後、特定の Bean に対する配備記述子 sun-cmp-mapping.xml でそのテーブルを指定します。

<entity-mapping>
    <cmp-field-mapping>
        ...
    </cmp-field-mapping>
    <consistency>
        <check-version-of-accessed-instances>
            <column-name>OrderTable.VC_VERSION_NUMBER</column-name>
        </check-version-of-accessed-instances>
    </consistency>
</entity-mapping>

加えて、指定されたテーブル内のデータが変更されたときにバージョン列を自動的に更新するためのトリガーを、データベースに対して確立する必要があります。Application Server では、そのようなトリガーはバージョン整合性を使用する必要があります。そのようなトリガーを定義することにより、EJB データを変更する外部アプリケーションが、進行中の EJB トランザクションと競合しないことも保証されます。

たとえば、次の DDL は、Order テーブルのトリガーを作成する方法を例示します。

CREATE TRIGGER OrderTrigger
  BEFORE UPDATE ON OrderTable
  FOR EACH ROW
  WHEN (new.VC_VERSION_NUMBER = old.VC_VERSION_NUMBER)
  DECLARE
  BEGIN
    :NEW.VC_VERSION_NUMBER := :OLD.VC_VERSION_NUMBER + 1;
  END;

パーティション分割要求

「パーティション分割要求」では、要求の優先度を EJB コンポーネントに割り当てることができます。これにより、特定の EJB コンポーネントを、ほかよりも高い優先度で実行させる柔軟性が得られます。

要求優先度が割り当てられた EJB コンポーネントは、その要求 (サービス) を、割り当てられたスレッドプールの内部で実行させます。スレッドプールをその実行に割り当てることにより、EJB コンポーネントはほかの保留中の要求から独立して実行できます。要約すると、要求のパーティション分割により、サービスごとに異なるレベルの優先度が割り当てられたサービスレベルアグリーメントを満たすことが可能になります。

パーティション分割要求は、リモートインタフェースを実装するリモート EJB コンポーネントのみに適用されます。ローカル EJB コンポーネントは、その呼び出しスレッド内で実行されます (たとえば、サーブレットがローカル Bean を呼び出すと、サーブレットのスレッド上でローカル Bean 呼び出しが発生する)。

Procedureパーティション分割要求を有効にする

  1. 管理コンソールを使用して、EJB 実行用の追加スレッドプールを設定します。

  2. Application Server の ORB に、追加スレッドプールの ID を追加します。

    これは、domain.xml ファイルを編集することによって、または管理コンソールを使用して行うことができます。

    たとえば、 priority-1 および priority-2 という名前のスレッドプールを有効にするには、<orb> 要素を次のように編集します。


    <orb max-connections="1024" message-fragment-size="1024"
        use-thread-pool-ids="thread-pool-1,priority-1,priority-2">       
  3. EJB コンポーネントの配備記述子 sun-ejb-jar.xmluse-thread-pool-id 要素に、スレッドプールの ID を含めます。

    たとえば、次に示す sun-ejb-jar.xml は、「TheGreeter」という名前の EJB コンポーネントの配備記述子であり、priority-2 という名前のスレッドプールに割り当てられます。

    <sun-ejb-jar> 
      <enterprise-beans> 
        <unique-id>1</unique-id> 
        <ejb> 
          <ejb-name>TheGreeter</ejb-name> 
          <jndi-name>greeter</jndi-name> 
          <use-thread-pool-id>priority-1</use-thread-pool-id> 
        </ejb> 
      </enterprise-beans> 
    </sun-ejb-jar>
  4. Application Server を再起動します。

特定タイプの EJB コンポーネントのチューニングのヒント

この節では、特定のタイプの EJB コンポーネントのチューニングに関するヒントを示します。

エンティティー Beans

特定のエンティティー Bean の使用状況に応じて、max-cache-size を調整します。これにより、使用頻度の低い Beans (たとえば、作成されたがトランザクションの終了後は使用されることのない注文) はあまりキャッシュされず、頻繁に使用される Beans (たとえば、きわめて頻繁に参照される在庫内の品目) は数多くキャッシュされるようにします。

ステートフルセッション Beans

ステートフルセッション Bean がユーザーを表すとき、Beans の妥当な max-cache-size は、アプリケーションサーバープロセス上の同時ユーザーの予測数です。この値が (ユーザーの安定負荷との比較で) 小さすぎると、Beans は頻繁に非活性化および活性化され、ディスク I/O に加えて CPU 負荷がかかる直列化および直列化復元によって応答時間への悪影響が生じます。

チューニングにとって重要なもう 1 つの変数は、cache-idle-timeout-in-seconds です。cache-idle-timeout-in-seconds の定期的な間隔で、cache-idle-timeout-in-seconds の時間よりも長くアクセスがなかったキャッシュ内のすべての Beans が非活性化されます。HTTP セッションのタイムアウトと同様に、removal-timeout-in-seconds に指定された時間だけアクセスがなかった Bean は削除されます。非活性化された Beans は、直列化された形式でディスク上に格納されます。非活性化された多数の Beans は、多数のファイルでディスクシステム上の領域を占有するだけでなく、呼び出しの前にセッション状態を直列化復元しなければならないことが原因で応答時間を低下させる可能性もあります。

必要時にのみチェックポイントを設定する

高可用性モードで、ステートフルセッション Beans を使用しているときは、Bean の状態を大きく変更するメソッドのみにチェックポイントを設定することを検討してください。これにより、Bean の状態を持続ストアにチェックポイント設定しなければならない回数が減少します。

ステートレスセッション Beans

ステートレスセッション Beans は、エンティティー Beans やステートフルセッション Beans よりも高速にプールされます。steady-pool-sizepool-resize-quantity 、および max-pool-size の有効な値は、これらのタイプの Beans に対して調整可能なパラメータのうちもっとも多く使用するものです。プールを事前生成したい場合は、steady-pool-size を 0 よりも大きい値に設定します。この設定により、コンテナが発生するとき、コンテナは Beans の steady-pool-size の数値を使用してプールを作成します。プールを事前生成することにより、メソッド呼び出しの間のオブジェクト作成時間を不要にすることができます。

steady-pool size をあまり大きい値に設定すると、メモリーの不要な肥大の原因となり、結果的にガベージコレクションの時間が長くなる可能性があります。pool-resize-quantity は、プールの伸長率と減衰率を決定します。減衰の動作は指数関数的な減衰に似たものになるため、このパラメータは小さい値に設定することをお勧めします。max-pool-size の設定値を小さくすると、現在のプールサイズが max-pool-size を超える場合にインスタンスがプールから破棄される過程で、過度のオブジェクト破棄 (および、その結果として過度のオブジェクト作成) の原因となる可能性があります。

読み取り専用エンティティー Beans

読み取り専用エンティティー Beans は、データベースからデータをキャッシュします。Application Server は、Bean 管理による持続性 (BMP) とコンテナ管理による持続性 (CMP) の両方を使用する読み取り専用 Beans をサポートします。2 つのタイプのうち、パフォーマンス面では CMP 読み取り専用 Beans のほうがずっと優れています。EJB ライフサイクルで、EJB コンテナは読み取り専用 Bean の ejbLoad() メソッドを 1 回呼び出します。コンテナはそのデータから EJB コンポーネントの複数のコピーを作成し、Beans はデータベースを更新しないため、コンテナが ejbStore() メソッドを呼び出すことはありません。これにより、これらの Beans に関係するデータベーストラフィックが大幅に減少します。

データベースを更新することのない Bean が存在する場合は、パフォーマンスを改善するために、その Bean の代わりに読み取り専用 Bean を使用してください。読み取り専用 Bean は次のいずれかの場合に適切です。

たとえば、アプリケーションにおいて、ベストセラー書籍のリストを表現するために読み取り専用 Bean を使用できます。リストはデータベース内で (完全に別の Bean から) 変化する場合がありますが、アプリケーションでその変更をただちに反映する必要はありません。

読み取り専用 Bean の ejbLoad() メソッドの処理は、CMP Beans と BMP Beans で異なります。CMP Beans の場合、EJB コンテナはデータベースからデータをロードするために ejbLoad() を一度だけ呼び出します。Bean の 2 回目以降の使用ではそのデータをコピーするだけです。BMP Beans の場合、EJB コンテナはトランザクションで Bean が最初に使用されたときに ejbLoad() を呼び出します。トランザクション内部で次回以降この Bean を使用する場合、同じ値が使用されます。Bean が使用されるたびに、コンテナはトランザクションの内部で実行されない BMP Bean の ejbLoad() を呼び出します。したがって、読み取り専用 BMP Bean は引き続き、数回のデータベースの呼び出しを行います。

読み取り専用 Bean を作成するには、EJB 配備記述子 sun-ejb-jar.xml に次の内容を追加します。

<is-read-only-bean>true</is-read-only-bean>
<refresh-period-in-seconds>600</refresh-period-in-seconds>

更新期間

読み取り専用 Beans のチューニングにとって重要なパラメータに更新期間があります。これは、配備記述子の refresh-period-in-seconds エンティティーによって表されます。CMP Beans では、Bean への初回アクセス時に Bean の状態がロードされます。更新期間が経過したあとの最初のアクセスで、データベースからデータを再ロードします。それ以降の Bean の使用ではすべて、(次の更新期間が経過するまでの間) 新しく更新されたデータを使用します。BMP Beans では、既存のトランザクション内部の ejbLoad() メソッドは、更新期間が経過しない限りキャッシュされたデータを使用します (経過した場合、コンテナは ejbLoad() を再び呼び出す)。

このパラメータでは、EJB コンポーネントが、それが表すデータベース値の「スナップショット」を定期的に更新することを有効にします。更新期間が 0 以下の場合、Bean がデータベースから更新されることはありません (更新期間を指定しない場合のデフォルトの動作)。

コンテナ管理による関係 (CMR) Beans の先取り

コンテナ管理による関係 (CMR) がアプリケーションに存在する場合、ある Bean をロードすると、それに関連するすべての Beans がロードされます。CMR の典型的な例は、注文と注文明細の関係です。1 つの「Order」EJB コンポーネントと、それに関連する複数の「OrderLine」EJB コンポーネントが存在します。Application Server の以前のリリースでは、これらすべての Beans を使用するためには、複数のデータベースクエリーが必要でした。「Order」Bean に対するクエリーと、関係内の各「OrderLine」Beans に対するクエリーです。

一般に、1 つの Bean に n 個の関係がある場合、Bean のすべてのデータを使用すると n+1 回のデータベースアクセスが必要になります。CMR 先取りを使用して、Bean とそれに関係するすべての Beans のすべてのデータを、1 回のデータベースアクセスで取得します。

たとえば、ejb-jar.xml ファイルで次の関係が定義されているとします。

<relationships>
    <ejb-relation>
        <description>Order-OrderLine</description>
        <ejb-relation-name>Order-OrderLine</ejb-relation-name>
        <ejb-relationship-role>
            <ejb-relationship-role-name>
                Order-has-N-OrderLines
            </ejb-relationship-role-name>
            <multiplicity>One</multiplicity>
            <relationship-role-source>
                <ejb-name>OrderEJB</ejb-name>
            </relationship-role-source>
            <cmr-field>
                <cmr-field-name>orderLines</cmr-field-name>
                <cmr-field-type>java.util.Collection</cmr-field-type>
            </cmr-field>
        </ejb-relationship-role>
    </ejb-relation>
</relationships>

特定の Order がロードされるとき、アプリケーションの sun-cmp-mapping.xml ファイルに次の内容を追加することにより、それと関係を持つ OrderLine をロードできます。

<entity-mapping>
    <ejb-name>Order</ejb-name>
    <table-name>...</table-name>
    <cmp-field-mapping>...</cmp-field-mapping>
    <cmr-field-mapping>
        <cmr-field-name>orderLines</cmr-field-name>
        <column-pair>
            <column-name>OrderTable.OrderID</column-name>
            <column-name>OrderLineTable.OrderLine_OrderID</column-name>
        </column-pair>
        <fetched-with>
            <default>
        </fetched-with>
    </cmr-field-mapping>
</entity-mappping>

Order が取得されると、CMP エンジンは SQL を発行し、次の WHERE 句を持つ SELECT 文によって、すべての関係する OrderLine を取得します。

OrderTable.OrderID = OrderLineTable.OrderLine_OrderID

この句は外部結合を示します。これらの OrderLine は先取りされます。

一般的に、先取りを利用するとデータベースアクセスの数が減少するため、パフォーマンスが改善されます。ただし、ビジネスロジックでその OrderLine を参照することなく Order を頻繁に使用する場合、先取りはパフォーマンス面でのペナルティーとなる可能性があります。具体的には、実際には必要でない OrderLine を先取りする労力をシステムが費やしたことになります。

特定の検索メソッドについては、先取りを避けます。これにより、しばしばそのペナルティーを回避できます。たとえば、「Order」Bean に 2 つの検索メソッドがあると仮定します。OrderLine を使用する findByPrimaryKey メソッドと、注文情報のみを返し OrderLine を使用しない findByCustomerId メソッドです。OrderLine に対して CMR 先取りを有効にした場合、両方の検索メソッドが OrderLine を先取りします。ただし、配備記述子 sun-ejb-jar.xml に次の情報を含めることにより、findByCustomerId メソッドでの先取りを無効にすることができます。

<ejb>
    <ejb-name>OrderBean</ejb-name>
    ...
    <cmp>
        <prefetch-disabled>
            <query-method>
                <method-name>findByCustomerId</method-name>
            </query-method>
        </prefetch-disabled>
     </cmp>
</ejb>

JDBC とデータベースアクセス

こごては、データベースアクセスのパフォーマンスを改善するためのヒントを示します。

JDBC を直接使用する

大規模データベースの検索のように大量のデータを扱うときは、エンティティー EJB コンポーネントを使用する代わりに JDBC を直接使用します。

ビジネスロジックをエンティティー EJB コンポーネントにカプセル化する

ビジネスロジックを、そのロジックの処理に必要なデータを保持するエンティティー EJB コンポーネントと結合します。

接続をクローズする

接続がプールに戻されることを保証するために、使用後は必ず接続をクローズします。

データベーストランザクション遮断レベルを最小にする

別の遮断レベルでもアプリケーションが正しく動作し、高いパフォーマンスを発揮するという確証がある場合を除き、setTransactionIsolationLevel() を呼び出すことはせず、JDBC ドライバによって提供されるデフォルトの遮断レベルを使用します。

適切な状況では、データベーストランザクション遮断レベルを下げます。遮断レベルを下げると、データベース層での作業量が減少し、アプリケーションパフォーマンスの向上につながる場合があります。ただし、これはデータベーステーブルの使用パターンを入念に分析したあとで行う必要があります。

データベーストランザクション遮断レベルの設定は、管理コンソールで「リソース」、「JDBC」、「接続プール」の順に選択して「<プール名>」ページで行います。JDBC 接続プールのチューニングの詳細は、「JDBC 接続プールの設定」を参照してください。

メッセージ駆動型 Beans のチューニング

この節では、JMS とメッセージ駆動型 Beans (MDB) を使用しているときにパフォーマンスを改善するためのヒントを示します。

getConnection() を使用する

JMS 接続は接続プールから供給されます。これは、Queue 接続ファクトリに対する getConnection() の呼び出しが高速であることを意味します。


注意 – 注意 –

8.1 よりも前のバージョンでは、サーブレットまたは EJB コンポーネントとの接続の再利用が可能でした。つまり、サーブレットはその init() メソッド内で getConnection() を呼び出し、その後連続的に、各サーブレット呼び出しに対して getSession() を呼び出すことができました。グローバルトランザクションの内部で JMS を使用する場合、そのような呼び出しは機能しなくなりました。アプリケーションは各接続に対し getSession() を一度だけ呼び出すことができます。その後、接続をクローズする必要があります (これは実際には接続をクローズするのではなく、接続をプールに戻すだけである)。これは、移植性のある J2EE 1.4 アプリケーションの一般的な特徴です。Sun Java System Application Server では、以前の (J2EE 1.3 ベースの) アプリケーションサーバーでは施行されていなかったその制約を施行します。


メッセージ駆動型 Bean のプールサイズを調整する

メッセージ駆動型 Beans のコンテナは、エンティティー Beans およびセッション Beans のコンテナとは異なります。MDB コンテナでは、セッションおよびスレッドが MDB プール内の Beans に添付されます。この設計により、メッセージ駆動型要求をコンテナ内で実行するためのスレッドをプールできるようになっています。

メッセージ駆動型 Bean のプールサイズを調整し、メッセージの同時処理数を最適化します。サーバーのすべてのパラメータに基づいて、MDB プールのサイズを設定します (ほかのアプリケーションを考慮に入れる)。たとえば、500 を超える値は一般的には大きすぎます。

MDB プールの設定は、管理コンソールで「設定」、「<設定名>」、「EJB コンテナ」(「MDB 設定」) の順に選択して行うことができます。また、次のように asadmin を使用して設定することもできます。

asadmin set server.mdb-container.max-pool-size = value

Bean 固有リソースをキャッシュする

setMesssageDrivenContext() または ejbCreate() メソッドを使用して、Bean 固有リソースをキャッシュし、ejbRemove() メソッドでそれらのリソースを解放します。

JMS 接続の使用を制限する

JMS 接続を使用するアプリケーションを設計するときは必ず、接続をプールするか、または複数のセッションで同じ接続を使用することによって、使用する接続数を抑える方法論を使用します。

JMS 接続は 2 つのスレッドを使用し、セッションはそれぞれ 1 つのスレッドを使用します。これらのスレッドはプールから取得されたものではなく、結果のオブジェクトはプールされないため、利用負荷の高い期間中はメモリー不足が発生する可能性があります。

1 つの回避方法は、createTopicConnection をサーブレットの init に移動することです。

必ず、セッションを明示的にクローズしてください。クローズしないとセッションはオープン状態のままであり、リソースを解放しません。