タグ : O’reilly

ハイパフォーマンスWebサイト – 高速化ルールまとめ

ちょうど1年前のこの時期(11月頃)、O’rilleyの「ハイパフォーマンスWebサイト」を参考に「琉九祭」という沖縄の9つの大学の学生が運営するお祭りの公式ページで高速化のルールを実践してみた。このサイトの作成は自分一人で行なった。(デザイン/画像は芸大の子が担当

作成したイベントページ

作成したイベントページ


(2009年度はは公式サイトは作らないのかな?ブログはたててるみたいだけど。。

1年経って

最近、ハイパフォーマンスWebサイト構築に関するプレゼンを大学内部の勉強会で行う機械があり色々調べ直したりした。ついでに本の方でも紹介されている高速化のルールについてブログにもまとめておく。
(注意! 本に載っているルールを全部紹介するわけじゃないです。また、本に載ってないルールもあったりします。ほんの内容が知りたい人は、本家で確認を。

サイトを高速化するには?

本によると、フロントエンド(HTMLをダウンロードしてから、解析,各コンポーネントのダウンロード,描画にかかる時間)がサイトパフォーマンスの8割を閉めていると書かれている。

米Yahooのダウンロード時間推移

米Yahooのダウンロード時間推移

HTMLの内容次第で、それ以降のコンポーネント数は減らす事ができるからそれらをまとめてフロントエンドと読んでいるんだろう。
ダウンロード時間をグラフや、サイトの各種統計はSafariなら標準機能のWebインスペクタ、FirefoxならYslowなどのハイパフォーマンスWebサイトの診断プラグインで見る事ができる。SafariのWebインスペクタは個人的にお薦め。(いや、見た目が奇麗なだけでね。

SafariのWebインスペクタ

SafariのWebインスペクタ

以下、高速化のルールを列挙

リクエストを減らす

コンポーネントを減らす事 = HTTP Requesetの数を減らすルール

CSS Sprite

複数の画像を1つにまとめて、CSSのbackground-positionで個々の画像として見せるテク。
Youtubeとかのソレが分かりやすいかも。

ここで、1ページの全ての画像を全てまとめるわけではなく、例えば各ページで共通の画像毎でグルーピングしてまとめる方がExpires-Headerの恩恵が受けやすかったりする。

Image-Map

1つの領域内部(画像やdivとか,マップという)に、複数領域を指定してリンクを張るテク。
マップ全体を<map>タグで指定して、内部の領域は<area>で指定。areaの形には四角(rect)/円(circle)/多角形(poly)等が使用できる。(多角形とか使う状況あるか?そもそもImage-Map自体あまりないか:-)

Image-Mapを利用すると、ツールバー/メニューが1つの画像で済んだりすると。ほとんどはCSS Spriteで代用できるかも。

Merge(src)

CSSやJavascriptなどの外部ファイル(ソース)は、マージしてファイル数を減らすということ。
Javascriptの場合は、名前空間や実行の関係で1つのファイルにまとめられない場合とかもあるので注意。

CSSやJSを1つのファイルで編集していくのはさすがに管理の手間が増えるので、リクエストに合わせてマージしたファイルを応答するようなPHPでも組むのが無難。
以下は、複数のCSSファイルを1つのファイルにまとめて、さらに空白や改行などを抜きさるSnipet

 <?php
header("Content-type: text/css");
$css =  file_get_contents("yui_reset.css");
$css .= file_get_contents("base.css");
$css .= file_get_contents("style.css");
$css .= file_get_contents("lightview.css");

$css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);
$css = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $css);
echo $css;
?>

マージしたファイルを生成するスクリプトとして使用するのもあり。

Expires-Header

Expiresヘッダは、コンポーネントにユーザがキャッシュする期間を設定するHTTPヘッダに含まれる情報。
Expiresヘッダで期限が設定されていると、キャッシュ期限内ならリクエスト自体送られなくなるので2回目以降の描画がかなり速くなるそれ。(ただし、リロードされた場合はIf-Modified-Sinceという更新確認のリクエストが送信される。

ぶっちゃけると、Exipresヘッダとgzipを行なえばyslowのスコアは劇的に上がる。(実際、FからC~Bぐらいに上がった記憶が。。

.htaccessなどで設定が可能。
以下は、画像やCSS,JSflashなど主なファイルに期限を設定しているSnipet

<FilesMatch "\.(png|jpg|gif|swf|css|js|gz|JPG)$">
            Header set Expires "Thu, 31 Dec 2010 16:00:00 GMT"
            FileETag None
</FilesMatch>

Pre-Loading

全体のルールの中で一番トリッキーだと感動したのがこれ。(他は思いつくよね。
トップページなど最初に表示されるページで、次のページの画像などを先に読み込んでおいてキャッシュさせるというテク。(うーむ

JSのonloadで画像の読み込みなどを行なわせればOK。
Google Analyticsとかのアクセス解析サービスでは、ページの遷移の統計が取れるので、1番表示されるページの次に1番進まれるページとかも把握できる。なので進まれると予想するページの画像を先読みしておくのはかなり上手い手段。

Googleも、検索ページでPre-Loadingを行なってたりする。onloadで検索結果ページのナビゲーションが像を先読みしていますね。

ナビゲーション

ナビゲーション

Pre-LoadingのSnipetはGoogleから引用。

<body onload="document.f.q.focus();if(document.images)new Image().src='/images/nav_logo7.png'">

上では、bodyが読み込まれたら検索ボックスにフォーカスして画像を読み込んで(new Image)いますねー。
この自動フォーカス機能、ほんのちょっとの機能だけどあるとないとでは絶望的な差があるよなー。

通信量を減らす

コンポーネントの数を減らしたら、次はコンポーネント毎のサイズを小さくする工夫を。
先に紹介したルールは1つのコンポーネントが肥大化しがちになる。圧縮/最適化アルゴリズムは対象が大きいほど効率が良くなるのが普通なので非常に具合が良い。

gzip

httpdの設定でコンテンツを圧縮する事が可能。 (mod_deflate)
ただ、mod_deflateはサーバ側でgzipを行なって、しかも圧縮ファイルをキャッシュしないのでCPU使用率が若干あがる点もあったりする。(圧縮ファイルをキャッシュするモジュールも作られてるみたい。使用確認はとってないのでどうともいえないが。。mod_cache_deflate

自分がイベントのページ運営していたXREAさんでは、mod_deflateが有効になっていなかった(と思う)ので自前で圧縮掛けたファイルをアップし、リクエストURLを書き換えて圧縮ファイルを参照させるという手段をとっていた。
そのときの.htaccessの設定例

#gzip
RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME} \.js$ [OR]
RewriteCond %{REQUEST_FILENAME} \.css$
RewriteCond %{REQUEST_FILENAME} !\.gz$
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule .+ %{REQUEST_URI}.gz

<FilesMatch "\.js\.gz$">
    ForceType application/x-javascript
    AddEncoding x-gzip .gz
</FilesMatch>

<FilesMatch "\.css\.gz$">
    ForceType text/css
    AddEncoding x-gzip .gz
</FilesMatch>

gzipに対応していないクライアント(ブラウザ)があったりするので、非圧縮のファイルも挙げておかなきゃだめだったりする。
圧縮を掛けるのはcssとjsなどのテキストファイルで、画像ファイルなどは既に圧縮されたフォーマットだからgzipなどの効果は全然でないので圧縮は掛けない方向で。(ここらへん適当

Optimize(img)

テキストは圧縮。画像は最適化。それぞれの画像フォーマットに応じた最適化ツールがあるのでそれらを試す。
Wikipedia先生によると

ほとんどの画像でPNGはGIFより圧縮率が高い。

JPEGは、主に写真的なイメージデータを非可逆圧縮することでPNGよりも小さなファイルサイズに収めることができる。そのためPNGで、高画質に設定したJPEGと同程度の品質を得ようとすると、ファイルサイズはJPEGの数倍(大抵は5〜10倍程度)になる。

とのこと。(ここらへん良くわからん

自分が作成したイベントページでは、PNGをメインに使用していた。PNGの最適化ツールにはoptipngなるコマンドラインツールがある。

また、Smush.itという、最適化したいページのURLを渡したらそのページ内の画像をごっそり最適化してダウンロードできるWebサービスがあるっぽい。それは便利かも。
Smush.itの運営元はYahoo Developerチーム(Yslowと同じ)

Compress(src)

ここでいうcompressはzipなどでの圧縮ではなくて、ソースコード自体を空白/コメントを除去して圧縮することを意味している。
Javascript/CSSのコメント/空白/改行の除去はYahooの提供するyuicompressorというJavaによるツールが使える。

また、JavascriptではPackerなど圧縮サービスが色々あったりする。(辞書式圧縮やら
JavaScriptの圧縮の記事で細かく説明されていたり。

構造を最適化する

レンダリングの行程に注目した最適化、レンダリングエンジン内部の細かいお話は、Web+DB vol50から連載されている「Webkit Quest」という記事が取り上げていたりする。(現在ちょっと読んでます。

Put Stylesheets at the top

DOMツリーを構築する前にスタイルの情報がそろっていると逐次レンダリングが行ないやすいというお話。IE6の場合、CSSがHTMLファイルの一番下で読み込まれているとCSSが読み込まれるまで何も表示されないらしい。

Put Scripts at the bottom

JSが実行されている間は、他のコンポーネントのダウンロード/レンダリングが行なわれないというお話。
これはおそらく、JSのdocument.writeによってDOMが直接書き換えられる可能性があるから、とかなのかな?
使用するJSにdocument.writeなどが使用されていない証明としてdefer属性を付加する事で、ダウンロード/レンダリングを妨げないらしい。
処理時間のかかるJSをHTMLのトップで読み込んだ読み込んだ
上の例では10秒スリープさせる処理を行なっているので、最初の10秒間はコンポーネントのダウンロードすら行なわれない。

W3C Validator

これは恐らくあまり実行時間には関係ないかもしれないけど、W3Cの仕様にのっとったHTMLを書く事でエンジンさんの負担を下げれるんじゃね?という話。
Web+DBのWebkit Questでは「さまざまなエラーチェックが実装の大半を占めている」とか。ここらへん実際ソースみないと物も言えないよなー。 ってことで閉口。

また、プレゼンの場で「仕様に乗っ取るようにコーディングして、コード量が増えて逆に時間掛かったりしないの?」などという指摘もあったりした。
うーん、ここらへんは実際時間はかってみないとなー。でも、恐らく微々たる差なのだろう。

まとめ

「ハイパフォーマンスWebサイト」に載っているルールを全て(CDN意外!><)適用し、Yslowや各種ブラウザの解析ツールを仕様して色々高速かしていった結果、イベントページはYSlowで96点(Yslow V2)という評価を得た。

Yslow スコア

Yslow スコア


実際に、高速化を行なう前と後では 3s -> 0.8msぐらいはっきりと差が出た。一番嬉しかったのは、高速化に気付いてくれた人たちの言葉でした。高速化とうネタで圧縮からレンダリングの行程、(ここでは取り上げてないけど)ネットワーク的なお話など色々な知識が学べた。

でも

やっぱ、CMSに任せてたいですよね。こういうことは。(イベントページは全て手書きで作成
Wordpressでも高速化プラグインをいくつか試してみたり。

ところで、このブログは表示遅くない?

はい、それはWebサーバのスペックが低いからです。そればっかりはどうしようもないです。。
近々CPU/マザボ/メモリを買い替えてスペックを増強する予定! (お金が…!

 
Better Tag Cloud