某個子站是php寫的,訪問的時候nginx時不時會冒出現502錯誤,高峰時更頻繁,檢查php-fpm的日志發現大量的 child exited on signal 7 (SIGBUS),並且和accesslog裡的502時間完全吻合,排除了php進程過載的可能,然後又排除了apc的嫌疑。
既然php進程是收到信號後死亡的,那麼嘗試抓些coredump來分析吧:
先設置一下coredump的保存路徑,注意要空間夠大的地方,因為coredump可能會較多而且很大(比如開了apc設置了1G,那就會有1G):
#echo "/tmp/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern
然後修改下ulimit,允許coredump:
#ulimit -c unlimited
重啟php-fpm。 要不了多久,/tmp/目錄裡就產生了一堆coredump文件,很好,打包拖回線下來分析吧。 記得關閉coredump,並重啟程序:
#ulimit -c 0
分析coredump一般用gdb就夠了,(二進制發行版的話,先安裝對應的debug symbol包):
gdb /usr/local/php/sbin/php-fpm core.php-fpm.10375.php.1365314990
執行下bt命令,看下backtrace(具體的信息忘記記錄了),發現是掛在lex_scan函數,看了好幾個coredump,基本都是掛在lex階段的函數。
我對php源碼沒什麼研究,上google搜一下“php sigbus lex_scan”,前兩名的連接基本就給出了答案:
2010年報的bug,一直沒有close,因為看起來這並不是php的bug,仔細看,裡面有重現的范例,最後也有人找到了規避辦法。
此君經歷了和我一樣的分析過程,並且給出了明確的原因和解決辦法。
簡單說lex_scan是在對php文件進行語法分析,這個時候正好一個包含的php文件被改寫,於是悲劇發生。
為了證實,我用strace跟蹤php進程的執行,最後終於抓到了:
11670 lstat("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
11670 stat("/home/www/cache/default.php", {st_mode=S_IFREG|0644, st_size=68579, ...}) = 0
11670 --- SIGBUS (Bus error) @ 0 (0)
來源:http://blog.druggo.org/post/2013/05/02/%E4%B8%80%E4%BE%8Bphp%E8%BF%9B%E7%A8%8B%E7%9A%84SIGBUS%E6%95%85%E9%9A%9C