連載
» 2008年10月15日 00時00分 公開

現場から学ぶWebアプリ開発のトラブルハック(12):アプリ開発でも、よ〜く考えよう。キャッシュは大事だよ (2/2)

[佐藤聖規,@IT]
前のページへ 1|2       

キャッシュは、ためるものではなく使うもの

 今回のトラブルの最大の原因は通信を行うごとに、値のまったく変わらないプロパティファイルにアクセスしてしまうことである。

 そこで今回は、一度必要なプロパティの値をオブジェクト化したら、ロードしたプロパティをキャッシュ化しておき、2回目以降の通信時にはキャッシュから値を取得する形に変更することに決定した。

図4 キャッシュ化した後の通信時の挙動 図4 キャッシュ化した後の通信時の挙動

 なお、このアプリケーションでは、プロパティファイルは更新されないため、キャッシュクリアや更新のためのキャッシュアルゴリズムは特に用いず、アプリケーションが終了するまでキャッシュを保持しておくこととした。

 つまり、GOFのデザインパターンでいうところのシングルトンパターン(注意:シングルトンパターンの詳細な解説は「クラスのインスタンスを1つに保つ(Singletonパターン)」を参照してください)の適用を勧めた。

 私はプロジェクトの開発者たちに修正のアドバイスをして現場を立ち去った。

トラブルハッカーはアドバイスがほとんど

 なお、私たちのようなトラブルハッカーはプロジェクトのメンバーではないことが多い。そのためプロジェクトのアーキテクチャや業務に精通しているわけではない。

 従って、問題点を解消するためのアドバイスだけで実際のソースコードの修正や再試験はプロジェクトに任せることがほとんどである。

ところが、問題再発!?

 問題特定から数日が経過して、私は問題が解決したか気になりながらも、平和な日々を過ごしていた。「便りがないのは元気な証拠」といわんばかりに問題が解決したプロジェクトからは連絡がないことが多い。

 そう思っていた矢先、再びプロジェクトの担当者から電話がかかってきた。何でも、通信時のパフォーマンスは目標を達成したらしいが、それとは別の問題が発生したらしい。

 とにかく電話では現状が伝わってこないため、再びプロジェクトへお邪魔してヒアリングを行うことにした。

過ぎたるは及ばざるがごとし

 プロジェクトは以前の分析結果に基づき、プロパティファイルのインスタンスをキャッシュ化した。しかし、また別の問題が発生してしまったらしい。

再発した2つの問題

 プロジェクトの担当者にヒアリングを行ったところ、以下の2点が判明した。

  • 通信時のパフォーマンスは目標を達成した
  • アプリケーションの起動が著しく遅くなってしまった

 なお、ソースコードの修正は「プロパティインスタンスのキャッシュ化のみの修正」を行ったらしい。

 上記の事実と現象から原因は、プロファイリングを行うまでもなく、容易に予想がついた。恐らく、起動時にプロパティファイルをキャッシュ化する処理を実施しているのだろう。

起動時のプロパティファイルのキャッシュ化に加え……

 早速、担当者に確認したところ、やはり起動時にプロパティファイルのキャッシュ化を行っているらしい。さらに、以下の事実が判明した。

  • プロパティファイルは業務種別ごとに分かれており、全部で10個以上ある
  • 1つのプロパティファイルは数メガバイトから数十メガバイトの大きなサイズである
図5 起動時にすべてのプロパティをキャッシュ化する方式 図5 起動時にすべてのプロパティをキャッシュ化する方式

 上記の処理を起動時にすべて行ってしまっては、アプリケーションの起動が著しく遅くなってしまうのは無理もない。まさしく、「過ぎたるは及ばざるがごとし」である。

なぜ起動時に?

 ここで1つの疑問が浮かんだ。「なぜ、起動時にすべてのプロパティファイルをキャッシュ化したのか」である。

 この理由は、サーバ側のパフォーマンスに問題がなかったのは、起動時に必要なプロパティファイルをすべてインスタンス化して再利用していたからであり、その仕組みを踏襲したとのことである。

怠惰(Lazy)に問題を解消

 起動時にすべてのプロパティをキャッシュ化する方式は、一度起動すればメンテナンスのとき以外は再起動をしないサーバ型のアプリケーションでは有効な手段だといえる。

 ただし、今回は必要なときだけ起動して、不必要になればアプリケーションを終了するクライアント側で動くリッチアプリケーション型のアプリケーションである。起動が著しく遅くては、ユーザーへ与えるストレスが大きくなってしまう。

 そこで、プロパティファイルをインスタンス化するのは、初めてプロパティの値が使われるタイミングとした。すなわち「Lazy Instantiation(怠惰なインスタンス化)」である。

図6 Lazy Instantiationによるキャッシュ化 図6 Lazy Instantiationによるキャッシュ化

 つまり、起動時は「何もしない」というチューニングを施すこととなる。

意欲的なインスタンス化もある

 なお、この起動時にすべてのインスタンス化を行うような手法を「Eager Instantiation(意欲的なインスタンス化)」といい、起動時間にさほど気を使わず、比較的簡単にメモリを増設可能なサーバ型のアプリケーションでは有効な手法といえる。

 これにより、初めてプロパティの値が利用されるときは処理が遅くなってしまうが、起動時の著しいパフォーマンスの低下は抑えられる。

 すべてのプログラムを修正すれば、抜本的な対策を行えるかもしれないが、もちろんそんなことをやっている時間はない。このように、チューニングは往々にしてトレードオフである。

 そしてLazy Instantiationを行うことで、ようやくプロジェクトは目標のパフォーマンスを達成できた……。

ご利用は計画的に

 今回についてまとめると、以下の3つのテクニックでチューニングを行うトラブルハックを紹介した。

  1. プロファイラによる遅いメソッドの特定
  2. キャッシュによる無駄な処理の回避
  3. Lazy Instantiationによる処理の分散

 アプリケーションのチューニングで一番効果が覿面(てきめん)なのは、「何も処理させない」ことである。まずは、同じことを2度やっていないか、無駄なことをやっていないか、プロファイラを使えばすぐ分かるだろう。

チューニングはトレードオフ

 また繰り返すが、基本的にチューニングはトレードオフである。あるメリットを享受するために、デメリットを受ける可能性が高い。さらに、ソースコードに修正が及ぶため、再試験などの余計なコストも掛かってしまう。そのため、ソースコードレベルでのチューニングは最後の手段と考えた方がよいだろう。

 チューニングを行わなければならなくなったときは、チューニングが巻き起こすトレードオフを熟慮して行ってほしい。

プロフィール

佐藤聖規

佐藤 聖規(さとう まさのり)

某大手SIerに勤務し、ソフトウェア開発の抜本的生産性向上のためEclipseを中心とした開発環境の整備に日夜いそしんでいる。

その傍ら、アーキテクトやトラブルシューターとしてプロジェクト支援も行っている。



前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。