57

上周末,我注意到我的一个中型 AWS 实例存在问题,如果请求花费超过 60 秒,Nginx 总是返回 HTTP 499 响应。被请求的页面是一个 PHP 脚本

我花了几天时间试图找到答案,并尝试了我在互联网上可以找到的所有内容,包括 Stack Overflow 上的几个条目,但没有任何效果。

我试过修改 PHP 设置、PHP-FPM 设置和 Nginx 设置。你可以看到我周五在 NginX 论坛上提出的一个问题(http://forum.nginx.org/read.php?9,237692)虽然没有收到任何回复,所以我希望我能找到一个在我被迫搬回 Apache 之前在这里回答,我知道它可以正常工作。

其他条目中报告的 HTTP 500 错误不同。

我已经能够使用 PHP 5.4.11 复制一个新的 NginX 微型 AWS 实例的问题。

为了帮助任何希望看到实际问题的人,我将带您完成我为最新的 Micro 测试服务器运行的设置。

您需要使用 AMI ami-c1aaabb5 启动一个新的 AWS Micro 实例(因此它是免费的)

这个 PasteBin 条目具有完整的设置,可以运行以镜像我的测试环境。最后你只需要在 NginX 配置中更改example.com

http://pastebin.com/WQX4AqEU

设置完成后,您只需要创建我正在测试的示例 PHP 文件,该文件是

<?php
sleep(70);
die( 'Hello World' );
?>

将其保存到 webroot 中,然后进行测试。如果您使用 php 或 php-cgi 从命令行运行脚本,它将起作用。如果您通过网页访问脚本并跟踪访问日志/var/log/nginx/example.access.log,您会注意到您在 60 秒后收到 HTTP 1.1 499 响应。

现在您可以看到超时了,​​我将通过我对 PHP 和 NginX 所做的一些配置更改来尝试解决这个问题。对于 PHP,我将创建几个配置文件,以便可以轻松禁用它们

更新 PHP FPM 配置以包含外部配置文件

sudo echo '
include=/usr/local/php/php-fpm.d/*.conf
' >> /usr/local/php/etc/php-fpm.conf

创建一个新的 PHP-FPM 配置以覆盖请求超时

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 设置,再次使用单独的文件

# 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 分钟,并有助于记录错误。

最后,我将编辑一些 NginX 设置以增加超时的那一侧

首先我编辑文件/etc/nginx/nginx.conf并将其添加到 http 指令 fastcgi_read_timeout 300;

接下来,我编辑我们之前创建的文件/etc/nginx/sites-enabled/example(请参阅 pastebin 条目)并将以下设置添加到服务器指令中

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$部分

fastcgi_read_timeout 360;
fastcgi_send_timeout 360;
fastcgi_connect_timeout 1200;

在重试脚本之前,启动 nginx 和 php-fpm 以确保新设置已被拾取。然后我尝试访问该页面,但仍然在 NginX example.error.log 中收到 HTTP/1.1 499 条目。

那么,我哪里错了?当我将 PHP 的最大执行时间设置为 2 分钟时,这仅适用于 apache。

我可以看到通过从 Web 可访问页面运行phpinfo()已获取 PHP 设置。我只是不明白,我实际上认为增加了太多,因为它应该只需要在 server->location 指令中更改 PHP 的max_execution_timedefault_socket_timeout以及 NginX 的fastcgi_read_timeout 。

更新 1

进行了一些进一步的测试以表明问题不在于客户端正在死去,我已将测试文件修改为

<?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 正在完成该过程。

更新 2

设置fastcgi_ignore_client_abort ;确实将响应从 HTTP 499 更改为 HTTP 200,但仍然没有任何内容返回给最终客户端。

更新 3

将 Apache 和 PHP (5.3.10) 直接安装到盒子上(使用 apt),然后增加执行时间,问题似乎也发生在 Apache 上。症状与现在的 NginX 相同,是 HTTP200 响应,但实际客户端连接提前超时。

我也开始注意到,在 NginX 日志中,如果我使用 Firefox 进行测试,它会发出双重请求(就像这个PHP 脚本在超过 60 秒时执行两次)。虽然这似乎是客户端在脚本失败时请求

4

6 回答 6

80

问题的原因是 AWS 上的弹性负载均衡器。默认情况下,它们会在 60 秒不活动后超时,这就是导致问题的原因。

所以不是 NginX、PHP-FPM 或 PHP,而是负载均衡器。

要解决此问题,只需进入 ELB“描述”选项卡,滚动到底部,然后单击“空闲超时:60 秒”值旁边的“(编辑)”链接

于 2013-03-25T17:37:28.930 回答
1

我想我会留下我的两分钱。首先,问题与 php 无关(仍然可能与 php 相关,php 总是让我感到惊讶:P)。这是肯定的。它主要是由代理到自身的服务器引起的,更具体地说是主机名/别名问题,在您的情况下,它可能是负载均衡器正在请求 nginx,而 nginx 正在回调负载均衡器并且它一直这样。

我在nginx 作为负载均衡器和 apache 作为 webserver/proxy 时遇到过类似的问题

于 2016-03-09T16:13:34.693 回答
1

实际上我在一台服务器上遇到了同样的问题,我发现在 nginx 配置更改后我没有重新启动 nginx 服务器,所以每次点击 nginx url 我都会收到 499 http 响应。nginx 重新启动后,它开始使用 http 200 响应正常工作。

于 2016-10-18T10:18:12.677 回答
0

就我而言 - nginx 正在向 AWS ALB 发送请求并获得 499 状态码的超时。

解决方案是添加这一行:

proxy_next_upstream off;

在当前版本的 nginx 中,默认值是proxy_next_upstream error timeout;- 这意味着在超时时它会尝试下一个“服务器” - 在 ALB 的情况下,它是已解析 ips 列表中的下一个 IP。

于 2021-10-18T14:18:18.887 回答
-1

您需要找到问题所在的位置。我不知道确切的答案,但让我们试着找到它。

我们这里有 3 个元素:nginx、php-fpm、php。正如你所说,apache下的相同php设置是可以的。是不是一样的设置?您是否在同一操作系统/主机/等上尝试使用 apache 而不是 nginx?

如果我们看到,那个 php 不是可疑的,那么我们有两个可疑的:nginx 和 php-fpm。

要排除 nginx:尝试在 ruby​​ 上设置相同的“系统”。请参阅https://github.com/garex/puppet-module-nginx以了解安装最简单的 ruby​​ 设置。或者使用谷歌(可能会更好)。

我的主要嫌疑人是 php-fpm。

尝试使用以下设置:

  • php-fpm 的 request_terminate_timeout
  • nginx`s fastcgi_ignore_client_abort
于 2013-03-25T14:18:58.610 回答
-3

不知道是否有其他人遇到过这个问题,但对我来说,它发生在我/在实例 url 末尾加上一个之后。这给出了499错误,只有在我删除之后/,它给了我 200 并且一切顺利。

于 2018-04-04T07:24:11.677 回答