Nginx 与 PHP FPM - 资源暂时不可用 - 502 错误

Nginx 与 PHP FPM - 资源暂时不可用 - 502 错误

Nginx 与 PHP FPM - 资源暂时不可用 - 502 错误

我正在使用一些代码发送超过 160 个 GET 请求 异步使用 curl到我的 API,该 API 在 Ubuntu 服务器 16.04 上运行带有 Php-fpm 的 Nginx。每个请求都会从数据库中提取不同的数据选择,然后将其作为 JSON 响应返回。这个请求数足够小,我认为它不应该达到各种默认限制(套接字连接数、文件描述符等)。然而,它们同时发送/接收的事实似乎导致了问题。

绝大多数请求都会成功,但有几个(在连续的测试中始终是相同的数量,但根据配置而有所不同)会得到“502 Bad Gateway”响应。

如果我查看 nginx 错误日志(/var/log/nginx/error.log),我会看到以下错误消息:

2017/11/21 09:46:43 [error] 29#29: *144 connect() to unix:/run/php/php7.0-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 192.168.3.7, server: , request: "GET /1.0/xxx HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "my.domain.org"

总是有确切地日志中的“502 Bad Gateway”错误消息的数量与我从 API 收到的数量相同。

同时,在执行测试期间查看 fpm 日志文件时(使用tail -100f /var/log/php7.0-fpm.log),什么也没有发生。它只有以下内容:

[21-Nov-2017 11:54:29] NOTICE: fpm is running, pid 329
[21-Nov-2017 11:54:29] NOTICE: ready to handle connections
[21-Nov-2017 11:54:29] NOTICE: systemd monitor interval set to 10000ms

虽然我的 fpm 配置(在/etc/php/7.0/fpm/php-fpm.conf)用 指定了错误日志error_log = /var/log/php7.0-fpm.log,但似乎没有这样的文件,表明没有错误。

工作配置

我发现,如果我调整 fpm 配置,并且我将文件配置/etc/php/7.0/fpm/pool.d/www.conf为使用static多个15线程而不是动态生成进程或使用较少数量的静态进程,我就可以让 Web 服务器正常工作(没有 502 错误)。

pm = static
pm.max_children = 15

我相信这是可行的,因为已经有足够的线程准备好应对突然的打击,并且不会因生成或关闭线程而产生延迟。但是,这确实意味着我的网络服务器将使用比我希望的更多的内存。理想情况下,我希望该pm.max_children数字等于服务器上 vCPU 数量的 2 倍(即 8 个或更少)。在这种情况下,我使用的是四核服务器,但希望可以扩展向下到双核实例。理想情况下,我希望服务器能够回答全部即使总时间很长,也要及时处理请求,例如排队和调整超时。

配置设置

默认的 php-fpmlisten.backlog值是511,但我将其设置为 2000,只是为了消除它的影响。 listen.backlog = 2000

对于 Nginx,我设置了 1024 worker_connectionsworker_processes auto;所以应该是 4。

我还有以下缓冲区和超时设置,以尝试防止它们成为一个因素:

##
# Buffere settings
##
client_body_buffer_size 10M;
client_header_buffer_size 1k;
client_max_body_size 512m;
large_client_header_buffers 2 1k;


##
# Timeout settings
##
client_body_timeout 120;
client_header_timeout 120;
keepalive_timeout 120;
send_timeout 120;
fastcgi_connect_timeout 60s;
fastcgi_next_upstream_timeout 40s;
fastcgi_next_upstream_tries 10;
fastcgi_read_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_cache_lock_timeout 60s;

值得注意的是,我们在大约 20 秒内收到了所有请求(包括 502),因此我们并没有达到这些要求。此外,即使fastcgi_next_upstream_tries设置为 10,对于每个 502 错误消息,我只会收到 1 条资源不可用消息,而不是 10 次尝试应该尝试的 10 倍。

类似/相关问题

我发现 serverfault 和 stack overflow 上有很多类似的问题。我在这里详细介绍这些问题,这样这个问题就不会被标记为重复。

您可以看到它与 nginx 提供的错误消息中的套接字文件一致。

问题

相信Nginx 速度太快,PHP-fpm 端无法处理。有时 fpm 无法响应 nginx 请求,因此 Nginx 放弃​​并返回 502 错误。有没有办法(可能是一两个配置变量)来修复此问题,以便 fpm 将请求排队,或者让 nginx 稍后重试(fastcgi_next_upstream_tries似乎没有任何效果)?我不介意长的它需要 Web 服务器来处理所有请求(增加超时),只需将我的 fpm 进程数设置为相对于我的 CPU 的适当数字,所有这 160 个请求都将得到处理。

更新-使用 TCP 套接字工作正常

我刚刚尝试将 FPM 从监听 unix 文件套接字切换到 TCP 套接字,详情如下这里

例如将 fpm 更改为:Listen 127.0.0.1:9000并更新 nginx 以使用: fastcgi_pass 127.0.0.1:9000;

这似乎已经解决了问题。例如,即使我使用动态池或仅具有 2 个 fpm 线程的静态池,也不会收到任何 502 错误。

但是,我很想知道为什么这样做会有效,而不是使用本地 unix 文件套接字,以及是否只需进行配置更改即可使基于文件套接字的解决方案起作用,因为这是默认设置,并且许多人可能会使用它。

答案1

我相信你可以使用ngx_http_limit_req_module为了实现这一点,将数字配置为所需的 r/s 并使用 burst 设置队列大小,配置类似于:

limit_req_zone $binary_remote_addr zone=php:10m rate=2r/s;

server {
    location ~ \.php$ {
        limit_req zone=php burst=10;
    }

此示例将平均每秒允许 2 个请求,并将第三到第十个请求(如果有)排队。如果 r/sa 超过 10,503将返回错误(limit_req_status

答案2

转到您的 php-fpm 配置并添加 listen.backlog = 5000 注意硬限制是 65536

另外,确保它也受系统级检查支持,例如 sysctl net.core.somaxconn 如果它小于 5000,则执行 echo "net.core.somaxconn=10000" >> /etc/sysctl.conf sysctl -p

更多信息请点击这里: https://easyengine.io/tutorials/php/fpm-sysctl-tweaking/

相关内容