分析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]

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