【2/17】今年は「濃厚」技術トーク!@ITメールセミナー スラッシュドット    はてなブックマーク  Yahoo!ブックマークに登録  印刷



事例に学ぶWebシステム開発のワンポイント(12)

ブラウザキャッシュでパフォーマンス向上
―負荷分散装置の落とし穴に注意−


(株)NTTデータ

金子崇之
2003/5/10


本連載では、現場でのエンジニアの経験から得られた、アプリケーション・サーバをベースとしたWebシステム開発における注意点やヒントについて解説する。巷のドキュメントではなかなか得られない貴重なノウハウが散りばめられている。読者の問題解決や今後システムを開発する際の参考として大いに活用していただきたい。(編集局)


今回のワンポイント
Webシステムのパフォーマンスを考慮するうえで、実はコンテンツのキャッシュに関する知識は欠かせない。今回はブラウザ側のキャッシュ、サーバ側のキャッシュをいかに制御し、Webシステムのパフォーマンスを向上させるかについて解説する。

キャッシュされる場所は3カ所

今回の内容

キャッシュされる場所は3カ所
キャッシュ制御の方法
キャッシュの流れ

何でもキャッシュすればよいわけではない
負荷分散装置でキャッシュが効かないのは?

 コンテンツがキャッシュされる場所は、図1のように大きく分けて以下の3つの場所がある。

  • クライアントマシン上のブラウザ
  • クライアントマシンとWebサーバの間に位置するProxyサーバ
  • Webサーバの背後にあるアプリケーションサーバ

 キャッシュをうまく制御することによって、システムの正しい動作を保証するだけではなく、応答時間の短縮、回線の有効活用、サーバリソースの節約といった重要な性能対策になる。

 本稿では、HTTPのキャッシュ機構の説明とともに、キャッシュを有効活用するための指針、ブラウザのキャッシュ機構が正常に動作しないというトラブル事例について述べる。なお本稿ではアプリケーションサーバのキャッシュ機能については割愛する。

図1 キャッシュされる場所は「クライアント」「Proxyサーバ」「APサーバ」の3カ所にある

キャッシュ制御の方法

 サーバサイドからキャッシュを制御するには、以下の2つの方法がある。

  • HTTPヘッダによる制御
  • METAタグによる制御

 まずは、これらがどのようなものか、軽くおさらいしておく。

■HTTPヘッダによる制御

 HTTPプロトコルでは、HTTPヘッダにさまざまな情報を格納することができる。そのうちいくつかの情報は、キャッシュ制御のためのヘッダである。リクエスト(クライアント→サーバ)用のものと、レスポンス(サーバ→クライアント)用、リクエスト/レスポンス共通のものが存在する。

リクエスト用
 If-Modified-Since
  日時を指定する。指定した日時より新しいコンテンツの場合のみデータを返却するようにサーバに指示する。ローカルキャッシュの最新確認に使用される
 If-None-Match
  指定したエンティティタグに一致しない場合のみコンテンツを返却するようにサーバに指示する。最新情報の取得や競合の排除のために指定される

■レスポンス用
 Expires
  コンテンツの有効期限を示す
 Last-Modified
  コンテンツの最終更新時刻を示す。If-Modified-Sinceと対で使用される
 ETag
  コンテンツの全体や一部を特定する固有値を示す。If-None-Matchと対で使用される

■リクエスト/レスポンス共通
 Cache-Control
  キャッシュのコントロールに関する指示や情報を示す
 Pragma
  関連するクライアント/Proxy/サーバそれぞれに認識させるための特殊な追加情報を記述する。例えば、「no-cache」を指定することで無条件に最新リソースを転送させることができる

■METAタグ

 METAタグはHTMLで規定されていない情報をHTMLページに持たせるためのタグだ。<meta http-equiv="name" content="content">というMETAタグを指定すると、HTTPヘッダにname: contentというフィールドを追加したのと同じ働きとなる。そのため静的なHTMLコンテンツの内部からクライアントのキャッシュを制御することが可能となる。

 また、METAタグは基本的にはブラウザのキャッシュを操作するためのものだ。なぜなら通常はProxyサーバはMETAタグを処理しないからである。ブラウザの種類によってはMETAタグをサポートしないものがあるので、確実にキャッシュをコントロールしたい場合には、HTTPヘッダとMETAタグの両方を使用するのがよいだろう。
 

キャッシュの流れ

 ブラウザやProxyサーバにコンテンツがキャッシュされる場合の動作は次のようになる。コンテンツがブラウザ内にキャッシュされた場合、ブラウザがそのコンテンツのキャッシュを使用する場合にはサーバに対してリクエストを発行しない。ブラウザ内にキャッシュがない場合や、キャッシュを使用するかどうか判断できない場合には、サーバにリクエストを発行する。

 コンテンツがProxyサーバにキャッシュされている場合、Proxyサーバではコンテンツと一緒にHTTPヘッダ情報を保存している。キャッシュが有効な場合にはブラウザからのリクエストに対してProxyサーバがレスポンスを返す。Proxyサーバでは、異なるクライアント(ブラウザ)が以前にリクエストしたコンテンツをキャッシュし、そのキャッシュを使用することができる。

 また、キャッシュが無効な場合や、キャッシュを使用しないことを指示されている場合には、ProxyサーバはWebサーバに対してコンテンツを取得するためにリクエストを発行する。

 リクエストがWebサーバまで到達すると、If-Modified-SinceヘッダやIf-None-Matchヘッダが付いていた場合、WebサーバはコンテンツのタイムスタンプとIf-Modified-Sinceヘッダの時間、コンテンツの全体や一部を特定する固有値とIf-None-Matchヘッダの値を比較し、もしコンテンツが更新されていればコンテンツを送信する。更新されていなければ304 Not Modified をレスポンスとして返す。

 「304 Not Modified」の場合にはレスポンスボディに実際のファイルを含まないヘッダだけのレスポンスなため、非常に軽量のデータである。

図2 キャッシュの流れ

何でもキャッシュすればよいわけではない

 WebシステムをWebサーバ、アプリケーションサーバを連携させて構築する場合、画像ファイルやCSSファイル、めったに更新されないHTMLファイルなどの静的なコンテンツは、通常Webサーバに配置しアプリケーションサーバの負荷を減らすようにする。そのためWebサーバでは適切なヘッダを送信するように正しく設定する必要がある。

 一方アプリケーションサーバで生成されるコンテンツは、通常、ユーザーのセッション情報やDBアクセスなどを基に動的に生成されるものである。そのためブラウザ、Proxyサーバにキャッシュされてしまうと、検索結果がいつまでも更新されなかったり、ほかのユーザーが検索した結果が参照できてしまったりするなどの不具合が発生する可能性がある。そのためキャッシュされないようにするためのキャッシュコントロールが必要である。

 J2EEアプリケーションサーバでは動的なHTMLページを生成するのにJSPが使用される。そこでJSPで生成したページをキャッシュさせないようにするための方法を紹介する。

■動的に生成したページをキャッシュさせないために

 JSPで生成したページをキャッシュさせたくない場合には、以下のようなファイルを用意して、<%@ page include="Nocache.inc" %> のようにインクルードするとよい。

Nocache.inc
<%! private String getHTTPDate() {
    java.text.SimpleDateFormat formatter =
      new java.text.SimpleDateFormat("E, dd MMM yyyy hh:mm:ss zzz", java.util.Locale.US);
    formatter.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
    return formatter.format(new java.util.Date());
  }
%><%
  response.setHeader("Expires", getHTTPDate());
  response.setHeader("Pragma","no-cache");
  response.setHeader("Cache-Control","no-cache");
%>

 また、レスポンスヘッダは以下のようになる。

HTTP/1.1 200 OK
Content-Type: text/html;charset=Shift_JIS
Cache-control: no-cache
Pragma: no-cache
Expires: Tue, 17 12 2002 15:34:27 GMT

Date: Tue, 17 Dec 2002 15:34:27 GMT
Server: Apache Coyote/1.0
Proxy-Connection: close
Connection: close

 
負荷分散装置でキャッシュが効かないのは?

 負荷分散装置を利用したWebサーバ、アプリケーションサーバのクラスタ化は、パフォーマンスやスケーラビリティの向上のために採用されることが多い。ここでは、負荷分散装置を利用したWebサーバのクラスタ化において、Webサーバ(Apache)の設定によりキャッシュが有効とならなかった事例を紹介しよう。

 システムは図3のように、Webサーバ、アプリケーションサーバを分割し、Webサーバは静的コンテンツのみ、アプリケーションサーバは動的コンテンツを処理するようになっていた。またWebサーバは多重化され、セッション情報などを持たないため負荷分散装置によってラウンドロビンに振り分けられていた。

図3 問題となったシステム構成

 Webサーバに配置されたコンテンツは主に画像ファイルで、応答時間劣化の懸念となっていた。しかし画像ファイルは多くの遷移先ページで同一の画像を使用しており、まためったに更新されないことが分かっていた。事実Webサーバが1台の場合の試験環境ではブラウザのキャッシュが有効となり、応答時間が改善されることが確認できていた。

 しかし実際のシステムでの状況は、画像へのリクエストに対して、期待されたレスポンスコード304を全く返さず、ほぼ毎回レスポンスコード200として画像ファイルを送信してしまっていた。そのため応答時間も悪化、Webサーバの負荷も上がってしまった。

■原因はHTTPヘッダのETag

 原因は、先ほど説明したHTTPヘッダのETagであった。このETagはコンテンツに対してユニークなIDを割り振り、変更されているかどうかを確認するためのものである。ブラウザからはIf-None-Matchタグにこの値が付けられ、サーバ側ではこの値とETagの値が異なればレスポンスコード200でコンテンツを送信する。

 ETagの値は、同じ内容、同じ更新日付のファイルであってもWebサーバごとに異なる値が返されていた。今回使用していたシステムではApacheを採用していたのだが、Apacheはファイルのi-nodeによりユニークなIDを付けていた。リクエストを負荷分散装置がラウンドロビンで振り分けていたため、同じWebサーバにアクセスが行かない限り異なるコンテンツと判断され、結果が送信されていたのだ。

■どう対策するのか?

 Apache 1.3.23以降では、サーバ側でETagを付けないことにより、ETagによる比較を行わなくすることが可能だ。Apacheのhttpd.confに「FileETag None」と記述すればよい。以下にいくつかの設定例を示す。

/var/www/icons配下のコンテンツにはETagを付けない
<Directory "/var/www/icons">
  FileETag None
</Directory>

画像ファイルの拡張子を持つコンテンツにはETagを付けない
<FilesMatch "\.(gif|jpe?g|png)$">
  FileETag None
</FilesMatch>

このApacheはETagを付けない
FileETag None

 今回の記事ではHTTPのキャッシュ機構、J2EEでのキャッシュの制御方法、キャッシュに関するトラブル事例を紹介した。

 キャッシュによる効果は、クライアントからすれば応答時間の短縮、サーバからすれば、サーバリソースの節約に非常に大きく発揮される。そのためキャッシュの仕組みを知り、正しく制御することはとても重要である。

 トラブル事例のときのように、試験環境と本番環境が異なる場合には特に注意が必要である。うっかり設定を見落とすことによって、避けられるはずの顧客のイライラやサーバの過負荷によるシステム管理者の悲鳴などに遭遇しないように注意するべきだ。


INDEX
事例に学ぶWebシステム開発のワンポイント
  第1回 クラスタ化すると遅くなる?(2002/3/9)
  第2回 キャッシュが性能劣化をもたらす“なぞ”を解く(2002/3/23)
  第3回 クラスタは何台までOK?(2002/4/19)
  第4回 マルチスレッドのいたずらに注意(2002/5/14)
  第5回 サービス中にアプリケーションを入れ替える(2002/6/4)
  第6回 APサーバからの応答がなくなった、なぜ?(2002/11/30)
  第7回 低負荷なのにCPU使用率が100%?(2002/12/11)
  第8回 文字化け“???”の法則とその防止策(2003/1/28)
  第9回 メモリは足りているのに“OutOfMemory”(2003/2/15)
  第10回 レスポンスキャッシュでパフォーマンス向上(2003/3/29)
  第11回 JDBC接続を高速化する(2003/4/18)
第12回 ブラウザキャッシュでパフォーマンス向上(2003/5/10)
  第13回 ファイルアップロード/ダウンロードに潜むわな(2003/6/12)


筆者プロフィール
金子 崇之(かねこ たかゆき)

現在、株式会社NTTデータビジネス開発事業本部に所属。 技術支援グループとして、J2EEをベースにしたWebシステム開発プロジェクトを対象に、技術サポートを行っている。特に、性能・信頼性といった方式技術を中心に活動中。


Java Solution全記事一覧





ホワイトペーパーTechTargetジャパン

Java Solution フォーラム 新着記事

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

スキルアップ/キャリアアップ(JOB@IT)

- PR -
- PR -

お勧め求人情報

キャリアアップ 〜JOB@IT
@IT Special -PR-
  企業の仮想化に足りない“発想”とは?
仮想化運用管理のキモは意外なところに!

New!
  操作もマニュアルも分かりやすい!
ユーザー視点で開発されたPC管理ツール

New!
  仮想化すればコストは削減できるか?
仮想化に必要な「3つの視点」を解説する

  セキュリティを知り尽くす上野氏が登壇!
@ITメールソリューションLive! in Tokyo

  運用管理の課題を“2つの観点”から分析
ユーザー満足度の高い「仮想環境」とは?

  世界に通用するストレージの作り方とは?
製品に込めた思いを富士通の開発者に聞く

  OSSで手間も時間も、障害も減った――
「マピオンの事例」オープンソース活用法

  「ノートPCの持ち出し禁止」で大丈夫?
情報漏えいを防ぐ管理手法とインフラは?

  1日の処理を1秒に――MySQLの達人が語る
「コスト削減」できるチューニング

  ドキュメント作成を自動化して、SEの作業
効率を大幅アップ! Visio 2007の魅力

  急速に広がるHyper-Vでのサーバ仮想化
そのベストプラクティスをデルが解説

  @IT主催セミナーで語られた、「担当者に
求められるセキュリティ対策」をレポート

  @IT「Windows 7」 特設サイトオープン!
最新情報・移行ノウハウを公開しています