分析php core dump的原因

  • 发现问题

最近发现服务器频繁出现core.xxx文件,并且php-fpm.log有类似这样的记录

WARNING: [pool www] child 2930 exited on signal 7 (SIGBUS - core dumped) after 22458.193927 seconds from start

说明有php-fpm进程异常退出了,业务侧的表现就是某些功能第1次打开异常(如显示空白),再点击又正常,这种现象的原因该php-fpm进程异常退出了。

  • 分析问题的的原因

最直接的办法就是用gdb工具对core.xxx进行分析了。

gdb /usr/local/php56/sbin/php-fpm -c /tmp/core.4522

输入命令bt,会列出退出前的堆栈信息,如

#0  lex_scan (zendlval=zendlval@entry=0x7ffc0ef65bb8) at Zend/zend_language_scanner.c:1082
#1  0x0000000000705642 in zendlex (zendlval=zendlval@entry=0x7ffc0ef65bb0) at /usr/local/src/php-5.6.32/Zend/zend_compile.c:6919
#2  0x00000000006e0256 in zendparse () at /usr/local/src/php-5.6.32/Zend/zend_language_parser.c:3732
#3  0x00000000006e5a08 in compile_file (file_handle=<optimized out>, type=2) at Zend/zend_language_scanner.l:586
#4  0x00000000005ab802 in phar_compile_file (file_handle=<optimized out>, type=<optimized out>) at /usr/local/src/php-5.6.32/ext/phar/phar.c:3370
#5  0x00007fb2962aebb4 in compile_and_cache_file (file_handle=file_handle@entry=0x7ffc0ef682f0, type=type@entry=2, 
    key=key@entry=0x7fb2964cbafc <accel_globals+380> "/webroot:./Application/Runtime/Cache/VendorApi/48b1f9c30fb6cceae8315a38de289ddd.php:/webroot/ThinkPHP/Library/Think/Storage/Driver:A", key_length=166, op_array_p=op_array_p@entry=0x7ffc0ef681e0, 

可以看到最开始一条记录,是函数lex_scan异常退出了,lex是属于词法分析的zend方法,往下看也可以发现业务侧的代码,如/webroot:./Application/Runtime/Cache/VendorApi/48b1f9c30fb6cceae8315a38de289ddd.php,根据上述代码可以知道是分析这个文件时出错了,打开这个文件看看是什么内容:

<?php if (!defined('THINK_PATH')) exit();?><?xml version="1.0" encoding="utf-8"?>
<response>
    <state>
        <code><?php echo ($result["code"]); ?></code>
        <message><?php echo ($result["message"]); ?></message>
    </state>
</response>

嗯,一个thinkphp的xml模板文件,看到这个文件基本可以定位原因了,是由<?xml version="1.0" encoding="utf-8"?>这个标签php无法正确进行语法解析, 进而导致php-fpm整个进程退出了。剩下的解决办法就好处理了,结合业务侧把<?xml version="1.0" encoding="utf-8"?>先从模板里删除,或移动到其它地方再输出。更新代码后,删除此目录下的缓存文件Application/Runtime/Cache/VendorApi/让thinkphp重新生成。

上面的分析方法,因为有业务侧的代码显现,还比较容易定位问题,否则就要借助php提供的.gdbinit脚本了,它能将更高层的业务跟踪代码显示出来,.gdbinit文件的位置一般是在/usr/local/src/php-5.6.30/.gdbinit目录下(php后的版本号根据你的环境修改,或者通过find方法搜索,或在这下载https://github.com/php/php-src/blob/master/.gdbinit)。 仍停留在上面的gdb交互环境里,执行命令source /usr/local/src/php-5.6.30/.gdbinit,再执行命令zbacktrace,则会打印更多业务侧的代码,如下

(gdb) source /usr/local/src/php-5.6.30/.gdbinit
(gdb) zbacktrace
[0x7fb2a45a4a38] load() /webroot/ThinkPHP/Library/Think/Storage/Driver/File.class.php:80 
[0x7ffc0ef68560] Think\Storage\Driver\File->load("./Application/Runtime/Cache/VendorApi/48b1f9c30fb6cceae8315a38de289ddd.php", array(1)[0x32adaf8], NULL, "tpl") 
[0x7fb2a45a4900] call_user_func_array(array(2)[0x32c7e28], array(4)[0x32c7c60]) /webroot/ThinkPHP/Library/Think/Storage.class.php:37 
[0x7ffc0ef68860] Think\Storage::__callstatic("load", array(4)[0x32c7dc8]) 
[0x7fb2a45a4798] Think\Storage::load("./Application/Runtime/Cache/VendorApi/48b1f9c30fb6cceae8315a38de289ddd.php", array(1)[0x32adaf8], NULL, "tpl") /webroot/ThinkPHP/Library/Think/Template.class.php:77 
[0x7fb2a45a4620] Think\Template->fetch("./Application/VendorApi/View/Lvmama/push_product_change_info.html", array(1)[0x32adaf8], "") /webroot/Application/Runtime/common~runtime.php:1 
[0x7fb2a45a44c8] Behavior\ParseTemplateBehavior->run(array(4)[0x32aebf8]) /webroot/Application/Runtime/common~runtime.php:1 

也可以发现php-fpm是在处理./Application/Runtime/Cache/VendorApi/48b1f9c30fb6cceae8315a38de289ddd.php后失败就结束了。

观察一段时间后没再出现core dump,到此,问题得到解决。

如果要调用运行中的进程,可以gdb --pid=xxxgdb -p xxx

参考:

@author:[email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章