IDCF テックブログ

IDCF テックブログ

クラウド・データセンターを提供するIDCフロンティアの公式テックブログ

IDCFクラウド上でさくっとH2Oサーバー作ってみた!簡単HTTP/2化

こんにちは、金杉です。

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では並列に取得しています。先ほども紹介した、ストリームの多重化ですね。

f:id:ykanasugi:20170605174632p:plain ▲HTTP/1.1でアクセスした場合

f:id:ykanasugi:20170605174626p:plain ▲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に対応する予定なので、その時は別エントリーで改めて紹介します。

Copyright © IDC Frontier Inc.