Core開発部の加藤です。かなりシンプルなレスポンスを返すだけのAPIを作成するにあたって、短時間に量を捌きたいという要望が出てきました。そういう時はGo言語が早いと聞いていたのですが、それこそ"Hello World"レベルであればPHPでもほぼ変わらないと思いNginx+PHP
,Nginx+Go
で単に"Hello World"を返すというレベルの処理の場合にはどんな差が出るのかちょっと試してみました。(ちなみにPHPは7ではなくて5です。)
AWSを利用して動作確認を行いました。 面倒の無いようにシンプルに構築したため下記のような環境になっています。
インスタンスタイプ: t2.micro
OS : amazon-linux2
nginx: 1.12 (amazon-linux-extras経由でインストール)
Go: 1.9 ( (amazon-linux-extras経由でインストール)
php: 5.4.16 (yumでインストール)
設定値については全くいじらず未調整のため、実情とは多少ずれている可能性はありますが、およその傾向を確認する程度という事でひとまずそのまま測定しています。
測定については、折角Go言語を入れたのでGo言語製のheyというベンチマークツールを使ってみました。
Nginx + PHP5
では、PHPはFCGIとして動かしています。Nginx + Go
についてはFCGIとして動かしての測定と、Nginxを使わずGo
でHttpサーバ立てての測定をします。
Nginx + PHP5
まずはNginx + PHP5
について。100件までの同時アクセスで計100000アクセスをさせてみてます。結果は下記、hey
初めて使いましたがシンプルで見やすい表示ですね。ざっくり確認する程度であれば非常にありがたいです。
$ hey -n 100000 -c 100 http://127.0.0.1/php/test.php Summary: Total: 33.3472 secs Slowest: 0.6459 secs Fastest: 0.0006 secs Average: 0.0332 secs Requests/sec: 2998.7525 Response time histogram: 0.001 [1] | 0.065 [99733] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.130 [200] | 0.194 [13] | 0.259 [11] | 0.323 [8] | 0.388 [8] | 0.452 [7] | 0.517 [6] | 0.581 [7] | 0.646 [6] | Latency distribution: 10% in 0.0262 secs 25% in 0.0322 secs 50% in 0.0335 secs 75% in 0.0347 secs 90% in 0.0361 secs 95% in 0.0395 secs 99% in 0.0515 secs Details (average, fastest, slowest): DNS+dialup: 0.0000 secs, 0.0006 secs, 0.6459 secs DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0054 secs req write: 0.0000 secs, 0.0000 secs, 0.0190 secs resp wait: 0.0330 secs, 0.0006 secs, 0.6457 secs resp read: 0.0001 secs, 0.0000 secs, 0.0207 secs Status code distribution: [200] 100000 responses
殆どが0.065secのなか、0.6secかかるレスポンスがちらほら見られます。部分部分でメモリへの再読み込みが発生している影響かとも思いましたがそれにしてはちょっとかかり過ぎな気がします。詳しい方いたら教えてくれると嬉しいです。
Nginx + go
go言語で同じ様に確認をしてみます。
$ hey -n 100000 -c 100 http://127.0.0.1/go/test Summary: Total: 39.3772 secs Slowest: 0.0862 secs Fastest: 0.0004 secs Average: 0.0393 secs Requests/sec: 2539.5388 Response time histogram: 0.000 [1] | 0.009 [1192] |■ 0.018 [458] | 0.026 [1557] |■ 0.035 [3627] |■■ 0.043 [85919] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.052 [6335] |■■■ 0.060 [349] | 0.069 [68] | 0.078 [453] | 0.086 [41] | Latency distribution: 10% in 0.0380 secs 25% in 0.0391 secs 50% in 0.0399 secs 75% in 0.0407 secs 90% in 0.0421 secs 95% in 0.0442 secs 99% in 0.0512 secs Details (average, fastest, slowest): DNS+dialup: 0.0000 secs, 0.0004 secs, 0.0862 secs DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0000 secs req write: 0.0000 secs, 0.0000 secs, 0.0267 secs resp wait: 0.0392 secs, 0.0004 secs, 0.0853 secs resp read: 0.0000 secs, 0.0000 secs, 0.0246 secs Status code distribution: [200] 100000 responses
予想ではもっと圧倒的にPHPより早いかと思っていたのですがトータルではPHP5より時間がかかるという状態になっていました。とはいえ一番時間のかかっているレスポンスでも0.0862secと、PHPに比べると安定したレスポンスの速さです。この辺り突っ込んで調べきれてはいないのですが、バイナリのGoの方がFCGIでの再ロードが高速なのではないかと考えています。
goのみ
nginxを介さずに、goのみでレスポンスを返すと、どのくらいの性能が出るのか測定してみました。
$ hey -n 100000 -c 100 http://localhost:8889/go/test Summary: Total: 14.6001 secs Slowest: 0.0459 secs Fastest: 0.0001 secs Average: 0.0144 secs Requests/sec: 6849.2468 Total data: 1400000 bytes Size/request: 14 bytes Response time histogram: 0.000 [1] | 0.005 [3564] |■■■■■■ 0.009 [21245] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.014 [22729] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.018 [22583] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.023 [21877] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.028 [7914] |■■■■■■■■■■■■■■ 0.032 [77] | 0.037 [9] | 0.041 [0] | 0.046 [1] | Latency distribution: 10% in 0.0062 secs 25% in 0.0093 secs 50% in 0.0143 secs 75% in 0.0194 secs 90% in 0.0226 secs 95% in 0.0237 secs 99% in 0.0253 secs Details (average, fastest, slowest): DNS+dialup: 0.0000 secs, 0.0001 secs, 0.0459 secs DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0013 secs req write: 0.0000 secs, 0.0000 secs, 0.0131 secs resp wait: 0.0143 secs, 0.0001 secs, 0.0290 secs resp read: 0.0000 secs, 0.0000 secs, 0.0114 secs Status code distribution: [200] 100000 responses
nginxとのやり取りもnginxでかかっている時間も無いので、その分の差はかなりあるだろうとは思っていましたが、こうして見るとやはりそれなりに差が出てきますね。
まとめ
Nginx+Go, Nginx+PHP5については、PHP5でもかなりの速度が出せていた事が驚きました。 NginxやFCGIについては何も設定を調整していないため、恐らくパラメータの調整でもう少し性能向上はできると思います。NginxとGo, PHP間はTCPでやり取りしたためUnixソケットを使うことでもう少し早くなるでしょうし、インスタンスのサイズに合わせてプロセス数の制限等に適当な値を設定することでも速度向上するかと思います。
PHPで妙に時間のかかるレスポンスが発生しているという問題がありましたが それ以外の結果につきましては、それぞれの最頻値を見る限りでは0.065sec vs 0.043secという事で若干Goの方が早い形です。この辺はPHP7だともっと差が縮まっていそうです。とはいえバイナリであることによる速度差が乗ってくるとGoの方が早いというのは頷けます。
Nginx無しで、Goのみで対応するケースについては、レスポンスの速度がよほどクリティカルな案件でなければNginx噛ませてFCGIで呼び出してもらったほうが安定はするかと思いますが、これだけ違いが明らかだと、極シンプルな作りであればHTTPサーバとしての処理をNginxに任せられるという部分を削ってでもGo言語のみで最小構成で運用する事を考慮するケースも出てきそうです。