REST APIサーバーがエラー多発してきた時のためのNginx PHP-FPM設定

2014-02-28

昨今では、サーバーサイド側はJSONをやりとりするだけのREST APIサーバーにして、フロントでJSをゴリゴリしてサイトを作るってのが流行ってますよね。

インケンが携わっているプロジェクトでも、PHPのAPIサーバーとフロントがBackbonejsという構成になっています。

今までの経験上、WEBサイトって大抵の場合DBがボトルネックになっているのですが、インケンが携わっているプロジェクトにてAPサーバーが悲鳴を上げだしたので、サーバーの設定を見直しました。

例えば、負荷が高まるとこんなエラーが出てきます。

Nginx /var/log/nginx/error.log


[error] 16347#0: *2141360 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: xxx.xxx.xxx.xxx

[error] 18897#0: *7931791 connect() failed (111: Connection refused) while connecting to upstream, client: xxx.xxx.xxx.xxx

[error] 18898#0: *7866945 upstream timed out (110: Connection timed out) while reading response header from upstream, client: xxx.xxx.xxx.xxx

worker connection not enough

だいたいどれも、コネクションが切れた、タイムアウトしたといったエラーです。

一番下のはわかりやすいですね。nginxのworkerコネクション数が足りないよって言われてます。

APIサーバーとJSといった構成の場合、どうしても通常のサイト(PHPがHTMLを吐き出して、AJAXをそこまで使用していないサイト)よりリクエスト数が増えます。

1ページ表示するのに、PHP側には10リクエスト以上飛んでくるってのもザラです。

なので、PV少なそうなのにMAXコネクションまで行ってるよ、、ってことがわりとあるんですね。

実際にインケンのプロジェクトでエラーが多発した時の対処をご紹介します。

参考スペック

APIサーバーのスペックはCPU4コア、メモリ14Gで、APIサーバーが2台、DBマスター1台、スレーブ2台、その他KVSやMQサーバーなどがあります。

月間PV1000万以上です。ピーク時のGoogle Analyticsのリアルタイム値が
1分間で200PV x 10 (_setSampleRateが10なので)

1ページで10のAPIリクエストがあるとすると、秒でざっくり330リクエスト飛ぶことになります。

設定値は各サーバーのスペックとか、同時アクセス数にもよるので、参考までに。

Nginxの設定

worker connection not enoughが出るような場合は、max値を上げましょう。

/etc/nginx/nginx.conf

events {
    use epoll;
    worker_connections 2048;
}

1024 → 2048にしました。

設定値はサーバーのスペック、アクセス数によって調整してください。

PHP-FPMの設定

104: Connection reset by peer , 111: Connection refused , 110: Connection timed outあたりのエラーは大抵PHPがボトルネックになっています。

/etc/php-fpm.d/www.conf

pm = static
pm.max_children = 300
pm.max_requests = 1000

pm = staticは最初から小プロセスの起動数を固定する記述です。dynamicだと動的ですが、最初から確保できるstaticのがよさげです。

max_childrenは起動する小プロセスの最大数です。これが低くて足りないと502 Bad Gateway が多発します。だからといってむやみに多くしてもLoad Average増えちゃう予感!

max_requestsは子プロセスが、再起動するまでに実行するリクエスト数です。メモリと相談。

パラメーターの詳しい説明は、公式のドキュメントに載ってるので参考にしてください

それ以外の設定

それ以外で対応できることとしては、apcの設定を見なおしたり、/etc/sysctl.confの中身やら、nginxのkeepaliveやらをもろもろ確認したほうがいいと思います。

あとはリクエストをまとめたり、プログラムを見なおしたり

でも結局はスケールアウトした方がいいかも

インケンのプロジェクトでは、上記の設定に見なおしたのですが、それでも若干不安定だったので、結局はAPIサーバーをスケールアウトしました。

各サーバーの設定を見なおして、最適化するのも大事ですが、コスト面で都合がつけばスケールアウトしたほうがいいと思います。