戴上你的老花镜——这将是一副很长的眼镜。
首先,我要做什么。我正在为一些特别慢的 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“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
答案1
我在邮件列表中报告了这个问题。它最终被认定为 php 中的一个错误,现已在 git 中得到解决,应该会出现在下一个 php 版本中,w00t!
如果有人感兴趣的话:https://groups.google.com/forum/#!topic/highload-php-en/qGu3Eaifj9s