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

特定タイプの 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>