尽管配置,NginX在60秒后发出HTTP 499错误。 (PHP和AWS)
在上周末,我注意到我的一个中型AWS实例出现问题,如果请求超过60秒,Nginx总是会返回HTTP 499响应。被请求的页面是一个PHP脚本
At the end of last week I noticed a problem on one of my medium AWS instances where Nginx always returns a HTTP 499 response if a request takes more than 60 seconds. The page being requested is a PHP script
我花了几天时间试图找到答案,并尝试了我可以在互联网上找到的所有内容,包括Stack上的几个条目溢出,没有任何效果。
I've spent several days trying to find answers and have tried everything that I can find on the internet including several entries here on Stack Overflow, nothing works.
我尝试修改PHP设置,PHP-FPM设置和Nginx设置。你可以在星期五看到我在NginX论坛上提出的一个问题( http://forum.nginx .org / read.php?9,237692 )虽然没有收到任何回复,所以我希望在我被迫搬回Apache之前我可以在这里找到答案。
I've tried modifying the PHP settings, PHP-FPM settings and Nginx settings. You can see a question I raised on the NginX forums on Friday (http://forum.nginx.org/read.php?9,237692) though that has received no response so I am hoping that I might be able to find an answer here before I am forced to moved back to Apache which I know just works.
此不与其他条目中报告的HTTP 500错误相同。
This is not the same problem as the HTTP 500 errors reported in other entries.
我已经能够使用PHP 5.4.11使用新的微型AWS实例NginX复制问题。
I've been able to replicate the problem with a fresh micro AWS instance of NginX using PHP 5.4.11.
帮助任何希望看到问题的人在行动中我将带您完成我为最新的Micro测试服务器运行的设置。
To help anyone who wishes to see the problem in action I'm going to take you through the set-up I ran for the latest Micro test server.
您需要启动一个新的AWS Micro实例(所以它是免费的)使用AMI ami-c1aaabb5
You'll need to launch a new AWS Micro instance (so it's free) using the AMI ami-c1aaabb5
这个PasteBin条目具有完整的设置,可以运行以镜像我的测试环境。你只需要在最后的NginX配置中更改 example.com
This PasteBin entry has the complete set-up to run to mirror my test environment. You'll just need to change example.com within the NginX config at the end
设置完成后,您只需要创建样本我正在测试的PHP文件是
Once that's set-up you just need to create the sample PHP file which I am testing with which is
<?php
sleep(70);
die( 'Hello World' );
?>
将其保存到webroot中然后进行测试。如果您使用php或php-cgi从命令行运行脚本,它将起作用。如果您通过网页访问脚本并拖动访问日志 /var/log/nginx/example.access.log ,您会注意到在60秒后收到HTTP 1.1 499响应。
Save that into the webroot and then test. If you run the script from the command line using php or php-cgi, it will work. If you access the script via a webpage and tail the access log /var/log/nginx/example.access.log, you will notice that you receive the HTTP 1.1 499 response after 60 seconds.
现在您可以看到超时,我将对PHP和NginX进行一些配置更改以尝试解决此问题。对于PHP,我将创建几个配置文件,以便它们可以轻松禁用
Now that you can see the timeout, I'll go through some of the config changes I've made to both PHP and NginX to try to get around this. For PHP I'll create several config files so that they can be easily disabled
更新PHP FPM配置以包含外部配置文件
sudo echo '
include=/usr/local/php/php-fpm.d/*.conf
' >> /usr/local/php/etc/php-fpm.conf
创建一个新的PHP -FPM config覆盖请求超时
sudo echo '[www]
request_terminate_timeout = 120s
request_slowlog_timeout = 60s
slowlog = /var/log/php-fpm-slow.log ' >
/usr/local/php/php-fpm.d/timeouts.conf
更改一些全局设置以确保紧急重启间隔为2分钟
# Create a global tweaks
sudo echo '[global]
error_log = /var/log/php-fpm.log
emergency_restart_threshold = 10
emergency_restart_interval = 2m
process_control_timeout = 10s
' > /usr/local/php/php-fpm.d/global-tweaks.conf
接下来,我们将更改一些PHP.INI设置,再次使用单独的文件
Next, we will change some of the PHP.INI settings, again using separate files
# Log PHP Errors
sudo echo '[PHP]
log_errors = on
error_log = /var/log/php.log
' > /usr/local/php/conf.d/errors.ini
sudo echo '[PHP]
post_max_size=32M
upload_max_filesize=32M
max_execution_time = 360
default_socket_timeout = 360
mysql.connect_timeout = 360
max_input_time = 360
' > /usr/local/php/conf.d/filesize.ini
如你所见,这是将套接字超时增加到3分钟并将帮助记录错误。
As you can see, this is increasing the socket timeout to 3 minutes and will help log errors.
最后,我将编辑一些NginX设置以增加超时的那一边
Finally, I'll edit some of the NginX settings to increase the timeout's that side
首先我编辑文件 /etc/nginx/nginx.conf 并将其添加到http指令
fastcgi_read_timeout 300;
First I edit the file /etc/nginx/nginx.conf and add this to the http directive fastcgi_read_timeout 300;
接下来,我编辑我们之前创建的文件 / etc / nginx / sites-enabled / example (参见pastebin条目)并将以下设置添加到服务器指令
Next, I edit the file /etc/nginx/sites-enabled/example which we created earlier (See the pastebin entry) and add the following settings into the server directive
client_max_body_size 200;
client_header_timeout 360;
client_body_timeout 360;
fastcgi_read_timeout 360;
keepalive_timeout 360;
proxy_ignore_client_abort on;
send_timeout 360;
lingering_timeout 360;
最后,我将以下内容添加到 location~.php $ 部分服务器目录
Finally I add the following into the location ~ .php$ section of the server dir
fastcgi_read_timeout 360;
fastcgi_send_timeout 360;
fastcgi_connect_timeout 1200;
在重试脚本之前,启动nginx和php-fpm以确保选择了新设置向上。然后我尝试访问该页面,仍然在NginX example.error.log中收到HTTP / 1.1 499条目。
Before retrying the script, start both nginx and php-fpm to ensure that the new settings have been picked up. I then try accessing the page and still receive the HTTP/1.1 499 entry within the NginX example.error.log.
那么,我哪里出错了?当我将PHP的最大执行时间设置为2分钟时,这只适用于apache。
So, where am I going wrong? This just works on apache when I set PHP's max execution time to 2 minutes.
我可以看到通过运行 phpinfo()来获取PHP设置来自可通过网络访问的网页。我只是没有得到,我实际上认为已经增加了太多因为它应该只需要PHP的 max_execution_time , default_socket_timeout 以及NginX的 fastcgi_read_timeout 只在server-> location指令内。
I can see that the PHP settings have been picked up by running phpinfo() from a web-accessible page. I just don't get, I actually think that too much has been increased as it should just need PHP's max_execution_time, default_socket_timeout changed as well as NginX's fastcgi_read_timeout within just the server->location directive.
进行了一些进一步的测试以显示问题不在于客户端正在死亡我已将测试文件修改为
Having performed some further test to show that the problem is not that the client is dying I have modified the test file to be
<?php
file_put_contents('/www/log.log', 'My first data');
sleep(70);
file_put_contents('/www/log.log','The sleep has passed');
die('Hello World after sleep');
?>
如果我从网页运行脚本,那么我可以看到文件的内容被设置为第一个字符串。 60秒后,错误出现在NginX日志中。 10秒后,文件内容变为第二个字符串,证明PHP正在完成该过程。
If I run the script from a web page then I can see the content of the file be set to the first string. 60 seconds later the error appears in the NginX log. 10 seconds later the contents of the file changes to the 2nd string, proving that PHP is completing the process.
设置 fastcgi_ignore_client_abort on; 确实将响应从HTTP 499更改为HTTP 200,但仍然没有任何内容返回给最终客户端。
Setting fastcgi_ignore_client_abort on; does change the response from a HTTP 499 to a HTTP 200 though nothing is still returned to the end client.
将Apache和PHP(5.3.10)直接安装到盒子上(使用apt)然后增加执行时间似乎也会发生问题在Apache上也是如此。现在的症状与NginX相同,HTTP200响应但实际客户端连接超时。
Having installed Apache and PHP (5.3.10) onto the box straight (using apt) and then increasing the execution time the problem does appear to also happen on Apache as well. The symptoms are the same as NginX now, a HTTP200 response but the actual client connection times out before hand.
我也开始注意到,在NginX日志中,如果我使用Firefox进行测试,它会发出双重请求(例如 PHP脚本在超过60秒时执行两次)。虽然这看起来似乎是请求脚本失败的客户端
I've also started to notice, in the NginX logs, that if I test using Firefox, it makes a double request (like this PHP script executes twice when longer than 60 seconds). Though that does appear to be the client requesting upon the script failing
问题的原因是AWS上的Elastic Load Balancers 。默认情况下,它们会在60秒不活动后超时,这是造成问题的原因。
The cause of the problem is the Elastic Load Balancers on AWS. They, by default, timeout after 60 seconds of inactivity which is what was causing the problem.
所以它不是NginX,PHP-FPM或PHP而是负载均衡器。
So it wasn't NginX, PHP-FPM or PHP but the load balancer.
要解决此问题,只需进入ELB描述选项卡,滚动到底部,然后单击(编辑)旁边的值空闲超时:60秒
To fix this, simply go into the ELB "Description" tab, scroll to the bottom, and click the "(Edit)" link beside the value that says "Idle Timeout: 60 seconds"