プロトコルを理解して最適なコーディングしよう

[前回](https://qiita.com/mikimhk/items/7cfbd6c94d0f3d7aa51f)レンダリングについて学んだことをまとめましたが、
今回はプロトコル(HTTP)について学んだことを超簡単にまとめてから
プロトコルに関連するパフォーマンス改善法を紹介しようと思います。

## ネットワークプロトコルについて
### **プロトコル**
コンピューター同士が通信をする際の手順や規約などの約束事...要は会話のための言語。
**双方が理解できる同じプロトコル(言語)**を使わないと通信(会話)は成立しないです。
バイリンガルでない限り日本語も同じじゃないと理解出来なくて伝わらないですよね。

プロトコルには沢山種類があって、物理的な部分からアプリケーション的な部分まで、物理層・インターネット層・トランスポート層・アプリケーション層と大きく分けて4段階あり...
みたいな説明が長々と続くわけですが、今回は要らないので省略。

### **HTTP**
ブラウザと Webサーバの間で HTML などの Webページのコンテンツを送受信するためのプロトコル。(アプリケーション層)

そういえばたまに「HTTPプロトコル」なんて聞きますけど
**HyperText Transfer Protocol**の略なんで "プロトコル" 要らないです笑

### 【通信】
HTTPの通信は非常にシンプル!!
`クライアント(ユーザ側)はサーバに対してHTTPリクエストを送信`
 <font color="DeepPink">↓　↑　この間には **TCPコネクション**という **道** みたいなものが出来ている</font>
`サーバはクライアントに対してHTTPレスポンスを返す`

#### 【バージョン】
HTTP にはバージョンが幾つかあり、現在支配的に利用されているのが <font color="DarkOrange">HTTP/1.1</font> になります。
ですが最近は2015年に Google が SPDY のサポートを終了し、 <font color="DarkOrange">HTTP/2</font> のサポートを開始すると発表してから、webパフォーマンスが向上しやすい HTTP/2 を取り入れるサイトが増えてきました。
参考：[Google、「SPDY」終了と「HTTP/2」サポートを発表 - ITmedia NEWS](http://www.itmedia.co.jp/news/articles/1502/10/news060.html)

ということで今回は一番利用率の高い HTTP/1.1 と最新の HTTP/2 のパフォーマンスについて説明していきます。


## HTTP/1.1とHTTP/2の違い
こちらも簡単に必要な部分しか書きませんので、詳細が気になる方は調べてみてください。
### **HTTP/1.1**
- 1つのTCPコネクション内に1対のリクエストとレスポンスしか処理できない
- 同時に複数のリクエストを送ることは可能だが、その場合必ずリクエストされた順にレスポンスが返る
- しかも殆どのモダンブラウザで TCPコネクションを同時に接続出来る数は <font color="DarkOrange">**６つ**</font>
- なので画像が100枚あったとしても一度に6枚分のリクエストしか送れない
    - 1枚分のレスポンスの受信が終わったら随時次のリクエストを送っていくため、常に6つ接続されていく

<img width="551" alt=" 2017-10-11 18.40.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/42808/456d6c1f-7810-7fe3-aa66-c84ba56e2fef.png">


### **HTTP/2**
- 1つのTCPコネクション接続上に**ストリーム**と呼ばれる仮想的な通信路を作ることによって、複数のリクエスト/レスポンスを<font color="DarkOrange">**同時並行**</font>に処理できて、レスポンスを返すための処理に時間がかかるようなケースでも、その間に別のリクエスト/レスポンスを処理することが可能
- なので画像が100枚あったとしたら一度に100枚分のリクエストが送れて、レスポンスも他の処理を待たずに返ってくる

<img width="550" alt=" 2017-10-11 17.01.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/42808/a989b47b-f964-646b-5343-463577e02017.png">
#### 【HTTP/2 を利用する場合の留意点】
現状 TLSプロトコルレイヤーなしでの HTTP/2 の利用を許可しているブラウザはない為、事実上TLSを利用する必要があります。
**TLS（Transport Layer Security）プロトコル**とは、一般的にSSL（Secure Sockets Layer）と呼ばれていて、

- クライアントとサーバの認証機能
- 通信データの暗号化
- 通信データの改ざん検出

などの機能を提供し、セキュアな通信を可能にします。
URL のプロトコル部分が `https://` だった場合、TLSが利用されています。


### **今見ているサイトはどのバージョン??**
WEBサイトがHTTP/2に対応しているかどうかは、ブラウザの以下のプラグインを利用すると簡単に確認出来ます。

Chrome　[HTTP/2 and SPDY indicator - Chrome ウェブストア](https://chrome.google.com/webstore/detail/spdy-indicator/mpbpobfflnpcgagjijhmgnchggcjblin)
Firefox　[HTTP/2 Indicator 3.0](https://addons.mozilla.org/ja/firefox/addon/http2-indicator/)

プラグインを導入しサイトにアクセスするとアドレスバーの右側に稲妻マークが表示され色でバージョンが見分けられます。

| 色 | バージョン |
|---|---|
| 青 | HTTP/2 |
| 緑 | SPDY |
| 赤 | QUIC |


### **体感しよう**
[HTTP vs HTTPS Test](http://www.httpvshttps.com/)
このサイトでは、360個の画像ファイルを TSLなしの HTTP/1.1で読み込んだときと、
HTTP/2 で読み込んだ時のパフォーマンスの違いを試すことが出来ます。

HTTP/1.1 では読み込みが同時接続の制限によってブロックされ、全ての画像ファイルを読み込むのに時間がかかっているのが分かります。
一方、HTTP/2 では同時接続の制限がないため、多数の画像ファイルを高速で読み込むことが出来ます。

## 何でもかんでも変えればいいって話じゃない
HTTP/2 は HTTP/1.1 に比べ利点が多く見えるので
「全部 HTTP/2 化しちゃえばいいじゃん！！」ヽ(｀▽´)/
と思われるかもしれません。
ですが、全てのサイトで**ただ導入すればサイトスピードが上がるのかと言われるとそうではない**です。
効力が期待できないサイトというのもあります。
例えば

- 既に HTTP/1.1 に適した処理を施しているサイト
    - HTTP/2 では無意味なテクニックを使っている場合、そのままのコードでは変化を感じられない
- リクエスト数やリソースが元々少ないサイト
- パケットロスが多いサイト
    - 多重化によって同時リクエストが可能となったが、TCPレベルでのブロッキングは解消されたわけではないので、パケットロスが多い環境では1本にした TCPコネクションが逆に影響されてしまう

などです。
これらのことから、**HTTPS で多くのコンテンツを配信する ECサイトや同時アクセスが集中するサイト**などは特に HTTP/2の恩恵を受けることが出来ます。

## HTTP/1.1 に合ったパフォーマンス改善法
HTTP/1.1では、<font color="DarkOrange">**リクエストできる数を増やす**</font>または<font color="DarkOrange">**リクエストする数を減らす**</font>事が高速化に繋がるテクニックになります。
### **リクエストを減らす方法**

- <font color="DeepPink">CSSスプライト</font>
    - サイト内で使用するたくさんの画像（パーツ）をなるべく一枚画像にまとめて、サーバへのリクエスト回数を少なくする方法
    - CSS で調整する
     - img要素ではなく、背景画像として配置して幅を指定し、ボタンがひとつずつ表示されるように `background-position` でズラして調整する。
    - 更新が面倒（サイズが変わった時とか増えた時とか）
    - やりすぎると CSSが `background-position` で溢れ返って見づらくなる...??
- <font color="DeepPink">画像のインライン化</font>
    - 画像などのバイナリファイルを**Base64**というテキストデータに変換してデータを HTMLの imgタグなどに埋め込む方法<br>
      こんな感じになる→ `<img src="data:image/png;base64,HFIKcsVBORwiHFIKcsVBORw">`
    - データが数MB だと srcが途轍もなく長くなるため、htmlファイル自体のダウンロードに時間が掛かり不利になってしまう可能性がある
    - IE9以下はごめんなさい

### **リクエストできる数を増やす方法**
- <font color="DeepPink">ドメインシャーディング</font>
    - 複数のドメインに分散させることによってドメイン数×6リクエスト分同時接続数を増やすことができる
    - ドメイン数が増えれば増えるほど、それぞれのドメインに対して名前解決しなければならないので、その時間が掛かりすぎると逆効果
    - もちろんコストと手間がかかる

どれも効果が出やすい技術ですが、やりすぎると逆効果になるので**ご利用は計画的に**
他にもリクエスト関連で出来ることを見つけたら随時更新しようと思います。

## 最後に
**HTTP/2** では上記の技術は必要なくなります。
物によっては逆に遅くもなります。(ドメインシャーディングとか)
今回プロトコルを知って、何故効果がないのかがわかりました。

こういった技術は石ころのようにたくさんネットで公開されてますが、**今動かしているサイトにこの技術は合っているのか**を見分けて効果的で最適なコーディングをすることによって、パフォーマンス改善を目指していきたいなと思っています。