<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>performance &#8211; HTML5Experts.jp</title>
	<atom:link href="/tag/performance/feed/" rel="self" type="application/rss+xml" />
	<link>https://html5experts.jp</link>
	<description>日本に、もっとエキスパートを。</description>
	<lastBuildDate>Sat, 07 Jul 2018 03:14:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.19</generator>
	<item>
		<title>この1年、Webのパフォーマンスで変わったことは？──HTML5 Conference 2016</title>
		<link>/furoshiki/21501/</link>
		<pubDate>Thu, 27 Oct 2016 00:00:26 +0000</pubDate>
		<dc:creator><![CDATA[川田寛]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">/?p=21501</guid>
		<description><![CDATA[連載： HTML5 Conference 2016 特集 (6)こんにちは、ふろしきです。HTML5 Conference 2016の当日は、38度近くの熱があり、発表時はろれつが回ってませんでした。しかし、伝えたいこと...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/html5-conf2016/" class="series-403" title="HTML5 Conference 2016 特集" data-wpel-link="internal">HTML5 Conference 2016 特集</a> (6)</div><p>こんにちは、<a href="https://twitter.com/_furoshiki" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ふろしき</a>です。HTML5 Conference 2016の当日は、38度近くの熱があり、発表時はろれつが回ってませんでした。しかし、伝えたいことは伝えられたと思っています。その内容とは…</p>

<p>「この1年でWebのパフォーマンスの技術にどんな動きがあったのか」</p>

<p>というダイジェスト。ここで話した3つのテーマについて、本記事でもご紹介。</p>

<p><img src="/wp-content/uploads/2016/10/kawada2.jpg" alt="" width="640" height="455" class="alignnone size-full wp-image-21557" srcset="/wp-content/uploads/2016/10/kawada2.jpg 640w, /wp-content/uploads/2016/10/kawada2-300x213.jpg 300w, /wp-content/uploads/2016/10/kawada2-207x147.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<h1>1. レイアウト処理を減らす</h1>

<p>HTML5がバスワードするよりもずっと前から、CSSでアニメーションさせることはごくごくあたりまえ。JSが扱えないデザイナーであっても手軽にアニメーションできる良い世界になりました。しかしそこに、モバイルが出現したことで、JSだけで満足という人たちもCSSの機能を活用しなくてはいけなくなりました。</p>

<p>モバイルのUIによくありがちなのが、あるコンポーネントの形状を変化させるようなアニメーションや、スワイプ操作のような指の位置に応じてコンポーネントを動かすもの。それを描画するとなると、CPUはあまりにも非力で、GPUの力を借りることが求められています。CSSはGPUと相性がよいため、JSからCSSの機能を呼び出して効率的にGPUを活用するということが求められています。</p>

<p>そのアプローチについては、HTML5 Experts.jpでも「<a href="https://html5experts.jp/furoshiki/19276/" data-wpel-link="internal">モバイルWebのUIを速くする基本テクニックがわかる──Google I/O 2016 High Performance Web UI</a>」で紹介していますので、本記事では簡単にだけ説明。</p>

<p>GPUでできることは、極めてシンプル。ある四角形の描画結果を、どの位置に表示させるのか、拡大縮小させるのか、回転させるのか、といった変更加えるだけ。それだけでいいというのであれば、CPUを介さず、GPUのみで描画処理を完結させることができます。</p>

<p>これをブラウザで行う場合は、ある特定のDOMとその配下にあるDOMの描画結果をGPU側に転送し、GPU側にどういう描画を行わせるのか指示を送ることで、高速に処理させます。その間、操作はすべてCSSのプロパティを使って行うことになります。</p>

<p><img src="/wp-content/uploads/2016/10/3-1.jpg" alt="3" width="640" height="392" class="alignnone size-full wp-image-21515" srcset="/wp-content/uploads/2016/10/3-1.jpg 640w, /wp-content/uploads/2016/10/3-1-300x184.jpg 300w, /wp-content/uploads/2016/10/3-1-207x127.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p>CSSも、従来の <code>left</code> や <code>top</code> といった、レイアウトを操作するようなものではなく、 <code>transform</code> プロパティ経由で指定。 JS上で、以下のように指定することで、CPUによるレイアウト処理を避けつつ、GPUで描画の位置のみを変えるというもの。</p>

<p></p><pre class="crayon-plain-tag">// ある要素の横の位置を移動
elem.style.transform = `translateX(#{position}%)`;</pre><p></p>

<p>この方法は一昔前には泥臭いとされ、バッドプラクティスと考えられていました。しかしそれも、最近は <code>will-change</code> というCSSプロパティが正式に標準化の流れに入ったことで、考えが改められています。GPU上に描画結果を保存させるのはバッテリー消費が大きいため、開始時に <code>will-change: transform;</code> で有効にし、終了時には <code>will-change: none;</code> で解除する、という流れになります。</p>

<p>簡単な例をあげると、以下の通りです。</p>

<p></p><pre class="crayon-plain-tag">// スワイプ時、指の位置にあわせてコンポーネントを左右に動かす。
class MovableComponent {
  constructor(elem) {
    this.elem = elem; // 動かす対象のコンポーネントのDOM
  }
  // ある要素の横の位置移動を開始
  function begin(beginX) {
    this.x = beginX; // 開始位置をセット
    this.elem.style.willChange = 'transform'; // GPU側に描画結果を置く
  }
  // 位置を変更(指の位置がかわるごとに呼び出される)
  move(currentX) {
    this.x = currentX; // 現在の位置をセット
  }
  // 描画(requestAnimationFrameで毎回呼び出される)
  render() {
    this.elem.style.transform = `translateX(#{this.x}px)`;
  }
  // 横移動の完了
  end() {
    this.elem.style.willChange = 'none'; // 解除
  }
}</pre><p></p>

<h1>2. スクロールイベントを減らす</h1>

<p>ブラウザのscrollイベントが、スクロールの滑らかさを落としてしまう。とはいえ、「どれだけスクロールされたのか？」というのに応じて何かしらのJSの処理を動かしたくなるという需要はなくならず、できるかぎりパフォーマンスを上げようという努力はされてきました。</p>

<p>2015年の4月にChromium Blogにポストされた「<a href="http://blog.chromium.org/2015_04_01_archive.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Chromium Blog
News and developments from the open source browser project
</a>」は有名な話です。Chromeではブラウザ上で動作するタスクに優先度を与え、JSの処理やブラウザ側の内部で行われる処理のうち、スクリーン上への描画が関わるタスクを優先的に扱うようにすることで、スクロールの滑らかさを損なわないようにしようという取り組み。確かに、ユーザーの体感としてパフォーマンスは上がったようにみえるでしょう。</p>

<p>しかしこの問題、その本質は、イベント自体が無駄に多く呼び出されてしまっているというところが大きかったりします。したがって、ユーザーワールド側でも、scrollイベントを毎回素直に実行するのではなく、頻度を落として実行するThrottlingという方法が一般的になっています。</p>

<p>これらはパフォーマンスを改善する上で、たしかに有効ではあります。ただ、デベロッパーが本当にやりたいことに目をむけ、そこにより特化した機能をブラウザ側が持てば、もっと良い解決につながるのは間違いありません。ハードウェアが貧弱で、スレッドの扱いに制約の多いブラウザでは、そこに踏み込んだアプローチが求められています。</p>

<p>scrollイベントの利用ケースで、かなり多いもののひとつに「画像の遅延読み込み」があげられます。例えば、ATF(Above The Fold : Webページアクセス直後にスクリーン内に映り込む領域)の表示を速くしたい！それこそ、headタグ内の大量のCSSファイルやトップの巨大な画像ファイルに帯域を譲らないことには高速化が困難ということになれば、ATF外にある画像ファイルは後から読み込んだほうがいい、ということになります。もちろん、サーバーの負荷を下げるという用途でも活用されるでしょう。</p>

<p>それを解決する方法として、Web標準「<a href="https://www.w3.org/TR/resource-priorities/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Resource Priorities</a>」にて、lazyloadというプロパティをHTMLのタグに追加しようという流れが生じ、IE11にも実装されたのですが、「そもそもそういう用途で使われるようなプロパティは追加されるべきなのか？」「本来JSであったり、より低レイヤーなアプローチで解決すべきでは？」という意見もあり、削除されてしまいました。</p>

<p>あれから2年が経ち、lazyloadは理想的な形で実現できるようになりました。それが「<a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Intersection Observer</a>」です。</p>

<p>Intersection Observerは、スクロール時に特定のDOMがスクリーン上に現れるタイミングでイベントを発火させてくれます。したがって、scrollイベントよりも軽量な上、scrollイベントの多くのユースケースを巻き取ることができます。そもそもDOMの位置を取得する、scrollTop、offset、getBoundingClientRect、といったプロパティやメソッドは、本記事の1章でもあげたような、レイアウト処理というヘビーな処理を呼び出しのタイミングで必要とする場合がある。それも無くなるとなれば、一石二鳥でlazyloadのような類の処理を最適化できるというわけです。</p>

<p>以下、使い方の例。jQuery.lazyloadのようなものを実装するとしたら、以下のようになります。</p>

<p></p><pre class="crayon-plain-tag"><!--
  画像を遅延読み込みさせる要素。
-->
<img src='dummy.gif' data-original='original.jpg' alt='hoge' class="lazyload"></pre><p>
</p><pre class="crayon-plain-tag">// 遅延読み込みをさせる専用のObserverを生成
let imageLazyLoader = new IntersectionObserver((changes) =&gt; {
  // イベント発火のタイミングで、遅延読み込みさせる
  changes.forEach((change) =&gt; {
    let image = change.target;
    image.src = image.getAttribute('data-original');
  });
}, {
  rootMargin: "120% 0" // 読み込みを開始するタイミング
});
// 遅延読み込みさせたいimg要素を取り出し、Observeさせる
let images = Array.from(document.querySelectorAll('img.lazyload'));
images.forEach((image) =&gt; {
  imageLazyLoader.observe(image);
});</pre><p></p>

<h1>3. タスクキューの待ちを減らす</h1>

<p>最後に、タスクの最適化の話です。ここの話については、ピクシブのブログのエントリー「<a href="http://inside.pixiv.net/entry/2015/12/24/182248" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">JSがブラウザを固めてつらいので、新しいAPI「requestIdleCallback」を使うことにした</a>」でも取り上げてますので、ざっくりと背景と概要を。</p>

<p>元々は、2016年頃にMicrosoft側が「setImmediateをちゃんと実装しよう！」と。Microsoftのプラットフォームにおいて、多くのユーザーがsetImmediateを利用しているということを、W3C Web Performance WGのMLで問題提議し、 <code>setTimeout(fn,0)</code> を使ってタスクを遅延実行させるバッドプラクティスを緩和しようという提案から始まった話です。こうした悩みは「requestAnimationFrameで解決されるものだ！」という意見もあったのですが、現実問題としてはそうはうまくいかないというのは、フロントエンドをやっているエンジニアなら感じられたはずです。</p>

<p>そもそもこの問題はどこから生じたのか？一昔前のビデオカードが、１つのスレッドでしか描画を扱えないという制約があった。そういった背景もあり、現在のブラウザもまた、ブラウザの内部の処理からJSで実装したユーザーワールドの処理に至るまで、その多くのUIスレッドと呼ばれる単一のスレッドだけで処理しざる得ない状況となった。その恩恵というべきか、JSはこれだけ単一スレッドで処理実行させることに進化したのですが！JSでやることが多くなってしまった今、本記事の2章でも語られたような「タスクの優先度」に手を加えないことには、解決出来ない問題も多くなったのです。</p>

<p>こうした中ででてきたのが、requestIdleCallbackという機能です。</p>

<p>2章にもでてきた、Chromeのスクロールパフォーマンスを改善した、パフォーマンス周りを専門としているGoogleのエンジニア<a href="http://research.google.com/pubs/RossMcIlroy.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Ross McIlroy</a>ら。彼らが、Microsoftがだした「setImmediateを全ブラウザでちゃんと実装しようぜ！」という案をはねのけて提案したのがこのrequestIdleCallback。</p>

<p>scrollイベントの改善で、彼らはあくまでブラウザ側のタスクの優先度に対して手を加えたわけですが、ここにきてデベロッパーが作ったJSの処理。ユーザーワールドで実行されるものについても、優先度のようなものを与えて、タスクが実行されるタイミングをうまく制御しようという提案をしたのでした。scrollイベントで培ったノウハウを広げようとしたんだろうなぁと、私は推測してます。</p>

<p>requestIdleCallbackはどういうものか？scrollイベントの一件では、緊急度の高いブラウザ内のタスクを、あらゆるタスクよりも優先して速く実行するというものでした。一方でrequestIdleCallbackは、ユーザー側の体験としてパフォーマンスが低いという状況を生み出しがちな、緊急度が低いユーザーワールドのタスクを、あらゆるタスクよりも低く実行するというもの。ブラウザ側だけじゃ限界があるから、デベロッパー側でもなんとかする術というのを提供したといったところです。</p>

<p>その仕組はとてもシンプルで、処理されることを待っているタスクがあれば絶対に実行しない。無ければそのタイミングで実行しようというもの。</p>

<p><img src="/wp-content/uploads/2016/10/20151224013042.jpg" alt="20151224013042" width="640" height="450" class="alignnone size-full wp-image-21540" srcset="/wp-content/uploads/2016/10/20151224013042.jpg 640w, /wp-content/uploads/2016/10/20151224013042-300x211.jpg 300w, /wp-content/uploads/2016/10/20151224013042-207x146.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p>サンプルは以下の通り。</p>

<p></p><pre class="crayon-plain-tag">var hd = requestIdleCallback( =&gt; {
  // タスクキューが空になってから実行されるタスク
},{
  timeout: 10000 // 何msであきらめるか。
});</pre><p></p>

<h1>最後に</h1>

<p>CPUからGPUに処理を移したいというお話から、それでもどうしようもないシングルスレッド問題を、いかにして効率的に運用するのかというお話まで。GPUがデベロッパーを幸せにしたり、不幸にされたからどうにかしようとしたり、という感じで、GPUとブラウザのパフォーマンス問題は切っても切り離せないようですね。</p>

<p>ちなみに、この記事を書いている今、TPACというイベントが開かれ、パフォーマンスに関する議論も行われています。そこでは様々な議論が繰り広げられているのですが「Measuring and improving scroll latency (~30m; rbyers)」というスクロールをもっと良くしようよという話や、「Paint metrics」といったレイアウト処理のさらに先の描画系の発展的な話であったり、「Long Tasks API」みたいな、requestIdleCallbackとか以前にタスクの処理時間長くね？ってところをなんとか変えていこうよという議論もあったりします。</p>

<p>個人的に注目しているのは、以前からデベロッパーの間で薄っすら思われていた、SPAの時にブラウザのナビゲーション計測系のAPIが役に立たないのだけどどうするの？って問題に注目しているところです。SPAと一言でいっても、Ruby on RailsのTurbo Linksのようなものもあり、ブラウザの持つページ遷移機能が活用されないケースがある中で、パフォーマンス計測はどうあるべきなのか。「ナビゲーションの開始」と断定することが困難であり、それゆえに画面の切り替わりにどの程度の時間がかかったのかわからないこの問題を、今後どう扱うのかが議論されるようです。</p>

<p>一通り終わったなぁ、パフォーマンス周りの機能整備、なんて思ったのですが、よくよく考えたら実態にそこまで即した感じでもないんですよね。今後も様子を見ておきたいと思います。それでは！</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Conference 2016 特集]]></series:name>
	</item>
		<item>
		<title>TCP Fast Open – Webを速くするためにGoogleがやっていること Make the Web Faster 4 &#8211;</title>
		<link>/jxck/3529/</link>
		<pubDate>Tue, 10 Dec 2013 01:00:14 +0000</pubDate>
		<dc:creator><![CDATA[Jxck]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">/?p=3529</guid>
		<description><![CDATA[連載： Make the Web Faster (4)HTTPは、その下層にあたるトランスポートレイヤーのプロトコルとして、通常TCPを使用します。 したがって、TCPのレイヤで速度が改善することは、そのままWebの高速...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-faster/" class="series-153" title="Make the Web Faster" data-wpel-link="internal">Make the Web Faster</a> (4)</div><p>HTTPは、その下層にあたるトランスポートレイヤーのプロトコルとして、通常TCPを使用します。
したがって、TCPのレイヤで速度が改善することは、そのままWebの高速化につながる可能性があるといえます。</p>

<p>GoogleはWebを速くするための活動として、TCPのようなプロトコルレイヤの改善にも取り組んでいます。
今回はその中の一つ、TCP Fast Openを取り上げ、解説と動作検証、簡単なベンチマークを行います。
検証環境等は最下部に記載します.</p>

<p><a href="https://developers.google.com/speed/protocols/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Make the Web Faster</a>: <a href="http://tools.ietf.org/html/draft-ietf-tcpm-fastopen" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">TCP Fast Open</a></p>

<!-- more -->

<h2>3 Way Handshake</h2>

<p>TCPは、「正確、確実にデータを届ける」ことを重視した設計になっています。
特に接続確立時には、双方の状態をきちんと確認しながら実施するための <em>3 Way Handshake</em> (以下3WH)という方式を採用しています。</p>

<p>例えば、クライアントがサーバに対してHTTPリクエストを送信したい場合は、以下のような流れになります。</p>

<p><img src="/wp-content/uploads/2013/12/tfo-3wh.png" alt="3 Way Handshake" /></p>

<p>クライアントは、3WHが終わってはじめてHTTPリクエストを送信できるため、HTTPのリクエストを送るまでにはTCPのレイヤで三回の通信が必要になります。
HTTPでは、Keep-AliveなどでTCPコネクションを使いまわすこともできますが、それでも切断と接続の頻度は多いのが現状です。</p>

<p>そこで、3WHの通信を「<a href="https://html5experts.jp/jxck/1415/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">なるべく少なく</a>」することで、接続確立の高速化を図る方法が、今回紹介する <em>TCP Fast Open</em> (以下TFO)です。</p>

<h2>なぜ3WHを使うのか</h2>

<p>わざわざ三回も通信を行う3WHを用いる理由はいくつかありますが、その一つとして、クライアントIPの確認があります。</p>

<p>クライアントSYNが含まれるパケットにはクライアントのIPアドレスが載るため、サーバはそのアドレスにレスポンスを返すのですが、このIPは簡単に偽装することができます。</p>

<p>そこで、HTTPのやりとりに移る前に、クライアントのアドレスに対してサーバからもSYNを送ります。
もしこのとき、アドレスが偽装されたものであった場合、その機器が実在したとしてもサーバからのSYNは無視されるため、HTTPのやりとりに移る前にアドレスが正しいことを確認できるのです。</p>

<h2>TCP Fast Open</h2>

<p>TFOは、簡単に言えばTCPレイヤでCookieを用いることで、すでに接続を確立したことがあるIPアドレスのホストに対しては、3WHを簡略化するという方式です。</p>

<p>Cookieを用いるため、まったく初めて接続する(Cookieを保持していない)ホストに対しては通常の3WHを実行し、その時ホストがCookieを発行します。
二回目以降の接続確立では、クライアントはそのCookieをサーバに送信するという流れになります。</p>

<p>では、通信の詳細を見てみましょう。</p>

<p>次に解説する流れは、TCPコネクションを確立した後にHTTPのGETリクエストを発行し、レスポンスを受け取るところまでの範囲とします。
この時、HTTPのリクエストの受信、レスポンスの送信はサーバの責務ですが、リクエストデータを処理しレスポンスデータを生成するのは、アプリレイヤの責務であるという前提を踏まえて読んでください。</p>

<h3>最初の接続</h3>

<p>この時点ではサーバとクライアントが有効なCookieをお互いに保存していません。</p>

<p><img src="/wp-content/uploads/2013/12/tfo-flow-1.png" alt="TCP Fast Open 1" /></p>

<ol>
<li>クライアントは、SYNに <em>Fast Open Cookie</em> オプションにCookie Requestをつけて送信する。</li>
<li>サーバは、 <em>TFO-Cookie</em> を生成し、それをFast Open CookieオプションにつけたSYN-ACKを送信する。</li>
<li>クライアントは、TFO-Cookieをキャッシュする。</li>
<li>クライアントは、ACKを返し、通常の接続確立を終える。</li>
<li>クライアントは、HTTP GETリクエストを送信する。</li>
<li>サーバは、HTTP GETクエストをアプリレイヤに渡し、アプリが生成したレスポンスデータをレスポンスとして送信する。</li>
</ol>

<p>通常の3WHと違うのは、SYNとSYN-ACKにFast Open Cookieオプションが付く点です。 通信の回数は三回と変わりません。
また、最初のSYNを受け取ったサーバがTFOに対応していない場合、サーバはオプションを無視して通常の3WHが実行(フォールバック)されます。
HTTPの通信は3WHが完全に終わった後になります。</p>

<p>ここでサーバが生成するTFO-Cookieは、クライアントのIPをベースにします。
クライアントはこのTFO-Cookieを、次回以降の接続で仕様するためにキャッシュします。</p>

<h3>次回以降の接続</h3>

<p>サーバとクライアントが有効なCookieをお互いに保持している状態です。</p>

<p><img src="/wp-content/uploads/2013/12/tfo-flow-2.png" alt="TCP Fast Open 2" /></p>

<ol>
<li>クライアントは、SYNパケットにキャッシュしたTFO-CookieとHTTP GETのリクエストデータを含めて送信する。</li>
<li>サーバは、TFO-Cookieを受け取る。この時初回接続で生成した方法と同じようにSYNからTFO-Cookieを生成し、受け取ったTFO-Cookieと比較する。同じであればTFO-Cookieは正しいものであり、同時にクライアントのIPは偽装されていないことがわかる。</li>
<li>TFO-Cookieが正しいことを確認したら、サーバはリクエストデータをアプリケーションレイヤに渡す。クライアントにはSYN-ACKを返すが、もしHTTPレスポンスデータが準備できていればSYN-ACKに載せることも可能。</li>
<li>アプリレイヤがHTTPレスポンスデータを生成し終えたら、サーバはそれをクライアントに送信する。</li>
<li>クライアントは、ACKを送信する。</li>
</ol>

<p>通常の3WHと違うのは、SYNに初回接続でキャッシュしたTFO-CookieとHTTP GETのリクエストデータが付くことです。
サーバはTFO-Cookieを元に、クライアントがIPを偽装していないかを知ることができるので、正しいIPであればその後のクライアントからのACKがくる前にGETのデータをアプリのレイヤに渡してしまいます。
アプリから見れば一回の通信で、リクエストデータを取得したのと同等の状態になります。</p>

<p>また、TFOは3WHの省略と解説されることが多いですが、実際にはサーバは従来どおりSYN-ACKを返し、クライアントも最後のACKをきちんと送ります。
ただし、もしアプリが生成したレスポンスデータがサーバに届いたらSYN-ACKに載せて返すこともできますし、SYN-ACKを先に返しておいて別途送ることもできます。
最後のクライアントACKを待たずにレスポンスを開始できるのが、3WHを短縮するからくりになっているのです。</p>

<p>もし、サーバがTFOに対応していなかったりクライアントのTFO-Cookieが無効と判断された場合は、通常の3WHにフォールバックされ、通常のフローでHTTPのGETが行われます。</p>

<h3>TFO-Cookie</h3>

<p>TFO-CookieはクライアントのIPを保証できなければなりませんが、その生成アルゴリズムは仕様では定義されておらず、実装依存です。
参考までにLinux Kernel 3.11では、以下のようにクライアント/サーバ双方のIPアドレスを暗号化して生成しています。</p>

<p><a href="http://lxr.linux.no/linux+v3.11/net/ipv4/tcp_fastopen.c#L67" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://lxr.linux.no/linux+v3.11/net/ipv4/tcp_fastopen.c#L67</a></p>

<p>IPアドレスを元に生成しているため、クライアントのIPが変わるとCookieが無効になることを意味します。</p>

<h2>注意点</h2>

<h3>Intermedialies(中間サーバ問題)</h3>

<p>こうしたネットワークプロトコルの改善には、必ずIntermedialies(middleboxともいう)と呼ばれる中間サーバが問題になります。
具体的にはプロトコルをいじることで、NATやFWなどが通信を不正と見なして遮断したり、内容を書き換えてしまう問題です。</p>

<p>TFOの場合は、NATでアドレスが書き換わる状況などではCookieが不正とみなされ、TFOが成功しない可能性が考えられます。
しかし、問題があれば通常の3WHへのフォールバックによって、通信を続行することができるよう設計されているため、この問題は最小限に抑えられています。</p>

<p>ただし、リクエストデータを付与したSYNが拒否され、3WH成立後に改めてリクエストを送信する場合は、リクエストデータが二重に送信されるためオーバーヘッドになる可能性があります。</p>

<h2>導入方法</h2>

<p>TFOはクライアントAPIがLinux kernel 3.6に、サーバAPIが3.7にマージされています。
執筆時点ではWindowsおよびMac OSでは使用することができません。</p>

<p>TFOを有効にするには、設定ファイルにフラグを立て、ソケットプログラムにおいて適切なシステムコールを呼ぶ必要があります。</p>

<h3>サーバ</h3>

<p>サーバでは、生成したソケットをバインドした後に、setsocketopt(2)を用いてTCP_FASTOPENオプションを付与する必要があります。
qlenの値は、TFOによって3WHが終了していないソケットのキューサイズです。</p>

<p></p><pre class="crayon-plain-tag">s = socket(AF_INET, SOCK_STREAM, 0);   // ソケットの生成

bind(s, ...);                          // アドレスへのバインド

int qlen = 5;
setsockopt(s, SOL_TCP, TCP_FASTOPEN, &amp;qlen, sizeof(qlen)); // TCP_FASTOPEN オプションの設定

listen(s, ...);                        // ソケットのリッスン</pre><p></p>

<h3>クライアント</h3>

<p>クライアントでは、生成したソケットに対するconnect(2)とsend(2)の代わりに、sendto(2)を使用してデータを送信します。
これは通常UDP通信などで使用されるシステムコールですが、TFOでは3WHが終了していない状態でのデータ送信が必要なため、これを用います。</p>

<p>このsendto(2)は、初回接続時はTFO-Cookie Requestを送信し、既にCookieがある場合はそれを使用してSYNにデータを載せて送信を行います。</p>

<p></p><pre class="crayon-plain-tag">// ソケットに対する connect(2) + write(2) の代わりに sendto(2) を使用
sendto(s, data, data_len, MSG_FASTOPEN,
    (struct sockaddr *) &amp;server_addr, addr_len);

// 以降の送受信は通常どおり read(2)/write(2) を使用</pre><p></p>

<h3>設定</h3>

<p>Linux KernelではTFOの設定ファイルとして  <em>/proc/sys/net/ipv4/tcp_fastopen</em> が用意されています。
このファイルにはビットでクライアント/サーバごとに有効/無効の設定が可能です。
Linux Kernelでは以下の設定値が定義されています。</p>

<p><code>0x0: 無効
0x1: クライアントのみ有効
0x2: サーバのみ有効
0x3: クライアント/サーバともに有効
0x4: CookieがなくてもSYNでデータを送信
0x100: Cookie を検証せずにデータの載ったSYNを受け入れる
0x200: Cookie オプションがなくてもSYNにデータを載せる
0x400/0x800: TCP_FASTOPENオプションを設定してないソケットでもTFOを有効にする。
</code></p>

<h2>実装</h2>

<p>簡単なTFOサーバとクライアントのスクリプトを作成して、パケットの流れを確認してみます。
現時点で言語レベルでTFOをサポートしているものは少ないため *1、Pythonで直接システムコールを呼ぶスクリプトを使用します。</p>

<p><a href="https://gist.github.com/Jxck/7854971" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">python sample code (gist)</a></p>

<p>クライアントは &#8220;hello\n&#8221; を二回送信し、サーバはそれをエコーバックします。
二台のマシン(MacOS)上のVartual Box上のUbuntuで実行します。</p>

<p></p><pre class="crayon-plain-tag"># server
$ sudo python server.py # listen port 80
# client
$ python client.py 192.168.1.10 # server address</pre><p></p>

<p>実行結果をWiresharkで確認します。</p>

<p><img src="/wp-content/uploads/2013/12/tfo-python-1.png" alt="1st Connection" /></p>

<p>最初のClient SYNにFast Open Cookie Requestが付き、SYN ACKでFast Open Cookiが付与されていることがわかります。
データは別のパケットで送られています。</p>

<p><img src="/wp-content/uploads/2013/12/tfo-python-2.png" alt="2nd Connection" /></p>

<p>二回目のClient SYNには、このCookieとデータが一緒に載っています。
しかもサーバはSYN ACKを返した後に、サーバのACKを待たずにデータを返しています。
正常に動いていることがわかりますね。</p>

<h2>ApacheとChrome</h2>

<p>ApacheやNginxなどはまだTFOに対応していませんが、kernel側でリスニングソケットにTFOを強制するオプションがあるので、それを使用して検証します。
また、最新のChromeはTFOに対応しているため(OSもTFO対応が必要) 、これをクライアントとして利用します。</p>

<p>まず、サーバ側でTFO強制の設定をしApacheをインストールします。</p>

<p></p><pre class="crayon-plain-tag">$ echo 0x403 | sudo tee /proc/sys/net/ipv4/tcp_fastopen
$ sudo apt-get install apache2</pre><p></p>

<p>クライアント側は最新のchromeを用意し <a href="chrome://flags" data-wpel-link="internal">chrome://flags</a> で &#8220;TCP Fast Openを有効にする&#8221; を設定します。</p>

<p>この状態でChromeからapacheのデフォルトページに二回アクセスします。
Chromeは、一回目のGETでCookieをリクエストし、二回目のGETでSYNにCookieとリクエストヘッダを載せて投げています。</p>

<p><img src="/wp-content/uploads/2013/12/tfo-apache-chrome.png" alt="Apache-Chrome" /></p>

<p>同様の方法を使えば、設定ファイルを書くだけで既存のサーバをTFOに対応させることができるでしょう。
しかし、このオプションはあくまでもテスト目的に使用するもので、本番運用ではkernel APIレベルで対応したものを使用するべきです。</p>

<h2>ベンチマーク</h2>

<p>TFOはRTTが大きい環境でこそ効果が期待されます。そこでAWSを用いて、Tokyoリージョンをクライアント、N.Virginiaリージョンをサーバとし、ベンチマークをとってみます。使用するAMIは以下です。(インスタンスにはElastic IPをふっています)</p>

<ul>
<li>TOKYO: ubuntu-raring-13.04-amd64-server-20130820(ami-0b8c1f0a)</li>
<li>N.Virginia: ubuntu-raring-12.04-amd64-server-20130820(ami-77fcbc1e)</li>
</ul>

<p>サーバにはApacheを、クライアントはTFOに対応している<a href="http://www.vanheusden.com/httping/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Httping</a>を用いて十回のリクエストを投げる簡単なベンチを行います。</p>

<p></p><pre class="crayon-plain-tag">$ echo 3 | sudo tee /proc/sys/net/ipv4/tcp_fastopen
$ wget http://www.vanheusden.com/httping/httping-2.3.3.tgz
$ tar zxvf httping-2.3.3.tgz
$ cd httping-2.3.3.tgz
$ ./configure --with-tfo # TFO を有効にしてビルド
$ make
$ ./httping -g http://192.0.2.0/ -c 10    # TFO off
$ ./httping -g http://192.0.2.0/ -c 10 -F # TFO on</pre><p></p>

<h3>結果</h3>

<p><code># TFO off
10 connects, 10 ok, 0.00% failed, time 13830ms
round-trip min/avg/max = 344.7/382.6/424.2 ms</p>

<h1>TFO on</h1>

<p>10 connects, 10 ok, 0.00% failed, time 12052ms
round-trip min/avg/max = 161.8/204.9/364.2 ms
</code>
(TFO onのパターンは、最初の一回はCookie Requestです)</p>

<p>この検証では、RTTは平均で46%短くなっている事がわかります。</p>

<h2>まとめ</h2>

<p>TFOは、まだドラフトの段階で実装も限られていますが、仕様が固まればサーバやOSも対応が進むと考えられます。
各言語の標準ソケットモジュールレベルでの対応も少しずつ進んでいるため、今後は普通にネットワークプログラムを書けば自動的にTFO対応されるでしょう。</p>

<p>注意点として、通常の3WHにフォールバックした場合にリクエストデータが二重になる可能性がありますが、
一方で通信を「<a href="https://html5experts.jp/jxck/1415/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">なるべく少なく</a>」することによる効果は非常に大きいため、そことのトレードオフとなるでしょう。</p>

<p>普及にはまだ時間がかかるかもしれませんが、今のうちから自身のもつサービス検証をしてみてはいかがでしょうか。</p>

<h2>検証環境</h2>

<ul>
<li>Ubuntu 13.10</li>
<li>kernel 3.11.0-13-generic</li>
<li>Python 2.7.3</li>
<li>Wireshark 1.10.2</li>
<li>HTTPing 2.3.3</li>
<li>Google Chrome 32(beta)</li>
</ul>

<ol>
<li>いくつかの言語は導入に関する議論やパッチを見つけたので載せておきます。  <a href="https://bugs.ruby-lang.org/issues/8897" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Ruby</a>, <a href="https://codereview.appspot.com/27150044/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Go</a>, <a href="https://groups.google.com/forum/#!topic/python-ideas/HOpnV_tyt0g" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Python</a></li>
</ol>
]]></content:encoded>
		
		<series:name><![CDATA[Make the Web Faster]]></series:name>
	</item>
		<item>
		<title>Google Hosted Library – Webを速くするためにGoogleがやっていること Make the Web Faster 03 &#8211;</title>
		<link>/jxck/3102/</link>
		<pubDate>Tue, 22 Oct 2013 22:00:33 +0000</pubDate>
		<dc:creator><![CDATA[Jxck]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[CDN]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">/?p=3102</guid>
		<description><![CDATA[連載： Make the Web Faster (3)Googleは、よく使われるJavaScriptのライブラリなどをGoogleのインフラを使って配布しています。 これを Google Hosted Library ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-faster/" class="series-153" title="Make the Web Faster" data-wpel-link="internal">Make the Web Faster</a> (3)</div><p>Googleは、よく使われるJavaScriptのライブラリなどをGoogleのインフラを使って配布しています。
これを <a href="https://developers.google.com/speed/libraries/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Google Hosted Library</a> と呼びます。</p>

<p>この、Hosted Libraryの導入を単純に「自分で配布しない分が楽になるだけ」、くらいな感覚で使っている方も多いと思います。しかし、実はこれはみんなが使えば使うほど、得をする仕組みになっていることを見落としてはいないでしょうか？</p>

<p>今回はそんな、Google Hosted Libraryについて、その仕組となるCDNやキャッシュの技術などについて解説します。</p>

<!-- more -->

<h2>よくある Web ページ</h2>

<p>例えば自分が配信するindex.html内でjquery.2.0.3.min.jsとそれに依存したmy-client.jsを使う場合、3つとも自分のサーバから配信するとします。
index.htmlは以下のような感じになるでしょう。</p>

<p></p><pre class="crayon-plain-tag">&lt;html&gt;
  &lt;title&gt;my web&lt;/title&gt;
  &lt;script src="js/jquery-2.0.3.min.js"&gt;&lt;/script&gt;
  &lt;script src="js/my-client.js"&gt;&lt;/script&gt;
  ...
&lt;/html&gt;</pre><p></p>

<p>これで全く問題なく動くはずです。</p>

<h2>キャッシュ</h2>

<p>ところでindex.htmlやmy-client.jsは、自分がアップデートすることで内容が新しくなる可能性がありますね。
しかし、jQueryはどうでしょう？jquery.2.0.3.min.jsの内容は通常一度生成されたら二度と変わりません。もしjQuery自体がアップデートされれば、付与されるバージョン番号が変わるので、バージョン番号を含んだファイルは将来の変更を意識する必要がありません。</p>

<p>将来変更がないのであれば、ブラウザへのキャッシュを検討することができます。
全く内容が同じファイルを何度も配信する必要はなく、一度配信したものをキャッシュさせ、次回以降再利用させれば、無駄なネットワークアクセスを減らすことができるからです。
重複したリクエストが減るのは、「<a href="https://html5experts.jp/jxck_/1415/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">なるべく少なく</a> 」の原則ですね。</p>

<p>キャッシュの設定には、jquery.2.0.3.min.jsのレスポンスにキャッシュをコントロールするヘッダを加えてあげる必要があります。
キャッシュヘッダの設定は実はそれだけで一つの記事になるくらい細かいのですが、今回の目的ではざっくりと以下の設定が考えられます。</p>

<pre><code>::
Cache-Control:public, max-age=2592000
Expires: Sun, 1 Jan 2014 11:11:11 GMT
</code></pre>

<p>Cache-ControlはHTTP/1.1のヘッダで、クライアントにコンテンツをキャッシュさせる時間を指定できます。この例では30日を指定しています。</p>

<p>ExpiresはHTTP/1.0のヘッダで、指定された日時までキャッシュさせる設定です。Cache-Control非対応のクライアントを想定し、両方が現時点から同じ日(例えば30日後)になるように設定することが多いです。</p>

<p>これで、一度取得したファイルを30日はキャッシュし、ファイルの取得が必要なくなります。</p>

<h2>Google Hosted Library</h2>

<p>さて、Google Hosted Libraryは、よく使われるJavaSriptの配信を代わりにやってくれるのですが、使い方は簡単。<a href="https://developers.google.com/speed/libraries/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">一覧ページ</a> から欲しいライブラリとバージョンのリンクをコピーして貼るだけです。</p>

<p>先ほどのjQueryを置き換えると以下のようになります。</p>

<p></p><pre class="crayon-plain-tag">&lt;script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script src="js/my-client.js"&gt;&lt;/script&gt;</pre><p></p>

<p>まず効果として、ファイルはGoogleの強靭なファイルサーバから取得されるため、可用性やパフォーマンスの面で有利ですし、自分のサーバからはその分の負荷がごっそり減ることになります。</p>

<p>そして、キャッシュ用のヘッダもすでに設定されているため、悩む必要がありません。jQueryにはキャッシュに関わる、以下のようなヘッダがついていました。</p>

<pre><code>::
Cache-Control:public, max-age=31536000
Expires:Mon, 08 Sep 2014 00:23:36 GMT
Last-Modified:Tue, 09 Jul 2013 11:31:25 GMT
</code></pre>

<p>これは、ファイルを1年間キャッシュするという設定です。
Last-Modeifiedは、「条件付きGet」という方法で使われるヘッダですが、今回は説明を割愛します。</p>

<p>では、自分で適切にキャッシュの設定ができて負荷も問題なければ、Hosted Libraryを使う必要はないのでしょうか？</p>

<h2>同時接続数</h2>

<p>ブラウザは、ファイルを取得する時にサーバとのTCPの接続を必要とします。
もし1つのTCP接続しかなかったら、同時に1つのファイルしか取得できず、他は待たされます。</p>

<p>これだと、画像やJSなどのファイルが多い場合、全て取得し終わるまでに時間がかかってしまいます。
そこで、ブラウザは種類にもよりますが大体同時に6つのTCP接続をサーバと作ります。つまり6個同時に取得できるので、全部取得するのにかかる時間も減らせます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/10/single-domain.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/10/single-domain.png" alt="単一ドメインの例" width="497" height="114" class="alignnone size-full wp-image-3120" srcset="/wp-content/uploads/2013/10/single-domain.png 497w, /wp-content/uploads/2013/10/single-domain-300x68.png 300w, /wp-content/uploads/2013/10/single-domain-207x47.png 207w" sizes="(max-width: 497px) 100vw, 497px" /></a></p>

<p>しかし、もっとたくさんの接続を作れば、もっと同時にダウンロードできそうですよね。実は6個という数字は、一つのドメインとの間の接続の数です。なので、ドメインが違えばもう6個追加で接続できるのです。</p>

<p>もしあなたのサイトがexampl.e.comというドメインだとしたら、ajax.googleapis.comは別のドメインなので、jQueryは別の6つから取得できることになります。　Hosted Libraryを使うだけで、JSをダウンロードに必要な接続は、自分のサーバの貴重な6接続とは別にできるのです。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/10/multi-domain.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/10/multi-domain.png" alt="複数ドメインの例" width="497" height="214" class="alignnone size-full wp-image-3119" srcset="/wp-content/uploads/2013/10/multi-domain.png 497w, /wp-content/uploads/2013/10/multi-domain-300x129.png 300w, /wp-content/uploads/2013/10/multi-domain-207x89.png 207w" sizes="(max-width: 497px) 100vw, 497px" /></a></p>

<p>ちなみに、同じexample.comでもサブドメインを切ればそれは別ドメインとみなされます。
つまりstatic.example.comというドメインを作って、js, css, pngなどはそこから配信することで、接続数を増やすという策はよく使われます。もちろん、自分で契約したCDNも別のドメインにすることが多いです。</p>

<p>では、ドメインとキャッシュ設定が適切に設計されていれば、Hosted Libraryを使う理由はないでしょうか？</p>

<h2>CDN(Contents Delivery Network)</h2>

<p>ところで、このGoogleのサーバはどこにあるのでしょう？
具体的な場所は公開されていませんが、Google曰く「世界中にある」そうです。</p>

<p>この世界中に散らばったサーバをエッジサーバといいます。
そして、先ほどのURLにアクセスした場合、そのユーザから一番近いエッジサーバからファイルを取得してくれる仕組みになっています。この仕組みは、 CDN(Contents Delivery Network) といいます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/10/CDN.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/10/CDN.png" alt="CDN のイメージ" width="800" height="504" class="alignnone size-full wp-image-3098" /></a></p>

<p>具体的には、サーバの名前解決時にDNSがなるべく近いサーバのIPに解決してくれています。
例えば、日本でapi.googleapis.comを解決すると173.194.72.95になりますが、USのバージニア州(AWS us-east 上)では173.194.76.95になります。</p>

<p>日本から二つのサーバにPINGを打ち、RTT(Round Trip Time)を比較してみましょう。</p>

<pre><code>:bash:
$ ping 173.194.72.95 -c 10 (jp to jp)
rtt avg = 53.441

$ ping ping 173.194.76.95 -c 10 (jp to virginia)
rtt avg = 174.525
</code></pre>

<p>実に3倍近い差が出ていることが分かります。
つまり、世界中からアクセスがくるようなサービスの場合は、Hosted Libraryに変えるだけで、JSが地理的に近いエッジサーバから配信され、RTTを小さくできる可能性があるのです。「<a href="https://html5experts.jp/jxck_/1415/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">なるべく近く</a> 」の原則ですね。</p>

<p>ちなみに、CDNという仕組み自体をサービスとして提供している会社もあります。
有名なのは 「Akamai Technologies」や「Limelight Networks」、あとAWSにも「Cloud Front」というサービスがあり、いずれもお金を払うとエッジサーバを貸りてCDNを構築できます。
ちゃんとやるとそれなりのお値段がする場合が多いですが、Googleはそれをタダで使わせてくれるんですね。</p>

<p>もし自分でCDN環境を持っていれば、index.htmlやmy-client.jsも配信できるので、同じ効果が他のファイルでも得られます。</p>

<p>では、自分でお金をかけてCDNを構築していたら、Hosted Libraryを使う理由はないでしょうか？</p>

<h2>Google Hosted Libraryはみんなが使うほど得をする</h2>

<p>最初にキャッシュの話をしましたが、ブラウザはキャッシュをURLごとに管理しています。
例えば、自分のページにアクセスしたユーザが、 同じURLのJSを別のサイトで取得しキャッシュしていた場合、そのキャッシュを自分のサイトでも利用することができます。</p>

<p>同様に自分のページでキャッシュしたJSも、他のページで再利用できます。同じURLのJSを一度どこかでキャッシュしていれば、キャッシュが切れるまでの間は、同じURL のJSを使っている全てのサイトで、そのキャッシュは使いまわすことができるのです。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/10/Hosted-LIbs.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/10/Hosted-LIbs.png" alt="Hosted Library のイメージ" width="473" height="277" class="alignnone size-full wp-image-3118" srcset="/wp-content/uploads/2013/10/Hosted-LIbs.png 473w, /wp-content/uploads/2013/10/Hosted-LIbs-300x175.png 300w, /wp-content/uploads/2013/10/Hosted-LIbs-207x121.png 207w" sizes="(max-width: 473px) 100vw, 473px" /></a></p>

<p>自前のCDNでは、せいぜい自分の管理するサイト内でしか使いまわせません。
しかし、Hosted Libraryの場合は、みんなが同じURLを共有するため、多くのページがHosted Libraryを使えば使うほど、キャッシュヒットする可能性が高くなり、ダウンロードが必要なのはそのどれか最初にアクセスした1つのページだけで済みます。</p>

<p>本来自分のサイトで発生したはずのリクエストがそもそもなくなったり、自分のサイトで発生したリクエストを他でも活かせるので、非常に大きなメリットとなります。</p>

<h2>他のHosted Library</h2>

<p>例えばjQueryのページを見に行くとjQueryを配信しているCDNが他にもいくつか紹介されています。</p>

<p><a href="http://jquery.com/download/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://jquery.com/download/</a></p>

<p>ここでは、hosted library以外にも、 code.jquery.comという公式のCDNと、Microsoft, CNDJSが紹介されています。細かい違いは、今回解説した知識を踏まえて、同ページか各リンク先を確認して下さい。</p>

<p>どれを選択するかは、サーバ自体の性能やエッジの数・場所などと合わせて、「みんなが使っている」というのもひとつの指標になることは、解説した通りです。</p>

<h2>まとめ</h2>

<p>Hosted Libraryは、ただリンクを張り替えるだけで、無料で導入できるので非常に手軽です。
メリットとして、以下があります。</p>

<ul>
<li>高可用、高性能なファイルサーバが使える</li>
<li>キャッシュの設定がされている</li>
<li>ドメインが分かれる</li>
<li>場所に応じてRTTの小さいエッジが選ばれる</li>
<li>同じURLを使うページ間で、キャッシュが共有できる</li>
</ul>

<p>仕組みを知っているからこそ、あえてそれらを使わず自分でCDNを用意したり、自分のサーバから直接配信するといったことも戦略として比較検討ができます。</p>

<p>今までなんとなく使っていた方は、その意味とメリットを少しでも理解して頂ければ幸いです。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Make the Web Faster]]></series:name>
	</item>
		<item>
		<title>WebP – Webを速くするためにGoogleがやっていること Make the Web Faster 01 &#8211;</title>
		<link>/jxck/2550/</link>
		<pubDate>Wed, 25 Sep 2013 22:00:28 +0000</pubDate>
		<dc:creator><![CDATA[Jxck]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Image]]></category>
		<category><![CDATA[WebP]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">/?p=2550</guid>
		<description><![CDATA[連載： Make the Web Faster (2)画像は、サイズが大きい（大きくなりがちな）コンテンツの一つです。 最近は画像を使わないページはほとんどなく、むしろ使う量はどんどん増えているんじゃないでしょうか。また...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-faster/" class="series-153" title="Make the Web Faster" data-wpel-link="internal">Make the Web Faster</a> (2)</div><p>画像は、サイズが大きい（大きくなりがちな）コンテンツの一つです。
最近は画像を使わないページはほとんどなく、むしろ使う量はどんどん増えているんじゃないでしょうか。また、HiDPI対応などでサイズも増えつつあるでしょう。
<a href="http://blog.chromium.org/2010/09/webp-new-image-format-for-web.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Googleの調査</a>では、現在Web上のトラフィックの65%を画像が占めているそうです。<a href="https://html5experts.jp/jxck_/1415/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Intro</a>で解説したように、パフォーマンスを考えるとファイルサイズは「なるべく小さく」が望ましいため、画像は通常圧縮された形式で使用されます。</p>

<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Webp_logo_Webp.png/320px-Webp_logo_Webp.png" alt="webp logo" class="aligncenter"></p>

<p>WebPは、<a href="http://blog.chromium.org/2013/02/using-webp-to-improve-speed.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Googleが開発した圧縮形式</a>で、従来の形式よりもファイルサイズを小さくすることを目的としています。今回はそんなWebPの概要と使い方、注意点を取り上げます。</p>

<!-- more -->

<h2>画像圧縮とは？</h2>

<p>ここで対象としているのはピクセル形式の画像で、ざっくり言うと「1pxごとにそこが何色なのか」という情報を持つ形式です。
例えば、Windowsのペイントなどで作れるBitmap(.bmp)という形式がなじみ深いでしょうか。</p>

<p>ところが、例えば以下の画像を見て下さい、同じ色が連続している場所があります。
そこで、「このピクセルは赤、このピクセルも赤…」と繰り返す情報を、「ここからここまで赤」と置き換えると、同じ情報を小さく表せるはずです。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/09/lossless.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/09/lossless.png" alt="可逆圧縮のイメージ図" width="701" height="274" class="alignnone size-full wp-image-2614" srcset="/wp-content/uploads/2013/09/lossless.png 640w, /wp-content/uploads/2013/09/lossless-300x117.png 300w, /wp-content/uploads/2013/09/lossless-207x80.png 207w" sizes="(max-width: 701px) 100vw, 701px" /></a></p>

<p>このように、同じ情報を小さく表現する方法を圧縮といいます。これを画像に適用したのが画像圧縮です。
上の図の方法は逆の計算をすれば元の画像が完全に復元できるため、「可逆圧縮（lossless）」といいます。</p>

<p>また、写真などにはものすごく細かい色の変化もあり、なくなっても人間は気づかれない場合が多いので、こうしたデータを捨てることで圧縮率を上げる方法もとられます。代わりに、完全には元に戻せなくなるため、この方法は「非可逆圧縮」と呼ばれます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/09/lossy.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/09/lossy.png" alt="非可逆圧縮のイメージ図" width="701" height="276" class="alignnone size-full wp-image-2615" srcset="/wp-content/uploads/2013/09/lossy.png 640w, /wp-content/uploads/2013/09/lossy-300x118.png 300w, /wp-content/uploads/2013/09/lossy-207x81.png 207w" sizes="(max-width: 701px) 100vw, 701px" /></a></p>

<p>この例は、あくまでもイメージで、実際には同じ情報を小さく表わす方法はいろいろとあり、それにより圧縮形式が異なります。
次によく使われる圧縮形式を見てみましょう。</p>

<h2>圧縮形式</h2>

<p>Webの世界では、現在以下の三つがよく使われています。</p>

<ul>
<li>JPEG: 写真など色数の多いものに有効。非可逆圧縮。</li>
<li>GIF: 色数が少ないアイコンなどに有効、アニメーションが可能。可逆圧縮(&#42;1)。</li>
<li>PNG: アイコンなどに使われ、透過も可能。可逆圧縮。</li>
</ul>

<p>現状はこれらの形式を場合に応じて使い分けているわけですが、Googleは多くの場合にこれらの形式よりも小さく圧縮でき、透過やアニメーションなどの機能もそろった新しい圧縮形式を開発しました。それが、WebPです。</p>

<p>&#42;1: 非可逆も可能です。</p>

<h2>WebP</h2>

<p>読み方は、Weppy＝ウェッピーです。
ファイルの構造としては、同じくGoogleが持つVP8コーデックを用いたWebMという動画フォーマットをベースとしており、WebMの1フレームだけを切り出したものがWebPで、それをRIFFという軽量なコンテナに格納した形式になっています。</p>

<p><a href="https://developers.google.com/speed/webp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://developers.google.com/speed/webp/</a></p>

<p>WebPは以下のような特徴があります。</p>

<ul>
<li>可逆 / 非可逆圧縮が可能</li>
<li>透過 (アルファチャネル) が可能</li>
<li>写真の圧縮にも向いている</li>
<li>アニメーションが可能</li>
<li>カラープロファイル対応</li>
<li>メタデータを持たせることができる</li>
</ul>

<p>画像に求められる基本的な機能をひと通り備えており、一つのフォーマットで幅広い用途で利用できるように作られていることがわかります。
現在Googleのサービスでは、Gmail、Google Drive、Picasa、Play Magazines、Image Search、YouTube、Chrome Web Storeなどがサポートしており、Facebookもサポートを始めました。</p>

<h2>ブラウザ対応</h2>

<p>現在、以下のブラウザがWebPに対応&#42;2しています。</p>

<ul>
<li>Chrome</li>
<li>Opera (12.0~)</li>
<li>Android Browser (4.2~)</li>
<li>Chrome for Android</li>
</ul>

<p>Firefoxでは<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=856375" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">議論中</a>で、IEやSafariは対応していません。
こうしたクライアントを対象とする場合は、後ほど説明するフォールバックが必要になります。</p>

<p>&#42;2: <a href="http://caniuse.com/webp" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://caniuse.com/webp</a></p>

<h2>ツール</h2>

<p>WebPは以下のような公式のライブラリ、オーサリングツールなどで生成することができます。</p>

<ul>
<li><a href="https://developers.google.com/speed/webp/download" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">WebP Library</a></li>
<li><a href="http://www.pixelmator.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Pixelmator</a></li>
<li><a href="http://www.imagemagick.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ImageMagick</a></li>
<li><a href="http://registry.gimp.org/node/25874" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">GIMP</a></li>
<li><a href="http://www.leptonica.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Leptonica</a></li>
<li><a href="http://www.xnconvert.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">XnConvert</a></li>
<li><a href="http://telegraphics.com.au/sw/#webpformat" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Photoshop Plugin</a></li>
<li><a href="http://img2webp.net/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">img2webp.net</a></li>
</ul>

<p>しかし、FacebookがWebPをサポートしたところ、ユーザから「画像をダウンロードしたら、編集ソフトで編集できなかった」というクレームがあったという<a href="http://japan.cnet.com/news/commentary/35031278/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ニュース</a>がありました。</p>

<p>これは、上記のようなメジャーなものを除いて、まだWebPに対応していないオーサリングツールが多くあることを意味しています。
また、OSのデフォルトのプレビューでは見れないため、Webから落とした後のことも考えるのであれば、代替手段として同じ画像のPNGやJPEGをダウンロードする手段を用意することが望ましいでしょう。</p>

<h2>WebP Library</h2>

<p>今回はWebP公式ライブラリに同梱されたCLIツールを用いて、実際に画像をWebPに変換してみます。
公式ライブラリは以下のページで公開されています。</p>

<p><a href="https://developers.google.com/speed/webp/download?hl=ja" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Downloading and Installing WebP</a></p>

<p>ここには以下のツールと、開発用のライブラリが含まれます。</p>

<ul>
<li>cwebp: WebP への変換</li>
<li>dwebp: WebP からの変換</li>
<li>vwebp: WebP の表示</li>
<li>webpmux: アニメーションの作成</li>
<li>gif2webp: GIF から WebP への変換</li>
</ul>

<p>これらのツールはかなりたくさんのオプションがあります。詳細はドキュメントを参照ください。</p>

<p>ここでは、使い方の解説を兼ねてPNG、JPEG、GIFとの簡単な比較をしてみます。(ライセンス情報は末尾に記載)</p>

<p>あくまで簡単な実験です、より厳密かつ詳細な比較結果は、<a href="https://developers.google.com/speed/webp/gallery?hl=ja" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">こちら</a>を参照ください。</p>

<h2>可逆圧縮</h2>

<p>可逆圧縮を、PNGファイルと比べてみます。
対象はPNGがよく使われるWebのUIアイコンとして、下記のPNGをもとにWebPに変換したものを比較します。</p>

<pre><code>::
$ cwebp uikit.lossless.png -o uikit.lossless.webp -lossless
</code></pre>

<table>
<thead>
<tr>
  <th align="center">PNG</th>
  <th align="center">WebP</th>
</tr>
</thead>
<tbody>
<tr>
  <td align="center"><img src="/wp-content/uploads/2013/09/uikit.lossless.png" alt="loss less png" width="300"></td>
  <td align="center"><img src="/wp-content/uploads/2013/09/uikit.lossless.webp" alt="" width="300"></td>
</tr>
<tr>
  <td align="center">74 KB</td>
  <td align="center">62 KB</td>
</tr>
</tbody>
</table>

<h2>非可逆圧縮</h2>

<p>非可逆圧縮をJEPGファイルと比べてみます。
対象はJPEGがよく使われる写真として、おなじみlennaさんのPNGをもとに、ImageMagickでJPEGに変換したものとWebPに変換したものを比較します。</p>

<pre><code>::
$ cwebp lenna.lossless.png -o lenna.lossy.webp
$ convert lenna.lossless.png lenna.lossy.jpeg
</code></pre>

<table>
<thead>
<tr>
  <th align="center">JPEG</th>
  <th align="center">WebP</th>
</tr>
</thead>
<tbody>
<tr>
  <td align="center"><img src="/wp-content/uploads/2013/09/lenna.lossy_.jpeg" alt=""  width="300"></td>
  <td align="center"><img src="/wp-content/uploads/2013/09/lenna.lossy_.webp" alt=""  width="300"></td>
</tr>
<tr>
  <td align="center">74 KB</td>
  <td align="center">20 KB</td>
</tr>
</tbody>
</table>

<h2>アニメーション</h2>

<p>5つのJPEG画像をもとに、500msごとに切り替えるアニメーションをGIFとWebPで作って比較します。</p>

<pre><code>::
$ webpmux -frame 1.webp +500+0+0+0 -frame 2.webp +500+0+0+0 -frame 3.webp +500+0+0+0 -frame 4.webp +500+0+0+0 -frame 5.webp +500+0+0+0 -o animation.webp
$ convert -delay 50 -loop 0 *.jpg animation.gif
</code></pre>

<table>
<thead>
<tr>
  <th align="center">GIF</th>
  <th align="center">WebP</th>
</tr>
</thead>
<tbody>
<tr>
  <td align="center"><img src="/wp-content/uploads/2013/09/animation.gif" alt="" width="240" height="240" class="alignleft size-full wp-image-18570" /></td>
  <td align="center"><a href="https://html5experts.jp/wp-content/uploads/2013/09/animation.webp" data-wpel-link="internal"><img src="/wp-content/uploads/2013/09/animation.webp" alt="" class="alignleft size-full wp-image-18571" /></a></td>
</tr>
<tr>
  <td align="center">262 KB</td>
  <td align="center">55 KB</td>
</tr>
</tbody>
</table>

<p>残念ながら執筆時点では、WebPアニメーションを表示できるブラウザはないため、上記は表示されてないかもしれません。その場合はvwebpコマンドで表示できます。</p>

<pre><code>::
$ vwebp animation.webp
</code></pre>

<p>GIFは色数が少ないため、写真を元にするとざらついた画質になりますが、WebPは比較して綺麗なアニメになっていることが分かると思います。</p>

<h2>圧縮解凍の速度</h2>

<p>WebPは圧縮率を上げるために、以下の追加コストがかかります。&#42;4</p>

<ul>
<li>圧縮: JPEG より 5~10 倍程度のコスト</li>
<li>解凍: JPEG より 1.3 倍程度のコスト</li>
</ul>

<p>特に圧縮は大きな差に感じます。
しかし、画像は一般的に一度作られたら更新されることが少ないリソースであり、圧縮が必要なのは一回ですが、参照される機会が多いのが特徴です。
WebPは多少時間をかけて、じっくりと小さく圧縮することを選択しています。</p>

<p>CPU資源は、サーバ側はサービスの規模に応じて投資してコントロールできますし、クライアント側は最近はモバイル端末ですらそれなりの処理性能を持っています。
ネットワーク資源は、サーバとクライアント間で状況により変わり、サービス側の投資だけではコントロールしきれないという特徴があります。
したがって、圧縮/解凍にかかる時間よりも、ファイルを小さくすることを選択するほうが、現在のWebを取り巻く環境を考えると妥当な場合が多いと考えられます。</p>

<p>しかし、動的に画像を生成するようなサービスでは、従来のフォーマットと比べるなどの検証が必須になるでしょう。</p>

<p>&#42;4 <a href="http://www.igvita.com/slides/2013/io-webp.pdf" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://www.igvita.com/slides/2013/io-webp.pdf (P.13)</a></p>

<h2>フォールバック</h2>

<p>執筆時点では対応するブラウザは限られています。従ってWebP非対応のブラウザのためにはPNGなどへのフォールバックを検討する必要があります。
対応方法は主に以下があります。</p>

<ul>
<li>サーバ側で対応

<ul>
<li>Accept ヘッダでの判別</li>
<li>User-Agent ヘッダでの判別</li>
</ul></li>
<li>クライアント側対応

<ul>
<li>JavaScript でのフォールバック</li>
</ul></li>
</ul>

<h3>Accept での判別</h3>

<p>クライアント・サーバ間での対応フォーマットの確認は、通常HTTP1.1のコンテントネゴシエーションという機能を用いて行います。
具体的には、WebPに対応したブラウザは、画像のリクエストのAcceptヘッダにimage/webpを付与することが求められており、サーバはこの値をもとにクライアントの対応を知ることができます。</p>

<p>手元のChrome29では、HTML中のimgタグのリクエストに以下のヘッダが確認できました。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2013/09/accept-header.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/09/accept-header.png" alt="Chrome の Accept Header" width="1020" height="746" class="alignnone size-full wp-image-2624" srcset="/wp-content/uploads/2013/09/accept-header.png 640w, /wp-content/uploads/2013/09/accept-header-300x219.png 300w, /wp-content/uploads/2013/09/accept-header-207x151.png 207w" sizes="(max-width: 1020px) 100vw, 1020px" /></a></p>

<p>この方法は、クライアントとサーバの間にキャッシュサーバが入る場合に注意が必要です。
同じURLから取得できるコンテンツがクライアントによって異なるので、キャッシュが共有されることで問題が起こる可能性があるためです。
これを防ぐためには、キャッシュに「Acceptヘッダによって、配信するソースが違う」ということを教えるためにVaryヘッダを付与します。
(この情報はGoogleのBotなどがコンテンツ内容を把握する上でも重要です。)</p>

<pre><code>::
Vary: Accept
</code></pre>

<p>コンテントネゴシエーションをサーバに設定する例は、<a href="https://github.com/igrigorik/webp-detect/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">webp-detect</a>が参考になります。</p>

<h3>User-Agentでの判別</h3>

<p>Chrome29は先のように、imgタグに対してimage/webpを送っていましたが、直接画像のURLにアクセスした場合は送っていません。（Canaryでは全ての画像のリクエストに送ります）
またWebPに対応していなくても、全てを許容する意味の &#42;/&#42; を送信するブラウザもあり、Acceptヘッダだけで判別するのは難しい場合があります。</p>

<p>そして、せっかく画像サイズを減らしているのに、Acceptヘッダに新しい情報を追加してしまっては、クライアントからサーバへ送信する情報を増やします。その理由から全てのブラウザが、今後Acceptヘッダを対応をするかどうかはまだ分かりません。 &#42;3</p>

<p>こうしたブラウザ場合は、対応をUser-Agentから判断することもできます。
対応するブラウザは、<a href="http://caniuse.com/webp" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://caniuse.com/webp</a> から確認できますが、より細かくバージョンを指定したい場合は、 <a href="https://code.google.com/p/modpagespeed/source/browse/trunk/src/pagespeed/kernel/http/user_agent_matcher.cc#112" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Google Page Speed のソース</a>が参考になります。</p>

<p>&#42;3 HTTP/2.0では、HPACKというヘッダの送受信を効率化する方式が採用される見通しであり、ヘッダへの情報追加によるオーバーヘッドは、HTTP/1.1に比べて減らせる可能性があります。</p>

<h2>Nginx のサンプル</h2>

<p>以下は、ここまでの判別方法を元に、Nginxでブラウザの対応に応じて切り替える例です。
対応している場合はlogo.webpを、非対応の場合はlogo.pngをレスポンスしています。</p>

<p></p><pre class="crayon-plain-tag">location = /logo {
    if ($http_accept ~* "webp") {
        add_header Vary Accept;
        rewrite (.*) $1.webp last;
    }
    if ($http_user_agent ~* "(Chrome|Opera|Android|Android.*Chrome)") {
        add_header Vary User-Agent;
        rewrite (.*) $1.webp last;
    }
    rewrite (.*) $1.png last;
}</pre><p></p>

<p>実際に以下のリンクで動作を確認できます。（対応ブラウザはWebP、非対応はPNG画像が返ってきます）</p>

<p><a href="https://jxck.io/labs/webp/logo" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://jxck.io/labs/webp/logo</a></p>

<h2>HTMLごと切り替える</h2>

<p>logo.webpとlogo.pngのURLを明示的に分けたい場合は、それらを含むHTMLをまるごと切り替える方が良い場合もあります。</p>

<p></p><pre class="crayon-plain-tag">// 対応ブラウザ用
&lt;html&gt;
  &lt;img src="/logo.webp"&gt;
&lt;/html&gt;

// 非対応ブラウザ用
&lt;html&gt;
  &lt;img src="/logo.png"&gt;
&lt;/html&gt;</pre><p></p>

<p>この場合も、User-Agentによって切り替え、Varyヘッダを付与するとよいでしょう。
もしくは、以下のヘッダを付与することでキャッシュの共有を限定してしまう方法もあります。</p>

<pre><code>::
Cache-Control: private
</code></pre>

<p>ただしこの方法では、例えばWebPに対応したクライアントで取得したlogo.webpのURLをtwitterなどで共有した場合、 WebPに対応しないクライアントでそれを開くと中身を見ることはできません。こうした状況を想定するならUser-Agentも併用する必要があるでしょう。</p>

<h3>JavaScriptでフォールバックする方法</h3>

<p>まず、<a href="http://modernizr.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Modernizr.js</a>には、ブラウザのWebPサポートを調べる機能があります。
これを用いて、読み込む画像をJavaScriptで動的に切り替えることができます。</p>

<p></p><pre class="crayon-plain-tag">if (Modernizr.webp) {
  // WebP を読み込む
} else {
  // PNG を読み込む
}</pre><p></p>

<p>また、WebPがWebMの1フレームに相当することを利用し、
videoタグでWebPを表示可能にする <a href="http://antimatter15.github.io/weppy/demo.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">weppy.js</a> というライブラリもあります。</p>

<p>これを用いると、WebMに対応したFireFoxでもWebPが表示できます。</p>

<p></p><pre class="crayon-plain-tag">&lt;script src="weppy.js"&gt;&lt;/script&gt;
&lt;img src="mandelbrot.webp" width="500"&gt;</pre><p></p>

<p>より強力なライブラリとして、WebPのデコードをJSでやってしまう<a href="http://webpjs.appspot.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">webp.js</a>というライブラリもあります。
こちらは、なんとIE6以降でほぼ全てのブラウザに対応しています。</p>

<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="js/webpjs-0.0.2.min.js"&gt;&lt;/script&gt;</pre><p></p>

<h3>まとめ</h3>

<p>画像を効率よく圧縮できれば帯域を節約でき、特にモバイル対応の場合は全体のパフォーマンスに大きく影響が出ます。
WebPはこの点を解消するために生まれ、圧縮率等に関しては一定の成果を出していると言えるでしょう。</p>

<p>しかし、まだ普及しきっていないため、フォールバックなど考慮すべき点もあります。特に、フォールバックのために施した対策のために、WebPで得られた以上のオーバーヘッドが生じては、パフォーマンスの観点からは台無しです。（全てWebP対応を考えた上での暫定策であれば別ですが）</p>

<p>また、圧縮効果が高いかどうか、不可逆でも画質を維持できるかどうかは、全てどういう画像をどういう用途で配布するかにかかります。パフォーマンスの向上も、今回解説したことを踏まえて、「推測するな測定せよ」を忘れずに実施してください。</p>

<h3>Version</h3>

<ul>
<li>libwebp 0.3.1</li>
<li>ImageMagick 6.8.6-3</li>
<li>Mac OSX 10.7.5</li>
</ul>

<h3>Photo License</h3>

<ul>
<li>Lenna: <a href="http://www.cs.cmu.edu/~chuck/lennapg/lena_std.tif" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://www.cs.cmu.edu/~chuck/lennapg/lena_std.tif</a></li>
<li>Smooth UI Kit: <a href="http://www.icondeposit.com/design:52" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Creative Commons Attribution 3.0</a></li>
<li>Photo Credit: <a href="http://www.flickr.com/photos/11599314@N00/590975150/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Luz Adriana Villa A.</a> via <a href="http://compfight.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Compfight</a> <a href="http://creativecommons.org/licenses/by/2.0/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cc</a></li>
<li>Photo Credit: <a href="http://www.flickr.com/photos/46944516@N00/8284187848/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">pedrosimoes7</a> via <a href="http://compfight.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Compfight</a> <a href="http://creativecommons.org/licenses/by/2.0/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cc</a></li>
<li>Photo Credit: <a href="http://www.flickr.com/photos/12836528@N00/3589122012/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">kevin dooley</a> via <a href="http://compfight.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Compfight</a> <a href="http://creativecommons.org/licenses/by/2.0/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cc</a></li>
<li>Photo Credit: <a href="http://www.flickr.com/photos/12836528@N00/4091928427/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">kevin dooley</a> via <a href="http://compfight.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Compfight</a> <a href="http://creativecommons.org/licenses/by/2.0/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cc</a></li>
<li>Photo Credit: <a href="http://www.flickr.com/photos/44345361@N06/6464688535/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">VinothChandar</a> via <a href="http://compfight.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Compfight</a> <a href="http://creativecommons.org/licenses/by/2.0/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cc</a></li>
<li>Photo Credit: <a href="http://www.flickr.com/photos/48973657@N00/2599237728/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">See-ming Lee 李思明 SML</a> via <a href="http://compfight.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Compfight</a> <a href="http://creativecommons.org/licenses/by-sa/2.0/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cc</a></li>
</ul>
]]></content:encoded>
		
		<series:name><![CDATA[Make the Web Faster]]></series:name>
	</item>
		<item>
		<title>Intro – Webを速くするためにGoogleがやっていること Make the Web Faster 00 &#8211;</title>
		<link>/jxck/1415/</link>
		<pubDate>Thu, 22 Aug 2013 23:20:07 +0000</pubDate>
		<dc:creator><![CDATA[Jxck]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">/?p=1415</guid>
		<description><![CDATA[連載： Make the Web Faster (1)今回から数回にわたって、Googleが進める&#8221;Make the Web Faster&#8221; というプロジェクト(以下、プロジェクト)について、プロ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-faster/" class="series-153" title="Make the Web Faster" data-wpel-link="internal">Make the Web Faster</a> (1)</div><p>今回から数回にわたって、Googleが進める&#8221;Make the Web Faster&#8221; というプロジェクト(以下、プロジェクト)について、プロジェクトにリストされたGoogleのプロダクトや仕様提案、ベストプラクティスなどを連載形式で紹介していきます。</p>

<!-- more -->

<h2>Make the Web Faster</h2>

<p><a href="https://developers.google.com/speed/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">&#8220;Make the Web Faster&#8221;</a> のページには、文字通り Google が 「Webを速くするため」に開発したプロダクトや、新しい仕様の提案、ベストプラクティスなどがリストされています。</p>

<p>例えば以下のようなものがあります。</p>

<ul>
<li>WebP</li>
<li>TCP Fast Open</li>
<li>Google DNS</li>
<li>Google Hosted Libraries</li>
<li>Page Speed</li>
<li>SPDY</li>
<li>etc.</li>
</ul>

<p><a href="https://developers.google.com/speed/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/08/shoto1.jpg" alt="shoto1" width="640" height="425" class="aligncenter size-full wp-image-1579" srcset="/wp-content/uploads/2013/08/shoto1.jpg 640w, /wp-content/uploads/2013/08/shoto1-300x199.jpg 300w, /wp-content/uploads/2013/08/shoto1-207x137.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>この連載では、そこから特に重要なものを、筆者の気の向いた順に紹介していきます。</p>

<p>そして、連載初回の今日は、これら &#8220;Make the Web Faster&#8221; を紹介するにあたり、共通して押さえておくべき基本知識について紹介します。</p>

<h2>Web というターゲット</h2>

<p>プロジェクトには様々な手法がリストされていますが、全てに共通するのは「Webの高速化」を目的としている点です。対象がWebであるために、共通するチューニングの観点としては大きく「ネットワーク」と「アプリケーション」の2つが考えられます。</p>

<h2>ネットワークのチューニング</h2>

<p>Web はネットワークへのアクセスを伴います。ネットワークを効率よく使うことは、パフォーマンスの改善を試みる上で非常に重要です。</p>

<p>まずは、一番簡単な原則としてこれだけは覚えておいてください。</p>

<h3>なるべく小さく</h3>

<p>Webは、HTML,CSS,JS,画像,動画などのデータをネットワーク経由でクライアントに届けています。このデータが小さければ小さいほど、速く届けることができます。特に画像や動画はサイズが大きくなりがちです。送る上でなるべく小さくするにはどうするか、ここで圧縮などの技術が有効になります。</p>

<h3>なるべく少なく</h3>

<p>ネットワークアクセスの回数が増えるほどオーバーヘッドが大きくなるため、極力少ない方が望ましいです。アクセス回数を減らす工夫や、プロトコル仕様レベルの改善などがあります。</p>

<h3>なるべく近く</h3>

<p>ネットは世界の裏側でも簡単にデータを届けることができますが、遠ければそれだけ遅くなってしまいます。しかし、コンテンツの種類によっては、ユーザに近いところにそれを配置するなど、工夫できるところがあります。</p>

<p>他にも HTTP と TCP についての基本的な知識が必要な回もあります。そうした場合は、<a href="http://www5e.biglobe.ne.jp/%257eaji/3min/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">3 Minutes Networking</a> や、現在執筆が進んでいる <a href="http://chimera.labs.oreilly.com/books/1230000000545" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">High Performance Browser Networking</a> などが参考になるでしょう。(この本はすでにHTTP2.0など最新のトピックも扱っています。)</p>

<h2>アプリケーションのチューニング</h2>

<p>WebでAPIを用意して、リクエストに対するJSONを返すだけのサービスなら、純粋にレスポンスにかかる時間(いかに早くJSONを返すか)に集中してチューニングすれば良いかもしれません。</p>

<p>しかし、 多くの場合Webはクライアントとして「ブラウザ」が前提になります。また、ブラウザは基本的に人間が使うものです。従って、以下のような観点もチューニングには必要になってきます。</p>

<h3>ブラウザの挙動</h3>

<p>ブラウザがどのようにリクエスト/レスポンスを処理するかといった挙動を理解することは重要です。そこを理解しないと、効率よくブラウザにコンテンツを届けられず、思ったような速度が得られない場合があります。</p>

<h3>人間への視覚フィードバック</h3>

<p>ブラウザを使って人間が操作することを想定しているならば、視覚的なフィードバックを調整することで「速いと感じる」という観点からチューニングするアプローチもあります。実際、純粋なレスポンスタイムの短縮が限界にきたら、こうした観点のチューニングは避けては通れないでしょう。</p>

<p>こうしたベストプラクティスについては、<a href="http://www.amazon.co.jp/dp/487311361X" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ハイパフォーマンスWebサイト</a> で「14のルール」としても紹介され、 <a href="http://www.amazon.co.jp/dp/4873114462" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">続・ハイパフォーマンスWebサイト</a> では、そこにモダンな技術も追加されています。両方を手元に置いておくことをお勧めします。</p>

<h2>「推測するな、測定せよ」</h2>

<p>「推測するな、測定せよ」という言葉があります。全てのチューニングは、ボトルネックの把握が必要です。やみくもにチューニングすればいいというものではありません。場合によっては遅くなるケースも考えられます。</p>

<p>この連載では、テーマごとに「なぜそれらが作られたのか」を重視して解説します。そこから学べるものが多いからです。しかし、筆者は連載を通して、「入れると速くなるから、今すぐ入れましょう！」などというつもりは一切ありません。</p>

<p>もし、紹介したものから何かを導入するのであれば必ず測定をし、効果と対応クライアントなどをきちんと確認した上で、自己責任で進めて下さい。
また導入した場合は、ノウハウや効果をBlogなどで是非公開してください。それは貴重な情報であり、 &#8220;Make the Web Faster&#8221; にとって大きな貢献になります。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Make the Web Faster]]></series:name>
	</item>
	</channel>
</rss>
