スピード狂の夢
はじめまして、ゲヒルン株式会社でエンジニアのアルバイトをしているKOBA789こと小林です。
弊社でゲヒルンニュースなるブログ(言わずもがな、本ブログです)がスタートするということで、社長にその記事の原稿を頼まれました。「頭のおかしいネタでお願い」と聞いた(気がする)のでモダンブラウザの新機能で遊んでみようと無理をしたのですが、日曜返上で月曜の朝まで粘ったにもかかわらず、まともな結果が出ず、急遽ネタを変更することになりました。本当に頭がおかしかったのはネタというよりも自分自身だったようです。
さて、私はスピード狂です。数年前、Apache+PHPの遅さが頭にきてNode.jsをいじりはじめました。しかし最近ではそのNode.jsですら遅さを感じるほどに感性が狂ってきてしまいました。なぜ遅いか。それはユーザーランドで動いているからに他なりません。システムコールはオーバーヘッドです。さらに言えば、流行りの非同期I/Oはシステムコールをより頻発します(細切れにデータを読み込むので)。やはり、真のスピードを求めるなら、カーネルランドで動く必要があるはずです。
しかし、急遽ネタを変更した私にカーネルモジュールを開発する余裕はありません。困りました。困ったのでGoogle先生に相談しました。すると、あるではないですか。カーネルランドで動くhttpdが!
というわけで初っ端から他力本願で元も子もないわけですが、今回はこのソフトウェアのベンチマークで遊んでみましょう。計測環境は我が家の可愛いサーバー達です。
環境
サーバーとクライアントのVMのホストは別の物理マシンです。
サーバー
SmartOS上に以下の様なVMを作りました。
- CPU: Intel Xeon E3-1220 @3.10GHz (4コア割り当て)
- RAM: 2GB
- OS: Ubuntu 12.04
クライアント
SmartOS上に以下の様なVMを作りました。
- CPU: Intel Core i3-2100 @3.10GHz (4コア割り当て)
- RAM: 16GB
- OS: Ubuntu 12.04(virtualized) on SmartOS
準備
サーバー側の準備。
まずはrecaroのソースコードをclone
します。
$ git clone git://github.com/KLab/recaro.git
次に、ディレクトリに入ってmake
します。
$ cd recaro
$ make
すると、recaro.ko
というカーネルモジュールがビルドできているはずです。
そして、カーネルモジュールのロードはroot
で。
$ sudo insmode recaro.ko
この時点で80番ポートでhttpdがlistenしています。
実験
まずはrecaroのベンチマーク。クライアント側からこのようなコマンドでベンチマークを実行してみます。
$ ab -k -n 5000 -c 500 http://server/foo
結果は以下のとおり。
Server Software:
Server Hostname: 10.2.0.9
Server Port: 80
Document Path: /foo
Document Length: 9 bytes
Concurrency Level: 500
Time taken for tests: 0.855 seconds
Complete requests: 5000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 5000
Total transferred: 485000 bytes
HTML transferred: 45000 bytes
Requests per second: 5849.84 [#/sec] (mean)
Time per request: 85.472 [ms] (mean)
Time per request: 0.171 [ms] (mean, across all concurrent requests)
Transfer rate: 554.14 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 3 13.1 0 94
Processing: 6 61 59.6 54 396
Waiting: 6 61 59.6 53 396
Total: 6 64 71.1 54 489
Percentage of the requests served within a certain time (ms)
50% 54
66% 59
75% 61
80% 63
90% 95
95% 160
98% 342
99% 450
100% 489 (longest request)
んー、あんまり速くない?
次にNginxのベンチマーク。同じVM上の8080番ポートで動かしました。
Server Software: nginx/1.1.19
Server Hostname: 10.2.0.9
Server Port: 8080
Document Path: /
Document Length: 151 bytes
Concurrency Level: 500
Time taken for tests: 0.816 seconds
Complete requests: 5000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 5000
Total transferred: 1835000 bytes
HTML transferred: 755000 bytes
Requests per second: 6129.61 [#/sec] (mean)
Time per request: 81.571 [ms] (mean)
Time per request: 0.163 [ms] (mean, across all concurrent requests)
Transfer rate: 2196.84 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 9 26.9 0 101
Processing: 17 71 33.4 63 411
Waiting: 17 71 33.4 63 411
Total: 17 80 48.2 64 499
Percentage of the requests served within a certain time (ms)
50% 64
66% 80
75% 90
80% 93
90% 129
95% 174
98% 192
99% 250
100% 499 (longest request)
うーん、recaroよりも速い。なんでだ。
というわけでそれぞれ3回計測した平均が以下です。
- Nginx: 3870 reqs/sec
- recaro: 2967 reqs/sec
あれれ……Nginxの方が速いですね。どういうことでしょうか。
実はなぜか途中からrecaroのベンチはapr_socket_recv: Connection reset by peer (104)
というエラーを頻発しているのです。なので上記の結果はエラーの起きてない計測結果を3つ平均したものです。進捗を眺めていてもパケ詰まりのような挙動をするので、もしかするとこのエラーの原因がrecaroのパフォーマンスの足を引っ張っているのかもしれません。
まとめ
今回のエラーがホストOSやゲストOSの問題なのか、それともrecaroやNginx自体の問題なのか、はたまたNICの問題なのかは不明ですが、環境を変えて再度実験する必要があるのは確かです。スピード狂としてはカーネルランドで動くhttpdの方が遅いという事実を否定したいところですので、余っているもう一台の物理マシンにいろいろなOSをインストールして再チャレンジしてみようと思います。また、今回は時間が少なかったためできませんでしたが、recaroのソースコードリーディングも面白そうなのでやってみたいところです。