この記事は、mruby advent calendar 2015の16日目の記事です。
画像やstaticコンテンツ配信系はHTTP/2が有利な状況が幾つかあるので、ついでにHTTP/2を喋る画像変換サーバのプロトタイプをmrubyで作ってみました。ベースはもちろんtrusterdです。なんていったってmrubyのHTTP/2サーバですからね!!
最近また開発を再開しておりまして、昔はh2oやnghttp2のベンチマークに一緒に比較対象として入れてもらったりしていたのですが、しばらく離れているうちに皆さん先へ先へと行ってしまわれたので、また追いつけるようにセッセと勉強しながら実装しだしております。
その他、trusterdについてはこの辺とか、
この辺を見ていただくと良いかと思います。
trusterdのビルド
まずは早速以下のようにビルドしていきましょう。
build_config.rb
cloneしたtrusterd/
にあるbuild_config.rb
に、今回は画像変換するためのmgemをリンクするべく下記のmgemを追記します。
conf.gem :github => 'kjunichi/mruby-mrmagick'
- build
後はビルドするだけです。環境はubuntu14_04のコア4つメモリ8GBのVMWareを使いました。
make make install
build/conf/trusterd.conf
installすると、デフォルトではカレントディレクトリのbuild/
以下に必要なファイルがインストールされるので、その中にあるtrusterdの設定ファイルを以下のようにしました。
この設定によって、あっという間にHTTP/2 + TLS + 画像変換の動きをします。簡単ですね。
アクセス対象のPNGファイルに対して、image.png?type=half
などとクエリを与えてアクセスすると、画像を半分にしてレスポンスするような動きをします。今回はプロトタイプということで、簡単にそれのみの動きをするだけにとどめました。
SERVER_NAME = "Trusterd" SERVER_VERSION = "0.0.1" SERVER_DESCRIPTION = "#{SERVER_NAME}/#{SERVER_VERSION}" root_dir = "/home/matsumotory/DEV/trusterd/build" s = HTTP2::Server.new({ :port => 8080, :document_root => "#{root_dir}/htdocs", :server_name => SERVER_DESCRIPTION, :run_user => "matsumotory", :worker => "auto", :tls => true, :key => "#{root_dir}/ssl/server.key", :crt => "#{root_dir}/ssl/server.crt", :callback => true, }) s.set_map_to_storage_cb do r = s.r if File.extname(r.filename) == ".png" unless r.args.empty? # クエリパラメータは一つで?type=halfであること前提でとりあえず実装 type = r.args[1..-1].split("=")[1] if type == "half" new_file = r.filename + "_" + type + ".png" unless File.exist? new_file img = Mrmagick::ImageList.new(r.filename) new_img = img.scale(0.5) new_img.write(new_file) end r.filename = r.filename + "_" + type + ".png" end end end end s.run
ブラウザからHTTP/2アクセスできるようにTLS関連ファイルも以下のように試しに作っておきます。
cd build/ssl sudo sh -c 'yes "" | openssl req -new -days 365 -x509 -nodes -keyout server.key -out server.crt'
ブラウザアクセス
では早速ちゃんと変換されるか確認してみましょう。
通常のサイズのアクセスは以下のようになります。
さらに、画像変換すべくクエリーパラメータを与えて、今回は半分のサイズになるように?type=half
となるようにしてアクセスると、以下のように変換された結果が帰ってきました。
できました。
ベンチマーク
せっかくなので、ついでにベンチマークもとってみましょう。HTTP/2 + TLSなのでh2loadを使います。基本パラメータは以下とします。
h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/
- 変換前の画像へのベンチマーク
$ h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/logo.png starting benchmark... spawning thread #0: 25 total client(s). 250000 total requests spawning thread #1: 25 total client(s). 250000 total requests spawning thread #2: 25 total client(s). 250000 total requests spawning thread #3: 25 total client(s). 250000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES128-GCM-SHA256 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 12.45s, 80349.06 req/s, 655.39MB/s requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 8553033172 bytes total, 10030172 bytes headers (space savings 91.85%), 8525000000 bytes data min max mean sd +/- sd time for request: 3.45ms 330.42ms 111.99ms 46.70ms 62.28% time for connect: 14.57ms 147.67ms 76.94ms 22.21ms 75.00% time to 1st byte: 25.56ms 202.79ms 135.98ms 41.96ms 76.00% req/s (client) : 803.61 1766.93 935.77 291.06 89.00%
- 変換された画像へのベンチマーク
h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/logo.png?type=half starting benchmark... spawning thread #0: 25 total client(s). 250000 total requests spawning thread #1: 25 total client(s). 250000 total requests spawning thread #2: 25 total client(s). 250000 total requests spawning thread #3: 25 total client(s). 250000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES128-GCM-SHA256 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 14.15s, 70663.46 req/s, 385.74MB/s requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 5724037565 bytes total, 10034565 bytes headers (space savings 91.84%), 5696000000 bytes data min max mean sd +/- sd time for request: 8.55ms 332.16ms 129.32ms 42.88ms 65.24% time for connect: 38.10ms 214.01ms 79.91ms 33.53ms 94.00% time to 1st byte: 59.78ms 270.10ms 143.91ms 45.15ms 73.00% req/s (client) : 706.85 1201.34 793.84 171.11 85.00%
VMの環境でこれぐらいでればそこそこ良さそうですね。
logo.png | logo.png?type=half | |
---|---|---|
req/s | 80349.06 | 70663.46 |
参考:index.htmlのような小さなファイルのベンチマーク
trusterd + TLS + HTTP/2は、小さなファイルの場合はどれぐらい性能がでるのかもついでに確認しておきます。
$ h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/index.html starting benchmark... spawning thread #0: 25 total client(s). 250000 total requests spawning thread #1: 25 total client(s). 250000 total requests spawning thread #2: 25 total client(s). 250000 total requests spawning thread #3: 25 total client(s). 250000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES128-GCM-SHA256 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 3.40s, 294449.34 req/s, 13.76MB/s requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 49014749 bytes total, 9011749 bytes headers (space savings 92.55%), 22000000 bytes data min max mean sd +/- sd time for request: 487us 125.01ms 28.70ms 14.40ms 70.64% time for connect: 34.69ms 109.32ms 77.21ms 19.47ms 55.00% time to 1st byte: 57.57ms 158.23ms 103.08ms 28.21ms 60.00% req/s (client) : 2947.22 5091.48 3476.10 646.64 84.00%
小さいファイルは、TLSかつfdのキャッシュ無しで 294449.34 req/s
ぐらいでます。おお、まぁまぁはやい。
ついでにnginxのTLS+HTTP/2もベンチマーク
また、上記のベンチマーク結果だけでは基準となる値がどの程度かわかりにくいので、今回はさらにnginxもHTTP/2に対応している事を踏まえて、v1.9.6で以下のような設定をした上で、参考程度にindex.htmlとlogo.pngへのベンチマークを計測しました。
設定は以下のようにしており、この設定の場合はこの値だという参考情報としてお考え下さい。もっとチューニングしたら良い値が出るとは思いますので各々でお試し下さい。
- nginx.conf
worker_processes auto; events { worker_connections 10240; accept_mutex_delay 100ms; } daemon off; http { include mime.types; access_log off; server { listen 8080 ssl http2; ssl_ciphers AESGCM:HIGH:!aNULL:!MD5; server_name localhost; root /usr/local/trusterd/htdocs; ssl_certificate /usr/local/trusterd/ssl/server.crt; ssl_certificate_key /usr/local/trusterd/ssl/server.key; ssl_buffer_size 4k; } }
- nginx + TLS + HTTP/2でindex.htmlに同一ベンチマークパラメータでアクセス
$ h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/index.html starting benchmark... spawning thread #0: 25 total client(s). 250000 total requests spawning thread #1: 25 total client(s). 250000 total requests spawning thread #2: 25 total client(s). 250000 total requests spawning thread #3: 25 total client(s). 250000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES128-GCM-SHA256 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 10.24s, 97662.68 req/s, 16.02MB/s requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 172004900 bytes total, 132000000 bytes headers (space savings 24.14%), 22000000 bytes data min max mean sd +/- sd time for request: 142us 297.97ms 79.58ms 44.96ms 71.00% time for connect: 35.99ms 770.81ms 170.07ms 166.40ms 85.00% time to 1st byte: 38.84ms 938.26ms 209.14ms 188.24ms 85.00% req/s (client) : 977.32 1552.77 1273.85 233.02 43.00%
- nginx + TLS + HTTP/2でlogo.pngへのアクセス
$ h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/logo.png starting benchmark... spawning thread #0: 25 total client(s). 250000 total requests spawning thread #1: 25 total client(s). 250000 total requests spawning thread #2: 25 total client(s). 250000 total requests spawning thread #3: 25 total client(s). 250000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES128-GCM-SHA256 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 15.92s, 62829.21 req/s, 520.57MB/s requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 8688004900 bytes total, 136000000 bytes headers (space savings 23.60%), 8525000000 bytes data min max mean sd +/- sd time for request: 206us 285.12ms 137.15ms 48.74ms 70.04% time for connect: 19.46ms 923.68ms 227.51ms 201.02ms 84.00% time to 1st byte: 30.66ms 1.16s 286.52ms 229.84ms 77.00% req/s (client) : 628.66 869.51 721.25 71.74 50.00%
というような値になりました。まとめで表にします。
まとめ
ということで、画像変換をTLS + HTTP/2なサーバとして実装した上で、それに対するベンチマークにより、画像変換サーバとしてもそれなりにはやいということがわかりました。
今回用いたコンテンツのファイルサイズは以下です。
-rw-rw-r-- 1 matsumotory matsumotory 22 Dec 13 19:18 index.html -rw-rw-r-- 1 matsumotory matsumotory 8.4K Dec 13 19:40 logo.png
ベンチマークパラメータは以下のとおりです。
h2load -t 4 -c 100 -m 100 -n 1000000 https://127.0.0.1:8080/
HTTP/2 + TLSの画像変換のベンチマークと参考のためにnginxでも計測した結果のまとめは、以下(req/sec)となりました。
index.html(22byte) | logo.png(8.4kb) | logo.png?type=half(5.6kb) | |
---|---|---|---|
trusterd | 294449.34 | 80349.06 | 70663.46 |
nginx | 97662.68 | 62829.21 | - |
ということで、trusterdを使えば簡単にmrubyで画像変換サーバみたいなものがサクっと作れてそこそこ速いねという話でした。かなり遊べるサーバなので、是非Rubyで設定を書いて色々とお試し下さい。
今後、fd cacheの機能を実装すると、ベンチマーク的にはこれの2倍の性能が出ることはtrusterdのfd cacheのプロトタイプ実装で確認しているので、おいおい実装したいと思っております。