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

Pro*_*ter 5 nginx php-fpm

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

\n\n

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

\n\n

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

\n\n

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

\n\n
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"\n
Run Code Online (Sandbox Code Playgroud)\n\n

日志中“502 Bad Gateway”错误消息的数量始终与我从 API 收到的消息数量完全相同。

\n\n

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

\n\n
[21-Nov-2017 11:54:29] NOTICE: fpm is running, pid 329\n[21-Nov-2017 11:54:29] NOTICE: ready to handle connections\n[21-Nov-2017 11:54:29] NOTICE: systemd monitor interval set to 10000ms\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

工作配置

\n\n

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

\n\n
pm = static\npm.max_children = 15\n
Run Code Online (Sandbox Code Playgroud)\n\n

我相信这是可行的,因为已经有足够的线程准备好承受突然的打击,并且不会因产生或关闭线程而产生延迟。\n但是,这确实意味着我的网络服务器将使用比我应该喜欢。理想情况下,我希望该pm.max_children数字等于服务器上 vCPU 数量的 2 倍(即 8 个或更少)。\n在本例中,我使用的是四核服务器,但希望可能缩小双核服务器理想情况下,我希望服务器及时答复所有请求,即使所花费的总时间要长得多,例如队列和调整超时。

\n\n

配置设置

\n\n

默认的 php-fpmlisten.backlog值为511,但我将其设置为 2000 只是为了消除它成为一个因素。\n\nlisten.backlog = 2000\n

\n\n

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

\n\n

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

\n\n
##\n# Buffere settings\n##\nclient_body_buffer_size 10M;\nclient_header_buffer_size 1k;\nclient_max_body_size 512m;\nlarge_client_header_buffers 2 1k;\n\n\n##\n# Timeout settings\n##\nclient_body_timeout 120;\nclient_header_timeout 120;\nkeepalive_timeout 120;\nsend_timeout 120;\nfastcgi_connect_timeout 60s;\nfastcgi_next_upstream_timeout 40s;\nfastcgi_next_upstream_tries 10;\nfastcgi_read_timeout 60s;\nfastcgi_send_timeout 60s;\nfastcgi_cache_lock_timeout 60s;\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

类似/相关问题

\n\n

我看到关于服务器故障和堆栈溢出有很多类似的问题。我在这里详细介绍了它们,这样这个问题就不会被标记为重复。

\n\n\n\n

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

\n\n\n\n

问题

\n\n

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

\n\n

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

\n\n

我刚刚尝试将 FPM 从监听 unix 文件套接字交换为 TCP 套接字,详细信息请参见此处

\n\n

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

\n\n

作为一种解决方法,这似乎已经达到了目的。例如,即使我使用动态池甚至只有 2 个 fpm 线程的静态池,我也不会收到任何 502 错误。

\n\n

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

\n

小智 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;
    }
Run Code Online (Sandbox Code Playgroud)

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


归档时间:

查看次数:

11572 次

最近记录:

3 年,6 月 前