查找导致随机 502 网关错误的 Nginx/PHP-FPM 瓶颈

查找导致随机 502 网关错误的 Nginx/PHP-FPM 瓶颈

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

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

在正常负载下,一切都运行正常,系统负载低于 1,PHP-FPM 状态报告实际上从未显示同时有超过 10 个活动进程。始终有大约 10GB 的 RAM 可用。在正常负载下,机器每秒处理大约 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。

系统配置参数

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

限制配置文件

* 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 后,我尚未完全重新启动机器,因为它是一台生产机器,这意味着太多的停机时间。

答案1

官方建议:worker_processes = CPU 核心数

worker_processes 16;

答案2

负载均衡器(例如 HAProxy 和 nginx)偶尔会出现 502 错误,通常是由于 LB 和 Web 服务器之间的中途中断导致的。

尝试通过 GDB 运行您的一个 Web 服务器或其测试副本,并查看在生成测试流量时是否看到分段错误(使用 ab 或 jMeter 或类似程序来模拟流量)。

我最近不得不解决一个非常相似的场景/问题。我已经排除了资源等导致问题的原因,因为我有相当全面的监控可以帮助我。最后我发现 502 错误来自负载均衡器后面的 Web 服务器,它向 LB 返回了无效(在本例中为空)的 HTTP 响应。

我打开一个 Web 服务器,停止了它,然后通过 gdb 重新启动它,然后浏览网站。最后,在点击几下之后,我看到了分段错误,这导致了 502 错误。我从 GDB 中获取回溯并将其作为错误提交给 PHP 团队,但对我来说唯一的解决办法是切换发行版以解决存在的 PHP 错误。

段错误导致 Web 服务器向 LB 发送无效内容,而 LB 显示 502 错误,因为就它而言,Web 服务器在“流程中途”消失。

我知道这不能直接回答你的问题,但这是一个开始寻找的地方。假设你确实看到了段错误,你可以从 GDB 获取堆栈跟踪,然后你有望反向工作并找到导致段错误的函数。

相关内容