我正在使用一些代码使用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),我会看到以下错误消息:
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"\nRun Code Online (Sandbox Code Playgroud)\n\n日志中“502 Bad Gateway”错误消息的数量始终与我从 API 收到的消息数量完全相同。
\n\n同时,在执行测试期间查看 fpm 日志文件(使用tail -100f /var/log/php7.0-fpm.log)时,没有任何反应。它只有以下内容:
[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\nRun Code Online (Sandbox Code Playgroud)\n\n虽然我的 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线程而不是动态生成进程或使用较少数量的静态进程,则可以让网络服务器正常工作(没有 502 错误)。
pm = static\npm.max_children = 15\nRun Code Online (Sandbox Code Playgroud)\n\n我相信这是可行的,因为已经有足够的线程准备好承受突然的打击,并且不会因产生或关闭线程而产生延迟。\n但是,这确实意味着我的网络服务器将使用比我应该喜欢。理想情况下,我希望该pm.max_children数字等于服务器上 vCPU 数量的 2 倍(即 8 个或更少)。\n在本例中,我使用的是四核服务器,但希望可能缩小到双核服务器理想情况下,我希望服务器及时答复所有请求,即使所花费的总时间要长得多,例如队列和调整超时。
默认的 php-fpmlisten.backlog值为511,但我将其设置为 2000 只是为了消除它成为一个因素。\n\nlisten.backlog = 2000\n
对于 Nginx,我设置了 1024worker_connections和worker_processes auto;,所以应该是 4。
我还有以下缓冲区和超时设置来尝试防止它们成为一个因素:
\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;\nRun Code Online (Sandbox Code Playgroud)\n\n值得注意的是,我们在大约 20 秒内收到了所有请求(包括 502),因此我们还没有达到这些请求。另外,即使fastcgi_next_upstream_tries设置为 10,对于每条 502 错误消息,我也只收到 1 条资源不可用消息,而不是它应该尝试的 10 次尝试的 10 倍。
我看到关于服务器故障和堆栈溢出有很多类似的问题。我在这里详细介绍了它们,这样这个问题就不会被标记为重复。
\n\nServerfault - 使用 Nginx 和 PHP-FPM 时,请求永远不会在 pm.max_children 之后排队。似乎是一个非常相似的问题,但尽管它是三年前发布的,但还没有答案,而且它的细节远没有这里那么详细。另外,我的一些请求必须成功排队,这与建议一旦达到最大值所有请求都会被丢弃的问题不同。
ServerFault - 连接到上游客户端时,nginx 错误 502 且资源暂时不可用。这篇文章看起来很相似(他描述了同样的问题),但正如答案之一指出的那样,他的套接字文件不匹配,而我的是。我的/etc/php/7.0/fpm/pool.d/www.conf配置文件有:
听= /run/php/php7.0-fpm.sock
您可以在 nginx 提供的错误消息中看到它与套接字文件一致。
\n\nServerFault - 需要增加 nginx 吞吐量到上游 unix 套接字 \xe2\x80\x94 Linux 内核调整?这里的答案建议设置net.core.somaxconn,net.core.netdev_max_backlog我相应地设置为4096和1000。该问题仍然存在。
ServerFault - 连接到上游时 php-fpm.sock 失败(11:资源暂时不可用) - 这里的建议是让 pm = ondemand 并将 max_children 设置为 4000。这不适合我,因为它可能会导致我的四核服务器有 4000 个线程并且耗尽内存。
我相信Nginx 的速度太快,PHP-fpm 方面无法处理。在某些时候,fpm 不响应 nginx 请求,因此 Nginx 放弃并发回 502 错误。有没有办法(可能是一个或两个配置变量)来解决这个问题,以便 fpm 将请求排队,或者让 nginx 稍后重试(fastcgi_next_upstream_tries似乎没有任何效果)?我不介意网络服务器需要多长时间来处理所有请求(增加超时),只是我可以将我的 fpm 进程数设置为相对于我的 CPU 的适当数字,并且所有这 160 个请求都将服务。
我刚刚尝试将 FPM 从监听 unix 文件套接字交换为 TCP 套接字,详细信息请参见此处。
\n\n例如,将 fpm 更改为:Listen 127.0.0.1:9000并更新 nginx 以使用:\nfastcgi_pass 127.0.0.1:9000;
作为一种解决方法,这似乎已经达到了目的。例如,即使我使用动态池甚至只有 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 次 |
| 最近记录: |