Core Tech Blog

株式会社Coreのエンジニアチームが日々習得した技術やTipsを公開するブログです

Nginx+PHPとNginx+Goの単純な処理性能差を確認してみた

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言語のみで最小構成で運用する事を考慮するケースも出てきそうです。