nginx+hhvm で UNIX Socket接続を試す

先日、PHP7 Casual Talks #2「速さ」に参加してきました。

その中で、nginx + php-fpm、apache+php-fpm 、apache+mod_php、 nginx+apache+mod_php との接続で、何が一番リクエストを処理できるかをベンチマーク(たしかsiegeを使ってた)を取っていました。

結果を見ると、nginx+php-fpmよりもapache+mod_phpのほうがリクエスト/秒の数値が多い。このとき、nginx+php_fpmはUNIX Socketを使って通信していました。まあ、普通UNIX Socketのほうが早いはずです。が、ここでnginx と php-fpmの接続をTCP(localhost:9000)にすると、順当にnginx+php-fpmのほうがリクエスト/秒が多くなったようです。

ここで疑問。なんでUNIX Socketだとリクエスト数/秒が少なくなるの?
とりあえず仮説を立てました。

ということで、やってみました。もちろんKUSANAGIで。

まず、hhvm 設定ファイル(/etc/hhvm/php.ini)の以下の部分を修正します。

次に、nginx設定ファイル(/etc/nginx/conf.d/XXX_html.conf)の以下の部分を修正します。2か所あるので、両方直しましょう。なお、ssl接続の時は、もう一つの設定ファイル/etc/nginx/conf.d/XXX_ssl.conf も同様に修正します。

/var/run/php-fpm のパーミションは一時的に777にしておきます。ここでサービス再起動。sock ファイルがうまく動くことを確認。

ここで自分自身に対して ab をかけます(URLは架空のものです)。リクエスト数1000、同時接続数100で実行すると、Requests per secondは130#/s でエラーなしでした。普通に早い何時ものKUSANAGIですね。

もうちょっと負荷を上げて同時接続数を300にしてみましょう。
おやおやエラーが出ましたね。

このときのエラーファイル(/home/kusanagi/XXX/log/nginx/error.log)を見ると、以下のようなエラーが出ていました。一時的にSocketファイルにアクセスできなかったようですね。

では、どんな動きをするか、strace で nginxのsystem call を追ってみましょう。strace は、-p  でプロセスID、-f でfork後のプロセスも追いかけます。nginxのプロセスIDはここでは なので、以下のようにstraceを実行後、別端末からab -n 1000 -c 300 で実行します。

通常は、connect()でソケットファイルを開き、hhvmとの通信処理を続行するのですが、大量通信時に、connect()が エラー(EAGEIN)を返します。これは一時的にサービスできないというエラーです。やはり同時接続数が多いと socket ではさばききれないようです。

同時接続数が多い場合、socketへの接続エラー発生率が高くなり、その結果秒間リクエストが少なくなる、ということのようです。

ということで、結論から言うと、以下の仮説は間違いでしたね。

正解は、Socketアクセスエラーが多くなる→正常処理できるリクエストが少なくなる、でした。

ちなみに、同じ環境でnginx+hhvmをtcp/9000で接続した場合、abの結果は以下のようになり、 エラーは発生してませんでした。

もっと過激にリクエスト数5000、同時接続数2000にしてみても、エラーは発生してませんね。リクエスト/秒もあまり変わらないのでエライ。