こんにちは、html5jパフォーマンス部、スタッフの川田です。5月8日ですが、私たちのコミュニティ主催で勉強会を開催することになりました!!
そして、残念なお知らせです。募集した直後に、席が埋まってしまいました!せっかく、これだけ多くの方にパフォーマンスへ興味を持っていただいたのに、このままじゃもったいない!
なので本記事では、この勉強会で語られない、別の切り口からパフォーマンスについて語ってみようかと思います。内容は、私が技術評論社「Software Design 2014年5〜7月号」にて連載しております、「Web標準技術で行う、Webアプリのパフォーマンス改善」で扱っているテーマの一部を、Web向けに書き直したものです。
Webアプリのパフォーマンス計測は簡単なのか?
パフォーマンスは、メモリを節約するものからCPUコストを下げるものまで、様々な種類があります。本記事では「ターンアラウンドタイム(TAT)」という指標値について考えてみましょう。
TATとは、アプリケーションの応答速度を表す指標の一つです。厳密には、あるアプリケーション・サーバに対して、ユーザが何かしらの操作・入力を行ってから、アプリが反応し終わり、ユーザが再び入力を受け付けることができるような状態になるまでの時間、と定義されています。Webページが遷移する時間を、定量的に評価できる指標値ということになります。
このTATという考え方、そんなにマニアックなものというものでもなく、レスポンスタイムやスループット、アベイラビリティなどと同様に、古くから存在する非機能要求の項目です。IPAの情報処理試験でもよく見かける、有名なキーワードに思えるでしょう。ところが、これをWebを検索しても、なかなかしっくりくる計測手段が見つかりません!この問題、特にWebに限定した話というものでもないはずです。GUIレベルでの性能計測は、昔からある悩みの一つで、アナログにストップウォッチの力を借りるなんてことも割とよく聞く話です。筆者もIE6全盛のWebアプリ開発で、同じ悩みを抱えたことがあります。
今回、そんなTATをめぐる悩みに対して、ちょっとしたヒントをご紹介します。ブラウザの仕組みを探り、WebアプリのTATとは何かを探り、そして標準的な手段の中からその計測方法について探ってみましょう。「そもそも、そんな指標で評価することに価値があるのか!?」なんて議論も生じていたりするのですが、その点は一番最後に触れるとして、今回はTATという切り口からWebページの性能について考えてみます。
TATの計測で、Webサーバのログはアテになるのか?
SPDYなどの新しいプロトコルのことは一旦忘れて、シンプルなHTTP1.Xを前提に考えてみて下さい。HTTP1.Xは、HTMLドキュメント取得し、HTMLドキュメント内で参照されている必要なJavaScript/CSS/画像などの外部リソースを、逐次取得し表示していくという仕組みです。サーバサイドで動的にHTMLを生成するようなアプリだと、画面を遷移する都度、最低でもHTMLドキュメント程度はサーバ側から取得することになります。
この動きに注目し、計測で非常によく利用されるのが、Webサーバログの「リクエスト処理時間(Time taken to process the request)」です。Apache HTTP Serverのアクセスログのフォーマットオプション「%D」あたりは有名でしょう。このオプションは、HTTPリクエストを受け付けた瞬間から、サーバで処理が行われ、データを出力し終わるまでの時間を、マイクロ秒単位で計測する機能です。TomcatやJBossのようなJavaミドル、MicrosoftのIIS(Internet Information Services)でも、リクエスト処理時間をミリ秒で計測できる機能を実装しており、大抵のWebアプリでは活用できるコモディティ化した機能と言えます。
リクエスト処理時間は、実際にサーバ上の問題を発見するのに価値が高い計測値です。運用時には、キャパシティプランニングの目安や、障害発生時の解析に活用されたりします。また、お客様と品質保証の明確な基準を決める「SLA(Service-Level Agreement)」でも、アクセスの何%を保障するかという「パーセンタイル」を配慮した形で活用することがあります。どこにでも目にするこの計測値、一見すると使い道が広く、万能な値に見えるでしょう。
ところが残念なことに、リクエスト処理時間は、キャッシュされていないごく一部のファイル/プログラム単位の性能しか評価できません。サーバがどの程度のリクエストを捌けるのかを判断する「スループット(=処理能力)」の指標値として扱うには高い価値を発揮しますが、TATの指標値として扱うには、対象が局所的で、不足が大きすぎます。サーバから見ると性能は高いのに、クライアントで見ると画面はいつになっても白いまま!なんてことになりかねません。
では、TATを計測するにはどうすればよいのでしょうか?画面を表示する際のもっさり感の原因は、どのように探ればよいのでしょうか?このあたり、最近のWeb標準がかなり力を入れています。2012年12月にW3C勧告となった「Navigation Timing(ver.1)」がまさにその代表的なスペックです。
Navigation Timingを含むWebのパフォーマンスに関する仕様は、2010年にW3Cで設立された「Web Performance Working Group(WebPerf WG)」で議論され、IE9+、Firefox、Chromeなどのブラウザにその成果が反映されています。Facebookのザッカーバーグ氏がHTML5に失望し、同社のアプリをネイティブに書き換えるという有名な事件がありますが、そんな彼らも同WGの設立直後すぐに反応し、WGの議論に参加しています。2013年には「Web vs ネイティブ」という議論が盛り上がりましたが、WebPerf WGの取り組みは、現在のWebが抱える性能という問題を見つめていく上で、注目すべき重要なポイントと言えるでしょう。
Navigation Timingの使い方、TATの計測方法
Navigation Timingでは、ハイパーリンクをクリックした瞬間からWebページが利用できるようになるまでを、ブラウザの内部的な動作である「処理モデル(Processing Model)」として定義し、その経過時間を取得することができます。
ブラウザ自体にも「開発者ツール」として計測のためのツールが備わっていますが、ブラウザごとに考え方も違うし、活用できる場も開発時のみと非常に限定的です。Navigation TimingはWeb標準なので、ブラウザに依存しない共通の考え方で計測値を扱え、また運用時にもJavaScript上で生のデータを収集することができる点で、開発者ツールより高いポテンシャルを得ています。
実際のJavaScriptの仕様を見ながら確認してみましょう。
windowオブジェクト配下にある「performance」は、パフォーマンス関連のJavaScript APIにアクセスするための入り口となるオブジェクトです。そのさらに下に、WebPerf WGの成果である様々なスペックの実装が分類別で並んでいます。そのうちのひとつである「timing」の配下には、ハイパーリンクをクリックしてから応答するまでの間に発生する、様々な動作発生時のタイムスタンプを取得できるプロパティが並んでいます。
TATを取得しコンソールに表示させる、シンプルなコードを確認し、使い方を掴んでみましょう。
/* timingオブジェクトの取得 / var timing = ( window.performance || {} ).timing; / TATの計測 */ timing && window.addEventListener( "load", function() { setTimeout( function() { var tat = timing.loadEventEnd - timing.navigationStart; console.log( "TAT = " + tat ); },1); },false);
「timing.navigationStart」はハイパーリンクがクリックされた直後の時間、「timing.loadEventEnd」はWebページが表示されJavaScriptのloadイベントの処理が完了した直後の時間が取得できるプロパティです。サンプルでは、この2つの単純な差分を、仮にTATとしてみました。setTimeoutで実行時間を遅延させているのは、loadEventEndがloadイベント中だと未計測の状態「0」を返してしまうという問題への対策です。
このサンプルで得られる計測値が、TATとして「ほぼ正解」の値ということになります。ただ、ほぼ正解であって、完全な正解とは言えません。このあたりの理由については、ブラウザの内部のメカニズムによるところが大きかったりします。具体的には何が原因なのか、これから見ていきましょう。
※ 修正 2014.5.11:矢倉 眞隆さんからのご指摘により、サンプルのwindow.performanceのベンダプレフィクスは削除しました。IE9+を含む近年のブラウザでは、3年近く前にベンダプレフィクスが消えており、無意味であると判断できたためです。