J2EE アプリケーションの動作が遅くありませんか?トラフィックの増加に耐えられるでしょうか?この記事では、高性能で弾力性の高い JSP ページおよびサーブレットを開発するためのパフォーマンス最適化テクノロジについて説明します。その考えは、できるだけ早く構築し、増加するユーザーとその要求に適応することです。この記事では、サーブレットと JSP ページのパフォーマンスを大幅に向上させ、J2EE のパフォーマンスを向上させる、実践的で実証済みのパフォーマンス チューニング テクニックを学習します。これらのテクノロジーの一部は、設計フェーズやコーディングフェーズなどの開発フェーズで使用されます。テクノロジーの別の部分は構成に関連しています。
手法 1: HttpServletinit() メソッドでデータをキャッシュする
サーバーは、サーブレット インスタンスの作成後、サーブレットがリクエストを処理する前に、サーブレットの init() メソッドを呼び出します。このメソッドは、サーブレットのライフサイクルで 1 回だけ呼び出されます。パフォーマンスを向上させるには、静的データを init() にキャッシュするか、初期化中に実行される高価な操作を実行します。たとえば、ベスト プラクティスの 1 つは、javax.sql.DataSource インターフェイスを実装する JDBC 接続プールを使用することです。
DataSource は JNDI ツリーから取得されます。 SQL が呼び出されるたびに JNDI を使用して DataSource を見つけるのは非常にコストがかかり、アプリケーションのパフォーマンスに重大な影響を与えます。サーブレットの init() メソッドを使用して DataSource を取得し、後で再利用できるようにキャッシュすることができます。
publicclassControllerServletextendsHttpServlet
{
privatejavax.sql.DataSourcetestDS=null;
publicvoidinit(ServletConfigconfig)throwsServletException
{
super.init(config);
コンテキストctx=null;
試す
{
ctx=newInitialContext();
testDS=(javax.sql.DataSource)ctx.lookup("jdbc/testDS");
}
catch(ネーミング例外)
{
ne.printStackTrace();
}
キャッチ(例外)
{
e.printStackTrace();
}
publicjavax.sql.DataSourcegetTestDS(
)
{
テストDSを返す;
}
...
...
手法
2: サーブレットと JSP の自動ロード機能を無効にする
サーブレット/JSP を変更するたびにサーバーを再起動する必要があります。オートローディング機能により開発時間が短縮されるため、この機能は開発段階で非常に役立つと考えられています。ただし、実行時フェーズでは非常にコストがかかり、サーブレット/JSP は不必要なロードとクラス ローダーの負担の増大によりパフォーマンスの低下を引き起こします。繰り返しになりますが、特定のクラス ローダーによってロードされたクラスは、現在のクラス ローダーによってロードされたクラスと連携できないため、アプリケーションに奇妙な競合が発生する可能性があります。したがって、実行環境でより良いパフォーマンスを得るには、サーブレット/JSP の自動ロード機能をオフにしてください。
手法 3: HttpSession を制御する
多くのアプリケーションでは、相互に関連付けることができるように、一連のクライアント要求が必要です。 HTTP プロトコルはステートレスであるため、Web ベースのアプリケーションはセッションと呼ばれるそのような状態を維持する必要があります。状態を維持する必要があるアプリケーションをサポートするために、Java サーブレット テクノロジは、セッションを管理し、複数のメカニズムでセッションを実装できるようにする API を提供します。 HttpSession オブジェクトはセッションとして機能しますが、使用にはコストがかかります。 HttpSession が使用されてオーバーライドされるたびに、サーブレットによって読み取られます。次の手法を使用すると、パフォーマンスを向上させることができます。
lJSP ページにデフォルトの HttpSession を作成しない: デフォルトでは、JSP ページは HttpSession を作成します。 JSP ページで HttpSession を使用しない場合は、パフォーマンスのオーバーヘッドを節約するために、次のページの手順を使用して、HttpSession オブジェクトが自動的に作成されないようにします。
< %@pagesession="false"% >
1) ラージ オブジェクト グラフを HttpSession に保存しない: データをラージ オブジェクト グラフとして HttpSession に保存すると、アプリケーション サーバーは毎回 HttpSession オブジェクト全体を処理する必要があります。これにより、Java のシリアル化が強制され、計算オーバーヘッドが増加します。シリアル化のオーバーヘッドにより、HttpSession オブジェクトに格納されるデータ オブジェクトが増加するにつれて、システムのスループットは低下します。
2) 使用後に HttpSession を解放します。HttpSession が使用されなくなったら、HttpSession.invalidate() メソッドを使用してセッションを無効にします。
3) タイムアウト値を設定します。サーブレット エンジンにはデフォルトのタイムアウト値があります。セッションを削除しない場合、またはタイムアウトになるまでセッションを使用し続ける場合、サーブレット エンジンはセッションをメモリから削除します。メモリとガベージ コレクションのオーバーヘッドにより、セッション タイムアウト値が大きくなるほど、システムの復元力とパフォーマンスに与える影響が大きくなります。セッション タイムアウト値をできるだけ低く設定するようにしてください。
テクニック 4: gzip 圧縮を使用する
圧縮とは、冗長な情報を削除し、できるだけ小さなスペースで情報を記述することです。 gzip (GNUzip) を使用してドキュメントを圧縮すると、HTML ファイルのダウンロード時間を効果的に短縮できます。メッセージが小さいほど、より速く送信されます。したがって、Web アプリケーションによって生成されたコンテンツを圧縮すると、より速くユーザーに到達し、ユーザーの画面に表示されます。すべてのブラウザが gzip 圧縮をサポートしているわけではありませんが、ブラウザがサポートしているかどうかを確認して、gzip 圧縮されたコンテンツをブラウザに送信するのは簡単です。以下のコード スニペットは、圧縮されたコンテンツを送信する方法を示しています。
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsIOException、サーブレット例外
{
OutputStreamout=null
//HTTP リクエストの Accepting-Encoding ヘッダーを確認します。
//ヘッダーに gzip が含まれている場合は、GZIP を選択します。
//ヘッダーに圧縮が含まれている場合は、ZIP を選択します。
//それ以外の場合は、圧縮なしを選択します。
Stringencoding=request.getHeader("Accept-Encoding");
if(encoding!=null&&encoding.indexOf("gzip")!=-1)
{
response.setHeader("コンテンツエンコーディング","gzip");
out=newGZIPOutputStream(response.getOutputStream());
}
elseif(encoding!=null&&encoding.indexOf("圧縮")!=-1)
{
response.setHeader("コンテンツエンコーディング","圧縮");
out=newZIPOutputStream(response.getOutputStream());
}
それ以外
{
out=response.getOutputStream()
;
...
...
テクニック
5: SingleThreadModel を使用しない
SingleThreadModel は、サーブレットが一度に 1 つのリクエストのみを処理することを保証します。サーブレットがこのインターフェイスを実装している場合、サーブレット エンジンは新しいリクエストごとに個別のサーブレット インスタンスを作成するため、大量のシステム オーバーヘッドが発生します。スレッドの安全性の問題を解決する必要がある場合は、このインターフェイスの代わりに他のメソッドを使用してください。 SingleThreadModel の使用は、Servlet2.4 では推奨されなくなりました。
手法 6: スレッド プール
サーブレット エンジンを使用して、リクエストごとに個別のスレッドを作成し、そのスレッドを service() メソッドに割り当て、service() メソッドの実行後にスレッドを削除します。デフォルトでは、サーブレット エンジンはリクエストごとに新しいスレッドを作成します。スレッドの作成と削除にはコストがかかるため、このデフォルトの動作によりシステムのパフォーマンスが低下します。スレッド プールを使用してパフォーマンスを向上させることができます。予想される同時ユーザー数に応じて、スレッド プールを構成し、スレッド プール内のスレッドの最小数と最大数、および増加の最小値と最大値を設定します。最初に、サーブレット エンジンは、構成内のスレッドの最小数と同じ数のスレッドを含むスレッド プールを作成します。サーブレット エンジンは、操作が完了するたびに新しいスレッドを作成するのではなく、プールからスレッドをリクエストに割り当てます。そのスレッドはスレッド プールに戻されます。スレッド プールを使用すると、パフォーマンスが大幅に向上します。必要に応じて、スレッドの最大数と増加数に基づいて、さらに多くのスレッドを作成できます。
テクニック 7: 正しいインクルード メカニズムを選択する
JSP ページでは、ファイルをインクルードする 2 つの方法があります。インクルード命令 (< %@includefile="test.jsp"% >) とインクルード アクション (<jsp:includepage="test.jsp ") です。 flash="true"/>)。 include ディレクティブは、コンパイル段階で、たとえばページがサーブレットにコンパイルされるときに、指定されたファイルの内容をインクルードします。インクルード アクションには、ユーザーがページをリクエストするときなど、リクエスト フェーズ中にファイル コンテンツを含めることが含まれます。指示を含めるほうが、アクションを含めるよりも高速です。したがって、インクルードされるファイルが頻繁に変更されない限り、include ディレクティブを使用するとパフォーマンスが向上します。
テクニック 8: useBean アクションで適切なスコープを使用する
JSP ページを使用する最も強力な方法の 1 つは、JavaBean コンポーネントを操作することです。 JavaBeans は、<jsp:useBean> タグを使用して JSP ページに埋め込むことができます。構文は次のとおりです:
<jsp:useBeanid="name"scope="page|request|session|application"class=
"パッケージ.クラス名"type="タイプ名">
</jsp:useBean>
scope 属性は、Bean の表示スコープを記述します。スコープ属性のデフォルト値はページです。アプリケーションのニーズに基づいて正しい範囲を選択する必要があります。選択しないと、アプリケーションのパフォーマンスに影響します。
たとえば、あるリクエストに固有のオブジェクトが必要であるが、スコープをセッションに設定した場合、そのオブジェクトはリクエストの終了後もメモリ内に残ります。メモリから明示的に削除するか、セッションを無効にするか、セッションがタイムアウトしない限り、メモリ内に残ります。正しいスコープ属性を選択しないと、メモリとガベージ コレクションのオーバーヘッドによりパフォーマンスが影響を受けます。したがって、オブジェクトに適切なスコープを設定し、使い終わったらすぐに削除します。
その他のテクニック
1) 文字列の連結を避ける: String オブジェクトは不変オブジェクトであるため、「+」演算子を使用すると、多数のゼロタイム オブジェクトが作成されます。 「+」を使用するほど、より多くのゼロタイム オブジェクトが生成され、パフォーマンスに影響します。文字列を連結する必要がある場合は、「+」演算の代わりに StringBuffer を使用します。
2) System.out.println の使用を避ける: System.out.println はディスク入出力を同期的に処理するため、システムのスループットが大幅に低下します。可能な限り System.out.println の使用を避けてください。利用可能な成熟したデバッグ ツールは数多くありますが、トレースやデバッグの目的で System.out.println が依然として役立つ場合があります。 System.out.println は、エラー段階とデバッグ段階でのみ開くように構成する必要があります。 FinalBoolean 変数を false に設定すると、コンパイル フェーズ中に最適化チェックと実行トレース出力が完了します。
3) ServletOutputStream と PrintWriter の比較: 文字出力ストリームとデータのバイトへのエンコードにより、PrintWriter を使用するとパフォーマンスのオーバーヘッドが若干発生します。したがって、PrintWriter は、すべての文字セット変換が正しく行われた後に使用する必要があります。一方、サーブレットがバイナリ データのみを返すことがわかっている場合は、ServletOutputStream を使用します。これは、サーブレット コンテナがバイナリ データをエンコードしないため、文字セット変換のオーバーヘッドが排除されるためです。
まとめ
この記事の目的は、J2EE アプリケーションの全体的なパフォーマンスを向上させる、サーブレットと JSP のパフォーマンスを向上させるための実用的で実証済みのパフォーマンス最適化テクニックをいくつか紹介することです。次のステップでは、EJB、JMS、JDBC などの他の関連テクノロジのパフォーマンス チューニングを観察する必要があります。