高负载下的 502 网关错误 (nginx/php-fpm)

Posted

技术标签:

【中文标题】高负载下的 502 网关错误 (nginx/php-fpm)【英文标题】:502 Gateway Errors under High Load (nginx/php-fpm) 【发布时间】:2012-02-05 00:28:04 【问题描述】:

我在一个相当繁忙的互联网站点工作,该站点经常会出现非常大的流量高峰。在这些高峰期间,每秒请求数百页,这会产生随机的 502 网关错误。

现在我们在具有 4 个 SAS 15k 驱动器 (raid10) 的机器上运行 nginx (1.0.10) 和 php-FPM,该驱动器具有 16 核 CPU 和 24GB DDR3 内存。我们还使用最新的 Xcache 版本。数据库位于另一台机器上,但是这台机器的负载非常低,没有问题。

在正常负载下,一切运行完美,系统负载低于 1,PHP-FPM 状态报告从未真正同时显示超过 10 个活动进程。始终有大约 10GB 的内存可用。在正常负载下,机器每秒处理大约 100 次浏览量。

当出现巨大的流量高峰时,问题就出现了,并且每秒数百次从机器请求页面浏览量。我注意到 FPM 的状态报告会显示多达 50 个活动进程,但这仍然远低于我们配置的 300 个最大连接数。在这些高峰期间,Nginx 状态报告多达 5000 个活动连接,而不是正常的平均 1000 个。

操作系统信息:CentOS 5.7 版(最终版)

CPU:Intel(R) Xeon(R) CPU E5620 @ 2.40GH(16 核)

php-fpm.conf

daemonize = yes
listen = /tmp/fpm.sock
pm = static
pm.max_children = 300
pm.max_requests = 1000

我没有设置 rlimit_files,因为据我所知,如果你不这样做,它应该使用系统默认值。

fastcgi_params(仅向标准文件添加值)

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

fastcgi_pass            unix:/tmp/fpm.sock;

nginx.conf

worker_processes        8;
worker_connections      16384;
sendfile                on;
tcp_nopush              on;
keepalive_timeout       4;

Nginx 通过 Unix Socket 连接到 FPM。

sysctl.conf

net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 1
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.eth0.rp_filter=1
net.ipv4.conf.lo.rp_filter=1
net.ipv4.ip_conntrack_max = 100000

limits.conf

* soft nofile 65536
* hard nofile 65536

这些是以下命令的结果:

ulimit -n
65536

ulimit -Sn
65536

ulimit -Hn
65536

cat /proc/sys/fs/file-max
2390143

问题:如果 PHP-FPM 没有耗尽连接,负载仍然很低,并且有足够的 RAM 可用,那么在高流量期间可能会导致这些随机 502 网关错误的瓶颈是什么?

注意:默认情况下,这台机器的 ulimit 是 1024,因为我将它更改为 65536,所以我没有完全重启机器,因为它是生产机器,这意味着停机时间太长。

【问题讨论】:

也许还有别的东西在旁边运行? osbmedia.com/blog/view/php-fpm-nginx-502-gateway nginx 本身可能是瓶颈。跟踪 IO 也是如此,不仅是加载。而且我认为这更多的是服务器故障,我是编码人员而不是系统管理员。 我也运行了 xcache。 256MB 专用于 Xcache,但从未全部使用。 可能您使用 nginx 提供动态内容,这是已知问题。 nginx 处理静态内容非常好,但对于动态内容,最好使用另一台服务器和 nginx 作为透明代理服务器。例如:apache(动态内容)+nginx(作为透明代理(静态内容))在这种情况下,您的服务器应该能够处理难以置信的负载。我知道对于这种规模的系统来说这是一个巨大的变化,但是你可以在另一台服务器上尝试这样的配置,然后比较 ab 测试来获得差异。 获取 nginx access.log 和 php-fpm 的慢日志样本会很有趣。你的服务器看起来很有能力,但这也是一个假设,因为我不知道你的服务器是什么样的应用程序。仅通过选择的框架,您就可以削弱性能。 【参考方案1】:

这应该可以解决它...

你有: fastcgi_buffers 4 256k;

将其更改为: fastcgi_buffers 256 16k; // 总共 4096k

同时设置 fastcgi_max_temp_file_size 0,这将在回复开始超过您的 fastcgi 缓冲区时禁用缓冲到磁盘。

【讨论】:

我也有同样的问题,唯一不同的是我用的是nodejs。 @Timothy 你能解释一下你的建议吗?【参考方案2】:

如果在某些情况下没有帮助 - 使用普通端口绑定而不是套接字,因为 300+ 上的套接字可以阻止新请求,迫使 nginx 显示 502。

【讨论】:

【参考方案3】:

Unix 套接字默认接受 128 个连接。把这行放到/etc/sysctl.conf里面就好了

net.core.somaxconn = 4096

【讨论】:

【参考方案4】:

@Mr.恩惠

我有 8 核 14 GB 内存。但是系统经常让网关超时。 实施以下修复也没有解决问题。仍在寻找更好的修复方法。

你有:fastcgi_buffers 4 256k;

改成:

fastcgi_buffers 256 16k; // 总共 4096k

同时设置 fastcgi_max_temp_file_size 0, 如果回复开始超出您的 fastcgi 缓冲区,则将禁用缓冲到磁盘。

谢谢。

【讨论】:

你使用 php 7.0 FPM 吗? @RobbNesp 我正在使用 PHP 7.0 FPM fastcgi_buffers 256 16k;fastcgi_max_temp_file_size 0 是否应该使用它?

以上是关于高负载下的 502 网关错误 (nginx/php-fpm)的主要内容,如果未能解决你的问题,请参考以下文章

远程服务器返回错误:(502)错误的网关 是啥原因、?

Ubuntu 16.04、nginx、phpmyadmin - 502 错误网关

nginx + php5-fpm 中的错误 502

为啥从亚马逊弹性负载均衡器后面发送重定向时收到 502 错误网关?

nginx+php测试时显示 502 bad gateway的解决方法

CloudFront 无法与 ELB 502 错误网关通信