Назад | Перейти на главную страницу

Сбой PHP (segfault) под mod_fcgid, apache

Я программировал сайт, используя:

  1. Zend Framework 1.11.5 (полный MVC)
  2. PHP 5.3.6
  3. Apache 2.2.19
  4. CentOS 5.6 i686 virtuozzo на vps
  5. cPanel WHM 11.30.1 (сборка 4)
  6. Mysql 5.1.56-журнал
  7. Mysqli API 5.1.56

Проблема началась здесь https://stackoverflow.com/questions/6769515/php-programming-seg-fault. Короче говоря, php дает мне случайные ошибки сегментации.

[Wed Jul 20 17:45:34 2011] [error] mod_fcgid: process /usr/local/cpanel/cgi-sys/php5(11562) exit(communication error), get unexpected signal 11
[Wed Jul 20 17:45:34 2011] [warn] [client 190.78.208.30] (104)Connection reset by peer: mod_fcgid: error reading data from FastCGI server
[Wed Jul 20 17:45:34 2011] [error] [client 190.78.208.30] Premature end of script headers: index.php

О расширениях. Когда я компилирую php с флагом «--enable-debug», мне нужно отключить эту строку:

zend_extension="/usr/local/IonCube/ioncube_loader_lin_5.3.so"

В противном случае сервер не принимает запросы, и я получаю сообщение «Соединение с сервером было сброшено». Возможно, мне придется отключить eaccelerator по той же причине. Я до сих пор не понимаю, почему apache запускает его несколько раз, а некоторые нет:

extension="eaccelerator.so"

В любом случае, после того, как я запустил httpd, ошибки сегментации могут возникать случайным образом. Если я не компилирую php с флагом "--enable-debug", я могу ДЕТЕРМИНИСТИЧНО получить сбой php:

<?php
class Admin_DbController extends Controller_BaseController
{
    public function updateSqlDefinitionsAction()
    {
        $db = Zend_Registry::get('db'); 
        $row = $db->fetchRow("SHOW CREATE TABLE 222AFI");
    }
}
?>

НО, если я компилирую php с флагом «--enable-debug», очень сложно получить эту ошибку. Я должен добавить немного сложности, чтобы он рухнул. Мне нужно выполнить много параллельных запросов в течение нескольких секунд, чтобы получить сбой:

<?php
class Admin_DbController extends Controller_BaseController
{
    public function updateSqlDefinitionsAction()
    {
        $db = Zend_Registry::get('db');
        $tableList = $db->listTables();
        foreach ($tableList as $tableName){
            $row = $db->fetchRow("SHOW CREATE TABLE " . $db->quoteIdentifier($tableName));
            file_put_contents(
                DB_DEFINITIONS_PATH . '/' . $tableName . '.sql',
                $row['Create Table'] . ';'
            );
        }
    }
}
?>

Обратите внимание, что это тот же сценарий, но он создает DDL для всех таблиц в базе данных, а не для одной. Кажется, что если php сильно загружен (с расширениями, и я делаю много параллельных запросов), это когда я получаю php сбой.


О запуске httpd с "-X": я пробовал. Дело в том, что уже сейчас сложно вызвать сбой php с помощью --enable-debug. С параметром «-X» (который включает только один дочерний процесс) я не могу выполнять параллельные запросы. Итак, я не смог создать правильную трассировку отладки: https://bugs.php.net/bugs-generating-backtrace.php

У меня конкретный вопрос: что мне делать, чтобы получить ядро?


root@GWT4 [~]# httpd -V
Server version: Apache/2.2.19 (Unix)
Server built:   Jul 20 2011 19:18:58
Cpanel::Easy::Apache v3.4.2 rev9999
Server's Module Magic Number: 20051115:28
Server loaded:  APR 1.4.5, APR-Util 1.3.12
Compiled using: APR 1.4.5, APR-Util 1.3.12
Architecture:   32-bit
Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APACHE_MPM_DIR="server/mpm/prefork"
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=128
 -D HTTPD_ROOT="/usr/local/apache"
 -D SUEXEC_BIN="/usr/local/apache/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_LOCKFILE="logs/accept.lock"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

Получение дампа ядра требует установки "размера файла ядра" rlimit на что-то ненулевое для процесса (ов), из которого вы хотите получить дампы ядра. Учитывая, что вы используете PHP в FCGI, вам наплевать на сам Apache, это не вызывает сбоев; вы хотите иметь скрипт для запуска ulimit -c unlimited затем запустите свой сервер FCGI.

Мне нравится иметь отдельный рабочий раздел для ядер, поэтому, если они станут немного большими или непослушными, они не вызовут проблем с заполнением диска где-либо еще - установите /proc/sys/kernel/core_pattern к чему-то вроде /var/cores/%e-%p.core.

Не уверен, поможет ли это в этом случае, но я установил только одного дочернего элемента, нашел PID, а затем отладил его с помощью strace

strace -p PID

Нашел временное решение. Это некрасиво, но подходит:

публичная функция selectCmd ($ q) {

$charsFrom = array("\\a", "\\t", "\\n", "\\v", "\\f", "\\r", "\\\\", "\\0", "\\\"", "\\\'", "\\b");
$charsTo = array("\a", "\t", "\n", "\v", "\f", "\r", "\\", "\0", "\"", "\'", "\b");

exec('echo ' . escapeshellarg($q) . ' | mysql' .
    ' -h ' . escapeshellarg($this->_config['host']).
    ' -u ' . escapeshellarg($this->_config['username']).
    ' -p' . escapeshellarg($this->_config['password']).
    ' ' . escapeshellarg($this->_config['dbname']), $output);

$colNames = explode("\t", array_shift($output));
foreach ($colNames as &$colName){
    $colName = str_replace($charsFrom, $charsTo, $colName);
}
unset($colName);

$rowSet = array();
foreach ($output as $line){
    $row = array();
    $rawRow = explode("\t", $line);
    for ($i = 0; $i < count($rawRow); ++ $i){
        $row[$colNames[$i]] = str_replace($charsFrom, $charsTo, $rawRow[$i]);
    }
    $rowSet[] = $row;
}
return $rowSet;

}

Вам нужно будет заменить $ this -> _ config на реальный массив соединений.

Этот сценарий запускает любую команду SQL, которая возвращает строки. На данный момент это решение, которое я принимаю. Если кто-то захочет помочь мне проактивно, у меня все еще есть источники. Я также парень, у которого есть ошибка сегментации PHP, использующая PHPUnit с Zend (детерминированно). Я делаю все это в своей работе, у меня нет ресурсов, чтобы проверить это. Спасибо за ваше понимание.

Вы должны использовать ioncube_loader и eaccelerator? Что касается eaccelerator, их поддержка 5.3.x была в лучшем случае нестабильной, и большинство пользователей версии 5.3 полагаются на APC (который также будет лучше работать через FCGI).

Если вы должны использовать eaccelerator, выполняете ли вы «make distclean», а затем их постоянные инструкции INSTALL (дважды проверяя, что загружаемый вами phpize предназначен для версии 5.3.6, а не для каких-то остатков от предыдущей установки)? Я подозреваю, что в этом и есть весь источник ваших coredump, и что Apache вовсе не виноват.