Ошибки FastCGI и Apache 500 периодически

У меня проблема с FastCGI (mod_fastcgi). Это происходит время от времени и не приводит к полному краху сервера, всего 500 ошибок. Вот пара вещей. Сначала я использую APC, поэтому PHP контролирует свои собственные процессы, а не FastCGI. Кроме того, у меня есть webroot как:

/var/www/html

И внутри fcgi-bin:

/var/www/html/fcgi-bin

Прежде всего, вот apache error_log:

[Fri Jan 07 10:22:39 2011] [error] [client 50.16.222.82] (4)Interrupted system call: FastCGI: comm with server "/var/www/html/fcgi-bin/php.fcgi" aborted: select() failed, referer: http://www.domain.com/

Я также запускал strace в процессе 'fcgi-pm'. Вот фрагмент из следа, когда он взрывается:

21725 gettimeofday({1294420603, 14360}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6503 38*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 96595}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6154 23*C /var/www/html/fcgi-bin/php.fcgi - - 6483 28*", 16384) = 92
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 270744}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 5741 38*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 311502}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6064 32*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 365598}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6179 33*C /var/www/html/fcgi-bin/php.fcgi - - 5906 59*", 16384) = 92
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 454405}, NULL) = 0

Я заметил, что select(), кажется, остается неизменным независимо от того, однако read() изменяет свое возвращение с 46 на какое-то другое число во время бомбардировки. Кто-нибудь видел что-нибудь подобное? Может ли это быть какая-то блокировка файла?

Спасибо Бен

3 ответа

конспект

Я наблюдал то же самое поведение с Apache; похоже, что эта проблема не является специфичной для lighttpd.

В моем случае симптомы были точно такими же; Журналы доступа Apache были пересыпаны прерывистыми кодами ответов 500, и в журнале ошибок PHP не было соответствующих записей (а отчет об ошибках PHP был настроен на максимально подробный).

Я подробно описал проблему в списке рассылки Apache (поищите в архивах списков тему "Прерывистые 500 ответов в access.log без соответствующих записей в error.log").

Первопричина

Ответ 1100110 намекает на основную причину, но я предоставлю дополнительную документацию непосредственно от Apache, а также предложения по устранению проблемы.

Вот официальное слово от Apache по этому вопросу:

https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html:

Особые соображения PHP

По умолчанию процессы PHP FastCGI завершаются после обработки 500 запросов, и они могут завершиться после того, как этот модуль уже подключился к приложению и отправил следующий запрос. Когда это произойдет, будет записана ошибка, и 500 Internal Server Error будет возвращено клиенту. Такое поведение PHP можно отключить, установив для PHP_FCGI_MAX_REQUESTS значение 0, но это может стать проблемой, если приложение PHP утечки ресурсов. Кроме того, PHP_FCGI_MAX_REQUESTS может быть установлен на гораздо более высокое значение, чем значение по умолчанию, чтобы уменьшить частоту этой проблемы. FcgidMaxRequestsPerProcess может быть установлено в значение, меньшее или равное PHP_FCGI_MAX_REQUESTS для решения проблемы.

Управление дочерними процессами PHP (PHP_FCGI_CHILDREN) всегда должно быть отключено с помощью mod_fcgid, который будет направлять только один запрос за раз процессам приложения, которые он породил; таким образом, любые дочерние процессы, созданные PHP, не будут использоваться эффективно. (Кроме того, дочерние процессы PHP могут не завершаться должным образом.) По умолчанию и при установке переменной среды PHP_FCGI_CHILDREN=0 управление дочерними процессами PHP отключено.

Популярный кэш кода операции APC для PHP не может совместно использовать кэш между процессами PHP FastCGI, если PHP не управляет дочерними процессами. Таким образом, эффективность кеша ограничена mod_fcgid; параллельные запросы PHP будут использовать разные кеши кода операции.

Там у нас это есть.

Возможные решения

Опция 1

Одно из решений состоит в том, чтобы установить PHP_FCGI_MAX_REQUESTS на ноль, но принятие этой меры может привести к тому, что утечки памяти выйдут из-под контроля.

Различные фрагменты документации, с которыми я ознакомился, не дают понять, страдает ли PHP через Fast-CGI утечкой памяти (отсюда и это встроенное поведение "повторного использования процесса") или риск ограничен плохо написанным ". убегающие "скрипты.

В любом случае существует риск, связанный с установкой PHP_FCGI_MAX_REQUESTS на ноль, особенно в среде общего хостинга.

Вариант 2

Второе решение, как описано в приведенной выше выдержке, состоит в том, чтобы установить для FcgidMaxRequestsPerProcess значение, меньшее или равное PHP_FCGI_MAX_REQUESTS. Однако в документации пропущен важный момент: значение также должно быть больше нуля (потому что ноль означает "неограниченный" или "отключить проверку" в этом контексте). Учитывая, что значение по умолчанию для FcgidMaxRequestsPerProcess равно нулю, а значение по умолчанию для PHP_FCGI_MAX_REQUESTS равно 500, любой администратор, который не переопределил эти значения, будет испытывать прерывистые 500 кодов ответов. По этой причине я не понимаю, почему FcgidMaxRequestsPerProcess и PHP_FCGI_MAX_REQUESTS не используют одно и то же значение по умолчанию. Возможно, это связано с тем, что настройка этих двух директив как таковых дает тот же чистый результат, что и установка PHP_FCGI_MAX_REQUESTS на ноль; документация неоднозначна в этом отношении.

Вариант 3

Третье решение - полностью отказаться от Fast-CGI в пользу сопоставимой альтернативы, такой как suPHP или обычный CGI + SuExec. Я провел несколько базовых тестов производительности в различных режимах PHP, и мои выводы заключаются в следующем:

  1. Мод-PHP 77.7
  2. CGI 69.0
  3. suPHP 67.0
  4. Fast-CGI 55,7

Mod-PHP - самый эффективный, с результатом 77,7. Оценки являются произвольными и служат только для демонстрации относительной дисперсии времени загрузки страницы в разных режимах PHP.

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

Хотя Fast-CGI не использует встроенное кэширование кода операции (например, через APC), умные пользователи разработали метод для повышения эффективности APC с помощью Fast-CGI (через кэши для каждого пользователя): http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/. Однако есть несколько недостатков:

  1. Требования к памяти (ОЗУ) значительны, поскольку для каждого пользователя имеется выделенный кэш. (Для перспективы учтите, что в режиме Mod-PHP все пользователи совместно используют один кеш.)
  2. Apache должен использовать более старый модуль mod_fastcgi вместо нового эквивалента mod_fcgid. (Подробнее см. Статью, процитированную в параграфе выше.)
  3. Конфигурация довольно сложная.

В качестве связанного следствия вы сказали следующее в своем вопросе:

Сначала я использую APC, поэтому PHP контролирует свои собственные процессы, а не FastCGI.

Если вы не используете mod_fastcgi (а не mod_fcgid), и если вы не выполнили шаги, подобные тем, которые цитировались несколькими параграфами выше, APC потребляет ресурсы без эффекта. Таким образом, вы можете отключить APC.

Краткое изложение решения

Примите одну из следующих трех мер:

  1. Установите переменную среды PHP_FCGI_MAX_REQUESTS в ноль. (Вводит потенциал для утечек памяти в сценариях PHP, чтобы выйти из-под контроля.)
  2. Задайте для FcgidMaxRequestsPerProcess значение, которое меньше или равно PHP_FCGI_MAX_REQUESTS, но больше нуля.
  3. Откажитесь от Fast-CGI в пользу сопоставимой альтернативы, такой как suPHP или простой старый CGI + SuExec.

Я где-то читал (имея в виду lighttpd, а не apache), что php по какой-то причине не может обработать более 500 запросов. 501-й запрос будет бомбить по любой причине.

Извините, у меня нет больше информации, но это как минимум стоит того.

tl;dr попробуйте установить PHP_FCGI_MAX_REQUESTS равным 500 и посмотреть, не устранена ли проблема.

Нашел информацию, она относится к Lighttpd, и я не знаю, относится ли она к apache или нет.

Протестируйте его, и я хотел бы услышать, если это только проблема с lighttpd, или это общая проблема.

Почему мое PHP-приложение время от времени выдает ошибку 500?

"Эта проблема, по-видимому, связана с малоизвестной проблемой PHP: PHP перестает принимать новые соединения FastCGI после обработки 500 запросов; к сожалению, во время кода очистки PHP существует потенциальное состояние гонки, при котором PHP может завершить работу, но при этом иметь сокет открыт, поэтому lighty может отправить запрос номер 501 в PHP и получить его "принятым", но затем PHP просто завершает работу, вызывая возврат 500 из lighty.

Чтобы ограничить это вхождение, установите PHP_FCGI_MAX_REQUESTS на 500. "

- http://redmine.lighttpd.net/projects/1/wiki/Docs:PerformanceFastCGI

Спасибо за ваш ответ. У меня все ошибки PHP происходит в лог-файл. Я получаю несколько уведомлений, но без ошибок. Я должен признать, что я не писал этот код. На данный момент я перенаправил все 500 ошибок в index.php, используя правило.htaccess. Я должен что-то упустить, хотя. Этого не должно быть. Единственное предположение, которое у меня есть, состоит в том, что когда PHP_FCGI_MAX_REQUESTS достигает максимального значения, php убивает дочернего элемента, и это сбивает с толку FastCGI. Однако, если я правильно понимаю, в PHP есть родительский процесс, который должен быть единственным, с которым FastCGI общается, поэтому я не уверен, что это так... Вот мой скрипт-обертка:

#!/bin/bash
# Shell Script To Run PHP5 using mod_fastcgi under Apache 2.x
# Tested under Red Hat Enterprise Linux / CentOS 5.x
### Set PATH ###
PHP_CGI='/usr/bin/php-cgi -d apc.shm_size=60M'
PHP_FCGI_CHILDREN=25
PHP_FCGI_MAX_REQUESTS=1000
### no editing below ###
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS
exec $PHP_CGI

Это очень объемный сервер, поэтому PHP_FCGI_CHILDREN установлен так высоко.

Еще раз спасибо, Бен

Другие вопросы по тегам