GAE開発の落とし穴
Googleのクラウド環境をつかったGoogle App Engineによる開発するにあたり、初めての試みで苦悩する開発者達の経験をもとに、各開発フェーズにあわせて問題点やどう解決したかをご紹介します
ブックマークされました!
ブックマークがエラーになりました。もう一度お願いします。

作者 Alex Devine , 翻訳者 編集部 投稿日 2009年5月26日
「アプリケーションの高速性やスケーラビリティに間違いのないことをステージング環境で時間をかけて確認したのに、その後プロダクションに入った途端に、どういうわけかパフォーマンスが急降下する」 -- これはまさに多数の開発者に馴染み深いマーフィーの法則です。さらに都合の悪いケースになると、通常は速いのに、上司や、動作について苦情を言う重要な顧客から見た場合に限って、いつもノロノロした動作になります。こうした断続的なパフォーマンスボトルネックを追跡するには、詳細なロギングと解析が必要不可欠です。
しかし、サービス指向アーキテクチャと広範囲に分散したアプリケーションで成り立っている現状では、パフォーマンスボトルネックの原因となっているコンポーネントの発見は非常に難しいことがあります。典型的なWeb 2.0スタイルのアプリケーションで比較的よく見られるシナリオについて、サーバーに何が起こるかを考えてみましょう。
「なぜ私のWebページは遅いのか?」という質問に答えるには、多数のコンポーネントと実行プランを調査する必要があり、さらに、プロダクション内の全アプリケーションコンポーネントから詳細なパフォーマンスデータが必要になります。
Perf4Jは、サーバーサイドでJavaのコードタイミング・ステートメントを追加したり、結果のロギングや解析、モニタリングをしたりする、オープンソースのツールセットです。log4jやjava.util.loggingといったロギングフレームワークに精通している開発者にとっては、Perf4Jの説明に類似性が役立ちます。
Perf4JのSystem.currentTimeMillis()に対する関係は、log4jのSystem.out.println()に対する関係と同じである。
これがPerf4Jの理解にどう関係があるのでしょうか。Java向けの優れたロギングフレームワークが広く利用可能になる前の古き悪しき時代、私たち開発者の大部分がロギングステートメントを追加した方法を考えてみてください。System.out.println()を「手軽なデバッガ」 -- ロギング情報を出力するための間に合わせの方法として使いました。すぐに、これでは不十分と分かりました。ロギングステートメントを専用のログファイル(異なる複数のファイルの可能性もあり)に向かわせ、おそらくそうしたログファイルを毎日ロールさせたかったのです。異なるレベルの重要性を異なるロギングステートメントに割り当てる能力や、コードをまったく変更することなく、特定の環境で特定のログステートメントのみを書いたり、異なる環境でログステートメントのフォーマットを変更したりするオプションを求めていました。そのため、log4jが提供する豊富な機能群が生まれるきっかけとなったのは、ロギングステートメント向けに「より優れた」System.out.println()が欲しいという願望でした。
同様に、Javaの新入り開発者がコードにパフォーマンスロギングを追加する必要性を見つけると、頻繁に以下のような処理をします。
long start = System.currentTimeMillis();
// execute the block of code to be timed
log.info("ms for block n was: " + (System.currentTimeMillis() - start));
ところが、こうした開発者はその後、平均偏差、最小偏差、最大偏差、標準偏差や、決められた期間におけるトランザクション/秒などといった、まとまった性能統計のような情報が欲しいことに気付きます。こうした数値のグラフをリアルタイムで入手できたら、実行中のサーバーの問題を検知可能ですし、JMXを通じてパフォーマンスのメトリクスを公開すれば、パフォーマンス低下の際に警告するモニターを設定できます。さらには、log4jのような広く使われているロギングフレームワークと自らのタイミングステートメントがうまく連携するようにしたいのです。
Perf4Jの目標は、こうした機能を簡単に統合できる(そして簡単に拡張可能な)オープンソースのパッケージとして提供することです。Perf4JはHomeaway.comで開発されましたが、Homeaway.comのインフラは広く分散した性質を持っており、その上、このWebサイトには高可用性、高パフォーマンスという必要条件もあるので、徹底的なパフォーマンス解析が必要となります。Perf4Jの重要機能には以下が含まれます。
これからお見せする例では、ほとんど労力を使わずに、いかにしてこうした機能を利用できるかにスポットライトを当てます。コードベースにPerf4Jを統合する方法の詳細については、Perf4J Developer's Guide(Perf4J開発者ガイド)をご覧になるようお勧めします。
org.perf4j.LoggingStopWatchクラスは、コードへのタイミングステートメントの追加と、出力ストリームやログファイルへのステートメントのプリントに使用されます。
StopWatch stopWatch = new LoggingStopWatch();
//... execute code here to be timed
stopWatch.stop("example1", "custom message text");
stop()メソッドへの呼び出しは、実行時間を記録し、ログメッセージをプリントします。デフォルトでは、ベースのLoggingStopWatchクラスはSystem.errストリームに出力をプリントします。しかしほとんどの場合、Log4JStopWatchやCommonsLogStopWatch、Slf4JStopWatchといった人気のあるJavaロギングフレームワークもしくはロギングファサードに一体化するLoggingStopWatchサブクラスを使った方がよいでしょう。ストップウォッチの出力サンプルをいくつか以下に挙げました。
start[1233364397765] time[499] tag[example1] message[custom message text] start[1233364398264] time[556] tag[example1] message[custom message text] start[1233364398820] time[698] tag[example1] message[custom message text]
デフォルトのストップウォッチ出力が、System.currentTimeMillis()の直接呼び出しを大きく改善したことにはなりませんが、本当のメリットはこの出力を解析して総合的な統計とグラフを作成できることから生まれます。LogParserは、タグとタイムスライスで出力をグループ化し、詳細な統計情報を生成し、オプションとして、Google Chart APIを用いて時系列グラフを生成します。デフォルトのテキストフォーマット(csvフォーマットもサポート)を使ったサンプル出力は以下のとおりです。
Performance Statistics 20:32:00 - 20:32:30 Tag Avg(ms) Min Max Std Dev Count codeBlock1 249.4 2 487 151.3 37 codeBlock2.failure 782.9 612 975 130.8 17 codeBlock2.success 260.7 6 500 159.5 20 Performance Statistics 20:32:30 - 20:33:00 Tag Avg(ms) Min Max Std Dev Count codeBlock1 244.0 7 494 150.6 41 codeBlock2.failure 747.9 531 943 125.3 21 codeBlock2.success 224.1 26 398 106.8 21 Performance Statistics 20:33:00 - 20:33:30 Tag Avg(ms) Min Max Std Dev Count codeBlock1 289.3 10 464 141.1 22 codeBlock2.failure 781.1 599 947 135.1 8 codeBlock2.success 316.2 115 490 112.6 13
平均実行時間とトランザクション/秒のグラフは、Google Chart Serverに対するURLとして生成されます。

LogParserはデフォルトで標準入力から読み込むので、動作中のサーバーからLogParserへログファイルをパイプすることにより、生成された出力をリアルタイムで入手できます。
tail -f performance.log | java -jar perf4j-0.9.8.1.jar
Perf4Jの拡張機能の多くは、log4jのカスタムアペンダ群を介して利用可能になります。これにより開発者は、多数のJava開発者に馴染み深いロギングフレームワークを介して、解析・モニタリング機能を漸次追加できるようになります(そしてPerf4Jの将来のバージョンでは、カスタムのlogbackアペンダとjava.util.loggingハンドラが提供されます)。そうした価値ある機能性により、Perf4JはJMX MBeans上でパフォーマンスデータを属性として公開し、許容されるしきい値をパフォーマンスが下回った際には、JMXに通知を送付できるようにします。Javaアプリケーションの管理とモニタリングではJMXが標準インターフェースとなったので、Perf4J MBeanの公開により、サードパーティ製のモニタリングアプリケーションが提供する様々な機能へと、選択の道が開かれます。たとえば、Homeawayでは、IT部門はシステムモニタリングをNagiosとCactiに標準化しています。両ツールともMBeansをデータソースとしてクエリすることをサポートしています。
以下のlog4j.xmlサンプルファイルを見れば、JMX向けにPerf4Jアペンダを有効にする方法がわかります。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/"> <!-- Perf4J appenders --> <!-- This AsyncCoalescingStatisticsAppender groups StopWatch log messages into GroupedTimingStatistics messages which it sends on the file appender and perf4jJmxAppender defined below --> <appender name="CoalescingStatistics" class="org.perf4j.log4j.AsyncCoalescingStatisticsAppender"> <!-- The TimeSlice option means timing logs are aggregated every 10 secs. --> <param name="TimeSlice" value="10000"/> <appender-ref ref="fileAppender"/> <appender-ref ref="perf4jJmxAppender"/> </appender> <!-- This file appender is used to output aggregated performance statistics in a format identical to that produced by the LogParser. --> <appender name="fileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="perfStats.log"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%m%n"/> </layout> </appender> <!-- This JMX appender creates an MBean and publishes it to the platform MBean server by default. --> <appender name="perf4jJmxAppender" class="org.perf4j.log4j.JmxAttributeStatisticsAppender"> <!-- The tag names whose statistics should be exposed as MBean attributes. --> <param name="TagNamesToExpose" value="firstBlock,secondBlock"/> <!-- The NotificationThresholds param configures the sending of JMX notifications when statistic values exceed specified thresholds. This config states that the firstBlock max value should be between 0 and 800ms, and the secondBlock max value should be less than 1500 ms. You can also set thresholds on the Min, Mean, StdDev, Count and TPS statistics - e.g. firstBlockMean(<600). --> <param name="NotificationThresholds" value="firstBlockMax(0-800),secondBlockMax(<1500)"/> </appender> <!-- Loggers --> <!-- The Perf4J logger. --> <logger name="org.perf4j.TimingLogger" additivity="false"> <level value="INFO"/> <appender-ref ref="CoalescingStatistics"/> </logger> <!-- The root logger sends all log statements EXCEPT those sent to the perf4j logger to System.out. --> <root> <level value="INFO"/> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.SimpleLayout"/> </appender> </root> </log4j:configuration>
Perf4JはJMXアペンダのほかにも、Perf4Jのグラフ化サーブレットを利用するWebフロントエンドを介して公開可能なパフォーマンスグラフを生成する、グラフ化アペンダも提供します。カスタムのcsvレイアウトにより、Excelや他のスプレッドシートプログラムに簡単にインポートできます。
コードにパフォーマンスロギングのステートメント(ならびに、ロギングステートメント一般)を追加した場合のデメリットの1つに、コードの「全情報と有用情報」比(SN比)が低下し、特定のコードブロックのクリティカルなビジネスロジックの追跡がいっそう難しくなってしまうことがあります。この軽減に役立つように、Perf4Jは@Profiledアノテーションを提供しますが、実行時間をログすべきメソッドにこのアノテーションを追加することにより、そのメソッド本体にはStopWatchコードを入れないですみます。
@Profiled(tag = "dynamicTag_{$0}")
public void profiledExample(String tagSuffix) {
... business logic only here
}
@Profiledアノテーションの追加がすめば、AspectJやSpring AOPといったアスペクト指向のプログラミングフレームワークを使って、Perf4Jのカスタムタイミング・アスペクトを有効化できます。このアスペクトは、StopWatchインスタンスの作成と停止を行うバイトコードを使って、メソッド呼び出しを取り囲みます。AspectJのロード時ウィービング機能を使って、ランタイムの特定クラスについてタイミング・アスペクトを選択的に有効化することさえ可能です。ですから、ロードタイム・ウィービングを使うことにより、プロファイリングを作動させていないメソッドに対して、オーバーヘッドが発生することは絶対にありません。
この例では、Perf4Jライブラリがもつ機能の大部分を説明する、実際のアプリケーションの作成ステップを最初から最後までお見せします。自分でこのアプリケーションを実行するには、perf4jPrimes.warファイルをダウンロードし、サーブレットコンテナで実行します。warファイルには、アプリケーションを作成するために使われたソースコードも入っているので、ご注意ください。
単純にする目的で、この例にはメインコードファイルが2つしか入っていません。生成された素数を表示し、ユーザー指定のパラメータの受け入れに使用するprimes.jspファイルと、実際の生成コード(その大部分はjava.math.BigIntegerクラスにデレゲートされます)が入っているPrimeNumberGeneratorクラスです。コードブロックの時間計測にPerf4Jを使用する場所が3つあります。
WEB-INF/classes/log4j.xmlファイルを見れば、Perf4Jの以下の機能が有効化されたことがわかるでしょう。
WebサーバーでこのWebアプリケーションをいったん起動すれば、http://servername/<rootcontextlocation>/primes.jspの素数生成ページにアクセス可能になり、そのページではWebサーバーの設定によってrootContextLocationが決定されます(簡単なアクセスで、http://servername/<rootcontextlocation>/PrimeNumberGenerator.javaでもPrimeNumberGeneratorソースコードを見ることができます)。primes.jspページでは、素数を生成する方法を決定する様々なパラメータをお見せします。パラメータを変更し、「Generate Prime Number」(素数を生成)ボタンをクリックすれば、数の生成に要する時間にパラメータがいかに影響しているかがわかります。数をたくさん生成した後は、Perf4Jの出力を以下の3ヵ所で見られるはずです。
この時点では、@ProfiledアノテーションをサポートするTimingAspectsをまだ1つも有効化していないので、表示される唯一のストップウォッチ出力は「fullPageGeneration」タグ向けになります。TimingAspectsを有効化するには、AspectJのロード時ウィービングを利用できます。有効化するには、次のようなAspectJのウィービングエージェント・コマンドライン・パラメータを使って、Webサーバーを起動する必要があります。
-javaagent:/path/to/aspectjweaver-1.6.1.jar
以下のアドレスで、このjarをダウンロードできます。http://mirrors.ibiblio.org/pub/mirrors/maven2/org/aspectj/aspectjweaver/1.6.1/aspectjweaver-1.6.1.jar
エージェントが有効化されると、「generatePrime」と「randomFromRandomDotOrg」のタグ名にストップウォッチ出力が表示されるはずです。
アプリケーションをモニタリングする多数の試みにおいて、パフォーマンスや安定性、セマンティックの正確性など、そのモニタリングの目的にかかわらず、意図されたメリットを最適にもたらすことに失敗しています。その原因は、集めた情報が膨大すぎて、データの洪水の中を進むのが難しくなってしまうか、必須の情報が最も必要とされるポイントで十分に情報収集されていないかのどちらかです。そして、あらゆるモニタリングでいくらかのオーバーヘッドが発生しますが、パフォーマンスモニタリングについては、追加の間接費に特に敏感であるべきです。以下に挙げた秘けつは、意図しない影響を最小に抑えながら、Perf4Jを最大限活用するのに役立つでしょう。
Perf4Jの開発は活発に行われており、新しい機能が頻繁に追加されています。たとえば、Perf4Jの将来のバージョンでは、別個のconfigファイルを使ってプロファイルするメソッドを指定できるようになるので、オリジナルのソースコードにアクセスできない場合でさえ、メソッドの実行時間を計測できます。ユーザーのフィードバックとニーズを踏まえて、全機能の優先順位をつけているので、将来の機能の方向付けに役立たたいと思うなら、今すぐPerf4Jを試してみてください。さらによいことに、Perf4JはApache 2ライセンスのもと、完全にオープンソースであり、コードも完全に文書化されているので、希望のままに拡張することができます。
今すぐPerf4Jをダウンロードして、意見をお聞かせください!
Googleのクラウド環境をつかったGoogle App Engineによる開発するにあたり、初めての試みで苦悩する開発者達の経験をもとに、各開発フェーズにあわせて問題点やどう解決したかをご紹介します
去る1月12日、定理証明支援系ツールCoqの初心者向けチュートリアルが開催さ れた(http://kokucheese.com/event/index/23667/)。今後も2月2日 (http://kokucheese.com/event/index/23744/)、2月9日、2月16日と引き続き開 催されていく予定である。本記事では、開催の様子をレポートする。
Neal Gafter氏はOracleによるJava買収の影響に関する議論、Javaにセグメンテッドスタックやメタオブジェクトプロトコルを追加することについての主張、そしてJavaとC#との比較について話をしてくれた。
GoogleはVMをともなう新しい言語であり、JSコンパイラでもあるDartをプレビューした。 InfoQはDartのアプリの構築に貢献する文法の裏側を探った:スナップショット、Isolate、モジュール方式
本記事ではCSPベースの「マルチドメイン・モデル検査ツール」である、PAT(Process Analysis Toolkit)について紹介する。モデル検査は、形式手法(Formal Method)という方法論を基礎とする技術であり、複雑さが増大しながらも安全性を求められる、現在のソフトウェア開発の状況に対する処方箋の1つとして注目されている手法である。
前回まで、Jenkinsの幾つかの側面に注目して解説をしてきました。シリーズ最後の今回は、Jenkinsをサービスとして使う方法を紹介します。
Alloyは、MITにて開発された仕様記述言語であり、ツールによる自動解析を使い、インクリメンタルに形式仕様が書けることが特長である。筆者らはAlloy開発者による、Alloyを使った形式手法入門書を翻訳、今夏にオーム社より刊行した。本記事では、Alloyの簡単な概要と、翻訳書『抽象によるソフトウェア設計』(「Alloy本」)を紹介する。
スマートフォンを中心としたマルチデバイスにおけるタッチユーザーインターフェイスへの対応は、既に必須の項目となりつつある。本記事では、Windows デバイスにおける UX のベースとなっている「メトロ」というデザイン言語を掘り下げながら、既存環境を意識しつつもどのようにタッチユーザーインターフェイス開発に取り組んでいくべきであるかについて解説していく。
No comments
スレッド表示 返信