![Nginx 上的 PHP5-FPM 崩溃 Zend/zend_language_scanner.c:没有此文件或目录](https://linux22.com/image/694088/Nginx%20%E4%B8%8A%E7%9A%84%20PHP5-FPM%20%E5%B4%A9%E6%BA%83%20Zend%2Fzend_language_scanner.c%EF%BC%9A%E6%B2%A1%E6%9C%89%E6%AD%A4%E6%96%87%E4%BB%B6%E6%88%96%E7%9B%AE%E5%BD%95.png)
我们当前的配置:
- Debian 8.6
- Nginx Web 服务器
- PHP5-FPM v5.6.27-0+deb8u1
- Zend Engine v2.6.0 和 Zend OPcache v7.0.6-dev
我们用Phalcon框架 v2.0.11(在测试环境中,我们遇到了同样的错误,v2.0.13 也是如此)。为了正常工作,Phalcon 需要进行编译,然后它将成为 PHP 预加载模块 (phalcon.so)。在编译过程中,它会调用 Zend 库等。
我们还使用Memcached(作为服务和 PHP 模块)。
除了 Nginx 随机抛出以下错误外,应用程序运行正常:
502 Bad Gateway
导航过程中出现错误。重新加载页面 (F5) 或按“后退”浏览器按钮,页面将加载,不会出现任何错误。
有时,502 错误比其他时候更频繁,似乎与服务器的负载或流量无关。
我们从日志中读到的唯一错误根本不具有说服力:
php5-fpm.log:
WARNING: [pool www] child 2183 exited on signal 7 (SIGBUS) after 0.120012 seconds from start
WARNING: [pool www] child 1391 exited on signal 7 (SIGBUS) after 59.871442 seconds from start
WARNING: [pool www] child 12836 exited on signal 7 (SIGBUS - core dumped) after 560.364868 seconds from start
WARNING: [pool www] child 10874 exited on signal 7 (SIGBUS - core dumped) after 38.964131 seconds from start
...
...
nginx/错误日志:
[error] 8428#0: *368771 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: xxx.xxx.xxx.xxx, server: xxxxxx.xxxxxxxxx.xxx, request: "POST /abc/def_ghi HTTP/1.1", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "xxxxxx.xxxxxxxxx.xxx", referrer: "https://xxxxxx.xxxxxxxxx.xxx/abc"
...
...
经过几天的研究,我们尝试应用了在互联网上找到的所有建议。我们在 Nginx 和 php-fpm 上修改、测试和检查的参数包括:
(on php.ini)
output_buffering
max_execution_time
memory_limit
(on www.conf)
listen = /var/run/php5-fpm.sock or listen = 127.0.0.1:9000
pm = ondemand/static/etc.....
pm.max_children 500/30/1/100/etc....
pm.start_servers = 30/50/1/etc......
pm.min_spare_servers
pm.max_spare_servers
pm.max_requests
(on nginx virtual server conf file)
fastcgi_pass
fastcgi_buffers
fastcgi_buffer_size
fastcgi_connect_timeout
fastcgi_send_timeout
fastcgi_read_timeout
上述参数的任何值组合都不会改变“502”错误的行为。它们有时会持续出现。
因此,我们尝试使用 GDB 在进程崩溃时转储 PHP 的核心。我们发现每次抛出 502 错误时,我们总是收到相同的转储(我的意思是,带有相同的错误)。这是一个转储示例:
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/sbin/php5-fpm...Reading symbols from /usr/lib/debug/.build-id/d4/62618919aec6e5b126ad219b9d08046ef6b875.debug...done.
done.
[New LWP 17814]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `php-fpm: pool www '.
Program terminated with signal SIGBUS, Bus error.
#0 lex_scan (zendlval=zendlval@entry=0x7fff14a7b0b8) at Zend/zend_language_scanner.c:1082
1082 Zend/zend_language_scanner.c: no such file or directory.
错误是这样的:
#0 lex_scan (zendlval=zendlval@entry=0x7fff14a7b0b8) at Zend/zend_language_scanner.c:1082
1082 Zend/zend_language_scanner.c: no such file or directory.
如果我们在互联网上搜索此错误,我们会发现几乎什么也找不到。
在升级 PHP(从 PHP 5.6.24 到 5.6.27)后,我们尝试重新编译 Phalcon,但错误仍然出现。
说实话,我们不明白我们还能做些什么来解释这个错误并了解如何最终解决它。
感谢您的帮助。
答案1
问题已解决。这是由框架 (Phalcon) 中用于构建视图 (Volt Template Engine) 的组件引起的。
经过我们进行的所有测试,我们发现问题与将选项 compileAlways 设置为 true 的 Volt 有关。
https://github.com/phalcon/cphalcon/issues/1949
https://github.com/phalcon/cphalcon/issues/11507
我们注意到,如果将 PHP-FPM 的选项 pm.max_children 配置为大于 1(这意味着 PHP-FPM 可以同时满足更多请求),则“502”(Zend/zend_language_scanner.c 错误)可以验证。但是,设置选项 pm.max_children = 1(因此 PHP-FPM 一次最多处理 1 个请求)显然可以防止出现 502 错误。
在网上搜索了一番之后,我们发现了上面链接的两个错误。将 Volt 设置为 compileAlways=false(pm.max_children > 1)实际上解决了这个问题。
因此看起来 Volt 无法在并发请求时编译相同的模板。
在生产环境中将 compileAlways 保持为 true 当然是一个粗心的错误。现在该选项为 false,一切正常。