Sun ONE ロゴ     前へ      目次      索引      次へ     
Sun ONE Application Server 7 パフォーマンスチューニングガイド



アプリケーションのチューニング

次に、最大のパフォーマンスを得るためのアプリケーションチューニングについて詳しく説明します。優れた性能を持つ Java アプリケーションおよび J2EE アプリケーションの記述方法についての完全な説明は、このマニュアルでは取り扱いません。

次の項目について説明します。

Java プログラミングのガイドライン

ここでは、Java プログラミングとパフォーマンスに関係する問題について取り上げます。ここに示すガイドラインは Sun ONE Application Server に固有のものではなく、多くの状況に適用できる一般的なルールです。Java の最適な記述方法については、http://java.sun.com/blueprints/performance/index.html に用意されている Java BluePrint を参照してください。

  • 直列化と直列化復元をできるだけ避ける
  • Java では、オブジェクトの直列化と直列化復元は CPU を多用するため、アプリケーションの速度低下を招きがちです。直列化されたデータの量を減らすには、transient キーワードを使います。readObject() メソッドと writeObject() メソッドのカスタマイズが役立つことがあります。

  • +」演算子の代わりに StringBuffer.append() を使う
  • Java では、String は不変であり、作成後に変更されることはありません。たとえば、次のようなコードがあります。

    String str = "testing";

    str = str + "abc";

    これは、コンピュータによって次のように解釈されます。

    String str = "testing";

    StringBuffer tmp = new StringBuffer(str);

    tmp.append("abc");

    str = tmp.toString();

    このため、コピーは本質的にはリソースの消費につながり、頻用した場合はパフォーマンス低下の大きな要因となります。代わりに StringBuffer.append() を使うことをお勧めします。

  • 不要になった変数の値には null を明示的に割り当てる
  • こうすることで、安全に回収できるメモリ領域をガベージコレクターが簡単に識別できます。Java ではメモリ管理が自動化されているため、メモリ消費とメモリリークの超過を防ぐことができません。アプリケーションが参照を解放せずにオブジェクトを保持し続けると、メモリリークが生じることがあります。この場合、Java のガベージコレクターはこれらのオブジェクトを回収できなくなり、結果としてメモリの消費量が増えます。トランザクションごとに不要な変数への参照を無効化することで、ガベージコレクターはメモリを回収できます。メモリリークを検出するには、プロファイリングツールを使ってトランザクションが終わるごとにメモリの消費状況を調べる方法があります。メモリリークのない健全なアプリケーションでは、ガベージコレクション後に一定したヒープメモリが記録されます。

  • メソッドを不必要に final と宣言しないようにしてください。最近の動的な最適化コンパイラであれば、Java メソッドが final でない場合でも、自動インライン展開による最適化を実行できます。このキーワードは、プログラムのアーキテクチャとして必要な場合や、メンテナンス上の理由など、本来の目的だけに使用します。メソッドのオーバーライドを避ける必要があると確信を持てる場合にだけ final キーワードを使ってください。
  • 定数を宣言するときは、static final を使います。動的なコンパイラは、ヒントを与えるだけで式を評価し、定数畳み込み最適化を実行できます。
  • コードにファイナライザを含めると、ガベージコレクターによるリソースの消費が増え、動作を予測しにくくなります。仮想マシンでは、ファイナライザがいつ実行されるかを事前に知ることはできません。プログラムが終了するまでに、ファイナライザが実行されないことも考えられます。finalize() メソッドを使って重要なリソースを解放すると、アプリケーションの動作を予想しにくくなることがあります。
  • メソッド内で引数が変更されないときは、そのメソッド引数に final を宣言します。一般に、初期化後、または値の設定後に変更されないすべての変数には、final を宣言します。
  • 同期が必要ない場合は、コードブロックやメソッドを同期させないでください。スケーラビリティのボトルネックとならないよう、ブロックやメソッドの同期は最小にとどめます。非同期のデータ構造では、java.util.HashTable などのリソース消費の多い方法の代わりに、Java コレクションフレームワークを使います。

J2EE プログラミングのガイドライン

J2EE モデルは、エンタープライズアプリケーション開発のフレームワークを定義します。これは、ソフトウェアの基本コンポーネント (JSP、サーブレット、EJB) のコンテナと、コンテナサービス (JAAS、JDBC、JNDI、JTA など) を定義します。J2EE モデルのすべての構成要素にはそれぞれの用途があります。次の各項では、アプリケーションアーキテクチャの設計時に考慮すべき事項について説明します。

サーブレットと JSP プログラミングのガイドライン

Sun ONE Application Server 上で稼働する多くのアプリケーションは、プレゼンテーション層の JSP またはサーブレットによって処理されます。サーブレットと JSP は、より複雑なトランザクションビジネスロジックが実装された EJB のエントリポイントとなります。サーブレットとそれ以外の J2EE API を使って、ある程度複雑なビジネスアプリケーションを作成することも珍しくありません。

  • デフォルトのマルチスレッドモデルのサーブレットでは、アプリケーションサーバーのインスタンスごとにサーブレットのインスタンスが一つずつ作成されます。あるアプリケーションインスタンスのサーブレットに対するすべての要求は、同じサーブレットインスタンスで処理されます。このため、サーブレットのコードに同期されたブロックが含まれていると、スレッドの競合が生じます。修正されたクラス変数の共有は、同期の原因となるので避けてください。
  • セッションの作成によってもリソースは消費されます。セッションは、必要な場合にだけ作成します。また、不要になったセッションは無効化してください。
  • JSP で必要のない場合に HTTP セッションの自動作成を停止するには、<%page session="false"%> 指令を使います。
  • 規模の大きなオブジェクトグラフを HttpSession に格納しないでください。これにより、Java の直列化が生じ、オーバーヘッドの原因となります。
  • HttpSession アクセスはトランザクションではありません。トランザクションデータのキャッシュとして使わないでください。トランザクションデータは、通常はデータベースに格納され、エンティティ Bean を使ってアクセスされます。障害が発生すると、トランザクションは元の状態にロールバックします。しかし、HttpSession オブジェクトには古く不正確なデータが残ることがあります。Sun ONE Application Server では、キャッシュされた読み取り専用データへのアクセスを増やせるように、Bean 管理による「読み取り専用」エンティティ Bean を提供しています。

EJB プログラミングのガイドライン

次に、J2EE アプリケーションの EJB コンポーネントのパフォーマンスを向上するためのガイドラインを示します。詳細は、『Sun ONE Application Server Enterprise JavaBeans 開発者ガイド』を参照してください。

  • 要求ごとの JNDI ルックアップを避けるため、EJB 参照はサーブレットにキャッシュします。
  • EJBHome は、サーブレットの init() メソッドにキャッシュします。ルックアップの繰り返しはホームインタフェースを頻繁に使用するため、リソースの消費も多くなります。
  • Bean 固有のリソースをキャッシュするときは、setSessionContext() メソッドまたは ejbCreate() メソッドを使います。これも、Bean のライフサイクルメソッドを使ってアプリケーションを動作させる例です。場合によっては、1 サイクルだけでリソースを解放できます。ejbRemove() メソッドを使って、取得したリソースを必ず解放してください。
  • 可能であれば、データベーストランザクションの分離レベルを下げます。分離レベルを下げることで、データベース層での処理が削減され、アプリケーションパフォーマンスの改善につながります。ただしこれを行うには、事前にデータベーステーブルの利用パターンを十分に分析する必要があります。Sun ONE Application Server では、サーバー設定ファイルの <jdbc-connection-pool> でデータベースの分離レベルを設定できます。サーバー設定の詳細については、『Sun ONE Application Server 管理者ガイド』および『Sun ONE Application Server 管理者用設定ファイルリファレンス』を参照してください。
  • Sun ONE Application Server ORB には、サーバーと同じ Java 仮想マシンにホストされているクライアントからの呼び出しを最適化するメカニズムが用意されています。たとえば、サーブレットのコードが Enterprise JavaBeans を呼び出したり、Enterprise JavaBeans が同じサーバーインスタンス上の別の Enterprise JavaBeans を呼び出す場合が対象となります。サーブレットと EJB が同じ Java 仮想マシンで稼働している場合は、-nolocalstubs フラグを指定せずに rmic コンパイラを実行します。これはデフォルトの設定であり、サーバー設定ファイルでは -nolocalstubs は指定されていません。
  • EJB がリモートアプリケーションサーバーでホストされるアプリケーションアーキテクチャでは、デフォルトの動作を変更する必要があります。この変更は、管理用のコマンドインタフェースである asadmin を使って行うか、アプリケーションが配備されるサーバーインスタンス上で直接行います。ブラウザベースの管理インタフェースでは、rmic オプションは「JVM 設定」タブに表示されます。ローカルスタブを使用することで、パフォーマンスは大きく向上します。これは、スタブジェネレータのデフォルトの動作です。

  • 対象データにアクセスするパスをアプリケーション開発者が確実に知っているのであれば、参照による受け渡しを行うように Bean を設定できます。これにより、メソッドを呼び出したときに引数をコピーしたり、メソッドからの返される結果をコピーしたりする必要がなくなります。ただし、呼び出し時に別のソースがデータを変更してしまった場合は問題が生じます。この値は、次の方法で sun-ejb-jar.xml 配備記述子に設定できます。<pass-by-reference>true</pass-by-reference> (各 EJB 単位で設定)
  • 不要になったステートフルセッション Bean は削除します。これにより、ステートフルセッション Bean の非活性化と、ディスク入出力を削減できます。

次に、パフォーマンスへの影響が少ない順に EJB の種類を示します。

    • ステートレスセッション Bean とメッセージ駆動型 Bean
    • ステートフルセッション Bean
    • Bean 管理による持続性を持つエンティティ Bean (読み取り専用に設定)
    • コンテナ管理による持続性を持つエンティティ Bean (CMP)
    • Bean 管理による持続性を持つエンティティ Bean

EJB のプールとキャッシュ

ステートレスセッション Bean とエンティティ Bean は、どちらもプールすることでサーバーのパフォーマンスを向上できます。また、ステートレスセッション Bean とエンティティ Bean は、キャッシュによってもサーバーのパフォーマンスを向上できます。

表:    Bean の種類、およびプールとキャッシュへの対応

Bean の種類

プール

キャッシュ

ステートレスセッション

 

Yes

 

No

 

ステートフルセッション

 

No

 

Yes

 

エンティティ

 

Yes

 

Yes

 

プールされた Bean とキャッシュされた Bean の違いは、プールされた Bean はすべてが等しく、それぞれを区別できないことです。反対に、キャッシュされた Bean の場合、ステートフルセッション Bean は対話状態を含み、エンティティ Bean は主キーと関連します。エンティティ Bean は、ejbActivate() でプールから削除されてキャッシュに追加され、ejbPassivate() でキャッシュから削除されてプールに追加されます。必要なエンティティ Bean がキャッシュに見つからないと、コンテナは ejbActivate() を呼び出します。キャッシュのサイズが設定されている限界値を超えると、コンテナは ejbPassivate() を呼び出します。

次に、EJB のプールとキャッシュの設定をチューニングする方法について説明します。

  • EJB プールを使えるのは、ステートレスセッション EJB とエンティティ EJB です。ステートレスセッション EJB の使い道と、サーバーが対応できるトラフィック量に注意して、作成と削除の回数が多くなりすぎないようにプールサイズをチューニングする必要があります。sun-ejb-jar.xml 配備記述子の bean-pool 要素を参照してください。
  • キャッシュを使えるのは、ステートフルセッション EJB です。ステートフルセッション EJB の使い道と、サーバーが対応できるトラフィック量に注意して、活性化と非活性化を最小に押さえられるように EJB のキャッシュサイズとタイムアウト設定をチューニングする必要があります。sun-ejb-jar.xml 配備記述子の bean-cache 要素を参照してください。
  • クライアント側で remove() メソッドを明示的に呼び出して、コンテナキャッシュからステートフルセッション EJB を削除できるようにします。
  • エンティティ Bean には、EJB プールと EJB キャッシュの両方の設定が適用されます。Bean の作成と削除を最小化できるように、エンティティ EJB のプールサイズをチューニングします。0 以外でサイズが一定の内容をプールに設定しておくことで、最初の要求に対する応答が向上します。
  • Bean 固有のリソースをキャッシュするときは setEntityContext() メソッドを使い、解放するときは unSetEntityContext() メソッドを使います。
  • 遅延ロードを使って、不必要な子データを最初から取り込まないようにします。
  • 読み取り専用の操作には、読み取り専用のエンティティ Bean を設定します。

トランザクション

トランザクションを使用する場合は、次のような処理を行います。

  • リソースを不必要なほど長く保持されないように、トランザクションがユーザーの入力時間や思考時間を大きく超えないようにします。
  • 整合性を得るには、コンテナ管理トランザクションのほうが適しています。また、パフォーマンスにも優れています。
  • セッション EJB のトランザクション以外のメソッドを宣言するときに、トランザクション属性 NotSupported または Never を使わないでください。これらの属性は、ejb-jar.xml 配備記述子ファイルにあります。トランザクションはデータベースの行をロックするので、使用時間をできるだけ小さくします。
  • 長いトランザクションチェーンでは、トランザクション属性 TX_REQUIRED を使います。EJB メソッドが確実に呼び出しチェーンに含まれるようにするには、同じトランザクションを使います。
  • すべてのトランザクションで利用できる限り、データベースの負担ができるだけ少ないロックを使います。各メソッドの呼び出し後ではなく、トランザクションが完了してからデータをコミットします。
  • 1 つのトランザクションに複数のデータベースリソース、コネクタリソース、JMS リソース、またはその組み合わせが関連するときは、分散トランザクションまたはグローバルトランザクションを実行する必要があります。これには、XA に対応したリソースマネージャとデータソースが必要です。XA 対応データソースは、1 つのトランザクションに複数のデータソースが関連する場合にだけ使います。ほとんどの場合に 1 つのまたはローカルのデータベーストランザクションに使われるデータベースが、いくつかの分散トランザクションにも関わる場合は、サーバー設定ファイルに 2 つの <jdbc-resource> 要素を登録し、アプリケーションに適したリソースを使うようにします。

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

次に、JDBC接続プールをチューニングする方法について説明します。

  • 大規模なデータベースの検索など、大容量のデータを扱うときは、エンティティ EJB ではなく、JDBC を直接使います。
  • ビジネスロジックと、処理するロジックに必要なデータを保持するエンティティ EJB を組み合わせます。
  • 接続が確実にプールに戻るように、使用後は常に接続を閉じます。

JMS

JMS を使用する場合は、次のような処理を行います。

  • メッセージ駆動型 EJB のプールサイズは、メッセージの並行処理を最適化できるようにチューニングします。
  • Bean 固有のリソースをキャッシュするときは setMesssageDrivenContext() メソッドまたは ejbCreate() メソッドを使い、解放するときは ejbRemove() メソッドを使います。


  • アプリケーションをある程度以上の数の EJB に分割すると、アプリケーションのパフォーマンスが低下し、オーバーヘッドも増加します。JavaBeans とは異なり、EJB は単なる Java オブジェクトではありません。EJB は Java オブジェクトより高いレベルのエンティティです。EJB は、リモート呼び出しインタフェースセマンティクス、セキュリティセマンティック、トランザクションセマンティクス、およびプロパティから構成されるコンポーネントです。



参考資料


前へ      目次      索引      次へ     
Copyright 2002 Sun Microsystems, Inc. All rights reserved.