Nginx+PHP-fpm環境で504エラーが出たので対応方法の検証

2019年1月12日

サーバー テクノロジー トラブル

待ち合わせ時間に遅れるヤツって腹たちますよね?そしてさらに遅れてきて何も言い訳をしないヤツもっと腹たちますよね? もちろん、事前に約束をしていたにも関わらずドタキャンなんかされたら、怒り沸騰です。 同じ事がインターネットWEBサイトにも言えて、待ち時間の長いWEBサイトは、閲覧していてイライラしてしまいがちです。 おまけにGoogleにも嫌われがちで、SEOランキングが下がりがちになります。 ガチで、人を待たせるのはよく無いという事なので、サーバーの待ち時間をいかに少なくできるかというのは、WEBサービス提供者側としては、ずっと追求していく課題でもあります。 今回、とあるシステム構築をしている時に、非常にサーバー処理の負荷が高い機能が504エラーを発したため、その対応方法などを備忘録化しておきたいと思います。

504エラーとは

インターネットサーバーで504エラーと言えば、タイムアウトですが、ProxyやCDNやDNS不調など、色々な要因があるみたいですが、一番多いのがサーバーの処理負荷が高くて制限時間を超えてしまう事が原因であるようです。 そもそもサーバー側では、ApacheやNginxといったパケットを受け取って処理をするモジュールと、PHPなどのプログラムを実行するモジュールがインストールされていて、これらがサーバーアクセスがあった際に、レスポンスを返す事でインターネットWEBサイトの閲覧ができるのですが、 レスポンスを返すまでの時間をlimitとして登録されているデフォルト値があります。 この値を超えた(秒数オーバーになる)場合に、504エラーを返す仕組みになっています。

今回の環境について

そもそもの話ですが、今回の環境について記述しておきます。 インターネットサーバーと言っても世の中にはいろいろな環境が存在するので、違う環境の場合はあまり参考にならないかもしれませんので事前にご了承くださいませ。 # サーバーOS : Ubuntu $ uname -a Linux 3edfc8aa86df 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux # Webサーバー : Nginx $ nginx -v nginx version: nginx/1.10.0 (Ubuntu) # PHPモジュール : php-fpm7.0 $ php -v PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies with Zend OPcache v7.0.22-0ubuntu0.16.04.1, Copyright (c) 1999-2017, by Zend Technologies サーバーOSはubuntuでもcentosでもLinuxであれば問題ないとは思いますが、windowsサーバーやその他のunix系などのサーバーについては、違いが大きいこともあるのでご自身で検証してください。 ちなみに、Nginx+phpは僕のよく使うスタンダード環境で、これにNodejsを付け加えると大体のWEBサービスが構築できてしまうし、wordpressでも問題なく使えてしまうので、デフォルト環境にしています。

具体的な対応方法

そもそも今回の事象が発生した時に「PHP 504エラー」としてググってみたんですが、全然タイムアウトエラーが回復しなかったので、ハマった事から、似たように困っている人もいるのではないかと、記事に書いておくことにしました。 まず、行う設定は2つで、以下の通りです。
1. php.iniの"max_execution_time"を最適な数値に変更 2. nginxのconfファイルの設定に"server{fastcgi_read_timeout 秒数}"を追記する
最初はPHPの設定ばかりやっていたのですが、Nginxの設定も同時に行わないといけない自体に気が付いて解決する事ができました。 ちなみに、設定完了したあとは、"php","nginx"どちらのモジュールもrestartするのを忘れないようにしましょう。

PHPはプログラムに記述できる?

ini_set関数を使って、タイムアウトの秒数をコントロールできると、非常に堅牢なシステムが作れると考えたので、以下検証しておきます。 まずはブラウザで表示される504エラー(nginx-default)は以下のような画面です。

デフォルト値と最適値

そもそも、nginxのtimeout-limit値とphp(-fpm)の上限timeout値はどのくらいなんでしょう?
fastcgi_connect_timeout : デフォルト 60秒 fastcgi_read_timeout : デフォルト 60秒 fastcgi_send_timeout : デフォルト 60秒 keepalive_timeout : デフォルト 65秒 send_timeout : デフォルト 60秒
今回は"fastcgi_connect_timeout"しか使いませんが、色々な場面で上記の設定が必要になる場合もあるので、合わせて覚えておきましょう。 あまりよろしく無いかもしれませんが、nginxでのtimeoutはできるかぎり無制限に近い状態にして、php(cgi)側での制限に集約しておきます。 server{ ...(通常設定) fastcgi_read_timeout 999999; } 次にPHPのtimeout対応ですが、やってみて気が付いたんですが"max_execution_time"の値がタイムアウトの上限値のはずなのに、まったくエラーが出ない状態です。 おそらくnginxでの設定が有効になっているのかもしれません。 とりあえず、局所的な設定でのみ使うようにするのがいいかもしれませんね。

limitを大きくすると生じるデメリット

実は今回行なったようなlimitの上限値を極端に大きくする事は、サーバー設定では望ましくありません。 何故なら、負荷が高い時にリミットが無いと、サーバーは負荷を高め続ける状態になってしまいます。 そのため、一定秒数以上でエラーにするという救済処置のために、「デフォルト値」というのを設けています。 ただし、これはWEBページとして表示する時のリミットであって、CLIとしてコマンドで実行すると、上限値なしで処理が完了できてしまうことから、この点はリミット考慮がされていません。 cliにも"max_execution_time"は設定できるんですが、恐らくNginxやApacheを通らないので、この設定が意味がないように思われますね。 本来であれば、PHPのini-setで、プログラム内部でコントロールできれば一番いいのですが、今の所今回セットした方法しかやりようがなさそうですね。 まだまだ研究の余地はありそうです・・・

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ