Raspberry Pi 2 Model B と 高速HTTPサーバーH2Oで毎秒2万リクエスト

Raspberry Pi 2 Model B が届いてベンチマークを取ってみました。前回H2OというHTTPサーバーで遊んでみましたが、Raspberry Pi 2でそれをやってみたところ、2万req/secを達成出来ました。OSはRasbian(Linux raspberrypi 3.18.7-v7+ #755 SMP PREEMPT Thu Feb 12 17:20:48 GMT 2015 armv7l GNU/Linux
)を使用しました。CPUのオーバークロックなどはしていません。

まずはインストール・立ち上げ方法を書いておきます。

$ sudo aptitude install cmake make gcc c++ libyaml-dev git
$ git clone git clone https://github.com/h2o/h2o
$ cd h2o
# ↓cmakeでピリオドを忘れないようにしてください。
$ cmake .
$ make

# (蛇足ですが↑でmake -jなどとして高速なコンパイルをしようとするとエラーが出ました)

# confの設定。一旦オリジナルを保持してから新しく作る。
$ cp examples/h2o/h2o.conf examples/h2o/h2o.conf.orig
$ vi examples/h2o/h2o.conf
$ cat examples/h2o/h2o.conf
user: root
http2-max-concurrent-requests-per-connection: 1024
num-threads: 4
listen: 8080
hosts:
  "0.0.0.0.xip.io:8080":
    paths:
      /:
        file.dir: examples/doc_root

# 'Hello, world.'という中身のファイルを作成
$ echo 'Hello, world.' > examples/doc_root/index.html

# 起動スクリプトの設定
$ echo './h2o -c examples/h2o/h2o.conf' > run.sh
$ chmod +x run.sh

# 起動
$ ./run.sh
[INFO] raised RLIMIT_NOFILE to 4096
h2o server (pid:2422) is ready to serve requests

↑さて、別のマシンでベンチマークしてみます。

トポロジーは、

Raspberry Pi 2 <=> GbEスイッチングハブ <=> クライアント(Opteron 3280, 8cores@2.4GHz、Ubuntu 12.04.5)

です。ラズパイとスイッチングハブ間は100Mbpsになっています。ラズパイのNICが100Mだからです。スイッチングハブとクライアントの間は1Gbpsです。つまりラズパイ<=>クライアントの帯域は100Mbpsとなります。

ベンチマークツールには、wrkというものを使います。

以下、ベンチマークです。クライアントマシンから一旦正常に通信できるか確かめて、次にベンチマークを取ります。

# 以下、クライアントから実行しています。
# ラズパイのIPアドレスは192.168.1.145だったとします。
$ curl http://192.168.1.145:8080/
Hello, world.

# wrkベンチマーク
$ ./wrk -c 100 -d 10 -t 5 http://192.168.1.145:8080/
Running 10s test @ http://192.168.1.145:8080/
  5 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.85ms  613.12us  15.60ms   73.90%
    Req/Sec     4.32k   272.86     5.50k    63.81%
  204553 requests in 10.00s, 45.06MB read
Requests/sec:  20455.96
Transfer/sec:      4.51MB

Requests/sec: 20455.96 !!!
というわけでラズパイ2とH2Oで毎秒2万リクエストを達成しました\(^o^)/

これまでの挑戦では毎秒1.9万ぐらいで足踏みしていたのですが、ラズパイ2を再起動してみてベンチマークを走らせたらあっさり到達出来ました。時代はリブートテクノロジーですね。

カーネルオプションはいろいろといじってみたりしましたが、効果がありませんでした。試みてみたもの一覧が以下になります。

sysctl -w fs.file-max=9999999
sysctl -w fs.nr_open=9999999
sysctl -w net.core.netdev_max_backlog=4096
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.somaxconn=65535
sysctl -w net.core.wmem_max=16777216
sysctl -w net.ipv4.ip_forward=0
sysctl -w net.ipv4.ip_local_port_range=1025 65535
sysctl -w net.ipv4.tcp_fin_timeout=30
sysctl -w net.ipv4.tcp_keepalive_time=30
sysctl -w net.ipv4.tcp_max_syn_backlog=20480
sysctl -w net.ipv4.tcp_max_tw_buckets=400000
sysctl -w net.ipv4.tcp_no_metrics_save=1
sysctl -w net.ipv4.tcp_syn_retries=2
sysctl -w net.ipv4.tcp_synack_retries=2
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w vm.min_free_kbytes=65536
sysctl -w vm.overcommit_memory=1

ちなみにapache2 (Server version: Apache/2.2.22 (Debian), Server built: Jan 10 2015 15:51:04)では、

$ curl http://192.168.1.145/index.html
Hello, world.

$ ./wrk -c 100 -d 10 -t 3 http://192.168.1.145/index.html
Running 10s test @ http://192.168.1.145/index.html
  3 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    19.38ms  133.78ms   5.42s    99.31%
    Req/Sec     1.71k   268.19     2.54k    66.11%
  50716 requests in 10.00s, 13.01MB read
  Socket errors: connect 0, read 0, write 0, timeout 32
Requests/sec:   5071.31
Transfer/sec:      1.30MB

程度でした。-t 3と下げてますが(-tはthread数)、それでもtimeoutが出ていますね。

また、mod_phpですと、

$ curl http://192.168.1.145/index.php
Hello, PHP.

$ ./wrk -c 100 -d 10 -t 1 http://192.168.1.145/index.php
Running 10s test @ http://192.168.1.145/index.php
  1 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    49.77ms   50.72ms 232.25ms   82.86%
    Req/Sec     1.96k    24.84     2.02k    75.00%
  19403 requests in 10.00s, 3.74MB read
Requests/sec:   1939.90
Transfer/sec:    382.68KB

でした。-t 1にしているのは、それ以上だとtimeoutがたくさん出るからです。

OpenResty(ngx_openresty-1.7.7.2)ですと、

$ curl http://192.168.1.145:8080/
Hello, world!

$ ./wrk -c 100 -d 10 -t 4 http://192.168.1.145:8080/
Running 10s test @ http://192.168.1.145:8080/
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.85ms   22.93ms 793.53ms   97.85%
    Req/Sec     4.49k   746.82     7.28k    69.50%
  173783 requests in 10.00s, 30.49MB read
  Socket errors: connect 0, read 0, write 0, timeout 4
Requests/sec:  17378.24
Transfer/sec:      3.05MB

でした。OpenRestyのnginx.confは、

cat conf/nginx.conf 
error_log logs/error.log;
worker_processes 4;
 
events {
    worker_connections 1024;
    accept_mutex_delay 100ms;
}
http {
    keepalive_requests 500000;
    tcp_nopush on;
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua 'ngx.say("Hello, world!")';
        }
    }
}

でした。