php-fpm + 持久套接字 = 502 错误网关

php-fpm + 持久套接字 = 502 错误网关

戴上你的老花镜——这将是一副很长的眼镜。

首先,我要做什么。我正在为一些特别慢的 tcp 设备构建一个 web 应用程序界面。打开一个套接字需要 200 毫秒,而 fwrite/fread 循环又需要 300 毫秒。为了减少每个请求上这两个操作的需要,我打开了一个持久的 tcp 套接字,这将响应时间缩短了上述的 200 毫秒。我希望 PHP-FPM 能够在来自不同客户端的请求之间共享持久连接(事实上它确实做到了!),但有些问题我上网、阅读日志和修改设置两天后仍无法解决。不过我已经将范围缩小了一些。

设置:

  • Linode 上的 Ubuntu 13.04 x64 服务器(已全面更新)
  • PHP 5.5.0-6~raring+1 (fpm-fcgi)
  • nginx/1.5.2

相关配置:

nginx

  • 工作进程 4;

php-fpm/pool.d

  • pm = 动态
  • pm.max_children = 2
  • pm.start_servers = 2
  • pm.min_spare_servers = 2

让我们从粗到细地了解一下发生了什么。 重新启动后,我有 4 个 nginx 进程和 2 个 php5-fpm 进程等待处理请求。 然后我每隔几秒钟向脚本发送一次请求。 第一个需要一段时间才能打开套接字连接并在大约 500 毫秒内返回数据,第二个在 300 毫秒内返回数据(是的,它重新使用了套接字),第三个也在大约 300 毫秒内成功,第四个请求 = 502 Bad Gateway,第五个也是一样。 第六个请求再次返回数据,只是现在又花了 500 毫秒。 该过程重复几个周期,之后每 4 个请求会导致 2x 502 Bad Gateways 和 2x 500ms 数据响应。

如果我将所有 fpm 池值加倍,并运行 4x php-fpm 进程,则循环将稳定下来,4x 成功的 500ms 响应后跟 4x Bad Gateway 错误。如果我不使用持久套接字,这个问题就会消失,但每个请求都是 500ms。我怀疑发生的事情是持久套接字使每个 php-fpm 进程不会空闲并将其绑定,因此下一个进程会被选中,直到没有剩余进程,并且当它们出错时,也许它们会重新启动并在下一个循环中可用,但套接字会随着进程死亡。我还没有检查“slowlog”,但 nginx 错误日志显示了很多这样的信息:

*188 recv() 读取上游响应头时失败(104:对端重置连接),客户端:…

互联网上关于修复 nginx/php-fpm/502 bad gateway 的所有建议都与高负载或 fcgi_pass 配置错误有关。但这里不是这种情况。增加缓冲区/大小、更改超时、将 fcgi_pass 从 unix 套接字切换到 tcp 套接字、增加系统的连接限制……这些都不适用于这里。

我曾成功设置 pm = ondemand 而不是 dynamic,但一旦初始 fpm 进程在空闲后被终止,所有后续 php-fpm 生成的持久套接字都会消失。对于 php 脚本,我使用带有 STREAM_CLIENT_PERSISTENT 标志的 stream_socket_client()。while/stream_select() 循环检测套接字数据,并使用 fread($sock, 4096) 获取数据。我显然不会调用 fclose()。

如果有人对如何在不绑定 php-fpm 进程(超出请求完成范围)的情况下获取持久套接字有其他问题或建议,或者可能有其他尝试,我将不胜感激。

一些有用的链接:

Nginx + php-fpm-recv() 错误

Nginx + php-fpm“504 网关超时”错误,几乎为零负载(在测试服务器上)

Nginx + PHP-FPM“错误 104 对等方重置连接”导致偶尔出现重复帖子

http://www.linuxquestions.org/questions/programming-9/php-pfsockopen-552084/

https://stackoverflow.com/questions/14268018/concurrent-use-of-a-persistent-php-socket

http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/#Heading3

https://stackoverflow.com/questions/242316/how-to-keep-a-php-stream-socket-alive

http://php.net/manual/en/install.fpm.configuration.php

https://www.google.com/search?q=recv%28%29+failed+%28104:+Connection+reset+by+peer%29+while+reading+response+header+from+upstream+%22502%22&ei=mC1XUrm7F4WQyAHbv4H4AQ&start=10&sa=N&biw=1920&bih=953&dpr=1

答案1

我在邮件列表中报告了这个问题。它最终被认定为 php 中的一个错误,现已在 git 中得到解决,应该会出现在下一个 php 版本中,w00t!

如果有人感兴趣的话:https://groups.google.com/forum/#!topic/highload-php-en/qGu3Eaifj9s

相关内容