こんにちは、金杉です。
HTTP/2やH2Oをご存知の方は多くいらっしゃるかと思います。今回のブログでは、IDCFクラウド上でH2OのWebサーバーを構築して、Google Chromeデベロッパーツールとh2loadを使ってHTTP/2のレスポンスを測ってみようと思います。使う証明書は無料のLet’s Encryptです。先に結論を申し上げますと、H2OのWebサーバーは思った以上に簡単に立てることができ、予想通りHTTP/1.1より早かったです!
HTTP/2とは?
HTTP/2は、Webプロトコルの一種で、従来のHTTPの上位版もしくはバージョン2として認識されています。2015年2月17日に正式に仕様が公開され、IETF HTTP Working Groupによって管理されています。
HTTP/2という規格が誕生した経緯はWeb世界の急速な発展にあります。昔のWebサイトはレイアウトが単純で、コンテンツもほぼ静的で数も少なかったです。しかし、今はページに1回アクセスするにあたり、リクエストが数十、数百と発生するのが一般的です。例えばIDCフロンティアのコーポレートサイトも1ページに100以上の項目があります。リッチコンテンツが増えれば表示までの待ち時間が増えるのが当然ですが、ユーザーは待ってくれません。なので、Webの高速化は前から認識されていた課題でした。
高速化に向けて、今までサーバーサイド、クライアントサイドでもたくさんの人が頑張ってきましたが、そもそもプロトコルレベルから見直さないか?という思いから、SPDYやHTTP/2が誕生しました。SPDY(スピーディ)は、HTTP/2の前身とも言われており、2009年にGoogle社によって開発されました。SPDY/1、SPDY/2、SPDY/3と数回アップデートされ、それを基にHTTP/2は設計されています。
HTTP/2のすごいところ
HTTP/2が従来のHTTP/1.1と比べて高速な理由はたくさんあります。HPACKを使ったヘッダー圧縮や、バイナリ化、そしてサーバープッシュ通信機能が実装されています。これら以外に一番大きく変わった点は、ストリームの多重化です。HTTP/1.1では、1つのTCPコネクションにおいて、リクエスト〜レスポンスのセットを同時に1つしか送受信できませんでした。なので重たいリクエストがあると、それに引きずられ全体の読み込み時間が長くなってしまいます。1車線の対面通行道路が渋滞を起こしやすいのと同じです。一方HTTP/2では、1つのTCPコネクションにおいて複数のリクエスト〜レスポンスのセットを同時に送受信できます。1つのリクエスト〜レスポンスのやりとりをストリームと呼び、このストリームを多重化することにより効率化を測っています。車線が増えて、パラレルに運行できるようになった感じです。
HTTP/1.1と比べてどれくらい早くなったのかについては、後ほど計測してみます。
H2O WebサーバーをIDCFクラウド上で構築
H2Oは2014年の年末にリリースされた新世代のWebサーバーです。Apache、NginxなどのメジャーなWebサーバーミドルウェアは一通りHTTP/2に対応しています。その中でも、H2OはHTTP/2対応を目的に一から設計されているため、最適化されています。
利用環境
今回、IDCFクラウドで構築するH2Oサーバーの詳細は次の通りです。仮想マシン作成の手順はこちらを参考にしてください。
- IDCFクラウド Standard.S4 (1 CPU, 4GB メモリ)
- CentOS 7.3 64-bit テンプレート
- Let’s EncryptでSSL証明書を発行
- 「IPアドレス」でSSH(22番)、HTTP(80番)、HTTPS(443番)のポートフォワードとファイアウォールの設定
- DNSでドメイン名を登録しておく (以下myDomain)
Let’s Encrypt証明書の取得
# yum -y install epel-release # yum -y install certbot # certbot certonly --standalone --agree-tos -m <emailAddress> -d <myDomain>
実行の結果、「〜〜Congratulations!〜〜 」と表示されれば取得は完了です。鍵は次のパスに設置されています。
# ls /etc/letsencrypt/live/myDomain/ README cert.pem chain.pem fullchain.pem privkey.pem
H2Oのインストール
ソースからダウンロードします。オフィシャルドキュメントに丁寧に書かれているので、合わせて参考にしてください。今回はバージョン2.2.0を使用します。
# yum groupinstall "Development Tools" # yum install cmake libyaml-devel openssl-devel # wget https://github.com/h2o/h2o/archive/v2.2.0.tar.gz # tar xvzf v2.2.0.tar.gz # cd h2o-2.2.0/ # cmake . # make h2o # make install
h2o.confファイル設定
オフィシャルドキュメントを参考に、h2o.confファイルを/usr/local/etc/h2o/配下に作成します。 関連するlogファイルも合わせて作成しておきます。
# mkdir -p /var/www/h2o # mkdir /var/log/h2o/ # touch /var/log/h2o/access_log # touch /var/log/h2o/error_log # vi /usr/local/etc/h2o/h2o.conf hosts: "myDomain": listen: port: 80 listen: port: 443 ssl: certificate-file: /etc/letsencrypt/live/myDomain/cert.pem key-file: /etc/letsencrypt/live/myDomain/privkey.pem paths: "/": file.dir: /var/www/h2o access-log: /var/log/h2o/access_log error-log: /var/log/h2o/error_log http2-reprioritize-blocking-assets: ON # performance tuning option
H2O起動
それでは上記で作成したconfファイルを指定してH2Oサーバーを起動します。トップページも適当なものを用意しておきます。
# /usr/local/bin/h2o -c /usr/local/etc/h2o/h2o.conf &
ブラウザからhttpsでアクセスして、画面が表示されれば成功です!
レスポンス計測してみる
Google Chromeデベロッパーツールで見る
冒頭でも説明した通り、HTTP/2の特徴はストリームの多重化です。なので、我が家の愛犬たらちゃん©の画像をたくさんページに並べて、HTTP/1.1とHTTP/2両方でアクセスします。Google ChromeのデベロッパーツールのNetworkパネルを開いて、リソースの読み込み時間を観測します。
まず、全体の読み込みにかかった時間はHTTP/1.1が3.96秒に対し、HTTP/2が3.14秒と約20%改善されています。暗号化されているのに、20%も改善されているのはすごいです!また、2つのグラフを比べて一目瞭然ですが、画像の読み込みをHTTP/1.1が逐次行っているのに対し、HTTP/2では並列に取得しています。先ほども紹介した、ストリームの多重化ですね。
▲HTTP/1.1でアクセスした場合
▲HTTP/2でアクセスした場合
h2loadでベンチマーク
Webサーバーのベンチマークツールで有名なのはab (apache bench)ですが、abはHTTP/2に対応していないため、今回はh2loadを使ってパフォーマンスを計測します。ベンチマークの対象は先ほどと同じページです。h2loadは非常に便利で、nghttp2というパッケージに同梱されており、これをソースからbuildします。h2loadコマンドに–h1オプションをつけることによって、HTTPSのURIでも強制的にHTTP/1.1で計測するように指定できます。では、早速両方試してみます。
まずはHTTP/1.1です。リクエスト数は10,000、コネクション数は100を指定します。
# h2load -n 10000 -c 10 --h1 https://myDomain starting benchmark... spawning thread #0: 10 total client(s). 10000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES256-GCM-SHA384 Server Temp Key: ECDH P-256 256 bits Application protocol: http/1.1 progress: 10% done progress: 20% done progress: 30% done progress: 40% done progress: 50% done progress: 60% done progress: 70% done progress: 80% done progress: 90% done progress: 100% done finished in 387.58ms, 25800.86 req/s, 37.01MB/s requests: 10000 total, 10000 started, 10000 done, 10000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 10000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 14.34MB (15040000) total, 1.76MB (1850000) headers (space savings 0.00%), 12.09MB (12680000) data min max mean sd +/- sd time for request: 166us 3.96ms 334us 104us 89.38% time for connect: 17.05ms 20.88ms 18.89ms 1.26ms 60.00% time to 1st byte: 21.00ms 21.21ms 21.11ms 71us 60.00% req/s : 2583.92 3093.93 2832.31 139.99 70.00%
続いてHTTP/2です。HTTP/1.1と同じように、リクエスト数は10,000、コネクション数は100を指定します。
# h2load -n 10000 -c 10 https://myDomain starting benchmark... spawning thread #0: 10 total client(s). 10000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES256-GCM-SHA384 Server Temp Key: ECDH P-256 256 bits Application protocol: h2 progress: 10% done progress: 20% done progress: 30% done progress: 40% done progress: 50% done progress: 60% done progress: 70% done progress: 80% done progress: 90% done progress: 100% done finished in 359.23ms, 27837.47 req/s, 34.52MB/s requests: 10000 total, 10000 started, 10000 done, 10000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 10000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 12.40MB (13001100) total, 137.50KB (140800) headers (space savings 91.95%), 12.09MB (12680000) data min max mean sd +/- sd time for request: 161us 3.00ms 314us 101us 89.77% time for connect: 17.15ms 21.03ms 19.00ms 1.26ms 60.00% time to 1st byte: 21.10ms 21.35ms 21.21ms 71us 60.00% req/s : 2788.66 3349.59 2984.09 176.11 60.00%
一見ちょっとわかりづらいので表組みにしてみます。笑
プロトコル | time | req/sec | total traffic | header size |
---|---|---|---|---|
HTTP/1.1 | 387.58 ms | 25,800.86 | 14.34 MB | 1.76 MB |
HTTP/2 | 359.23 ms | 27,837.47 | 12.40 MB | 137.50 KB |
結論、HTTP/2は優秀でした。
- 秒間リクエスト数がHTTP/2のほうが多く、ベンチマークにかかった時間も10%弱少なかった
- ヘッダー圧縮が効いているので、トラフィックサイズもHTTP/2のほうが少ない
- そもそもHTTP/2は暗号化されているので、HTTP/1.1より成績が良い時点で文句なし
まとめ
IDCFクラウド上でさくっとH2OのWebサーバーを立ててHTTP/2化する方法を紹介しました。HTTP/1.1と比べ、性能的にも帯域使用量においても改善されているため、みなさんもぜひHTTP/2を試してみてください!なお、今回使用したLet’s Encryptの無料SSL証明書は3ヶ月で有効期限が切れてしまうので、cronなどで自動更新を仕掛けておくのが良いでしょう。
IDCFクラウドでロードバランシングをする際の選択肢として、仮想ルーターの標準ロードバランサー機能とILBが挙げられますが、ILBは現在HTTP/2未対応のため、HTTP/2を使いたい場合は仮想ルーターでHTTPSのままロードバランシングするのをおすすめします。また、IDCFクラウドのコンテンツキャッシュも今年夏ごろHTTP/2に対応する予定なので、その時は別エントリーで改めて紹介します。