У меня проблема с FastCGI (mod_fastcgi). Это случается время от времени и не вызывает полного отказа сервера, а всего лишь 500 ошибок. Вот пара вещей. Сначала я использую APC, поэтому PHP контролирует свои собственные процессы, а не FastCGI. Кроме того, у меня установлен веб-корневой каталог:
/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 на какое-то другое число, пока он взрывается. Кто-нибудь видел что-нибудь подобное. Может быть, это какая-то блокировка файлов?
Спасибо Бен
Я наблюдал такое же поведение с Apache; похоже, что эта проблема не специфична для lighttpd.
В моем случае симптомы были точно такими же; журналы доступа Apache были заполнены прерывистыми кодами ответа 500, и в журнале ошибок PHP не было соответствующих записей (а отчеты об ошибках PHP были настроены на максимально подробные).
Я подробно описал проблему в списке рассылки Apache (выполните поиск в архивах списков по теме «500 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 будут использовать разные кеши опкодов.
Вот и все.
Одно из решений - установить PHP_FCGI_MAX_REQUESTS равным нулю, но принятие этой меры приводит к тому, что утечки памяти могут выйти из-под контроля.
Различные фрагменты документации, с которыми я консультировался, не проясняют, страдает ли PHP через Fast-CGI от внутренней утечки памяти (отсюда и такое встроенное поведение «повторного использования процесса»), или риск ограничен плохо написанным, " убегающие »скрипты.
В любом случае существует риск, связанный с установкой PHP_FCGI_MAX_REQUESTS в ноль, особенно в среде общего хостинга.
Второе решение, описанное в приведенном выше отрывке, состоит в том, чтобы установить для FcgidMaxRequestsPerProcess значение, меньшее или равное PHP_FCGI_MAX_REQUESTS. Однако в документации отсутствует важный момент: значение также должно быть больше нуля (потому что ноль в данном контексте означает «без ограничений» или «отключение проверки»). Учитывая, что значение по умолчанию для FcgidMaxRequestsPerProcess равно нулю, а значение по умолчанию для PHP_FCGI_MAX_REQUESTS - 500, любой администратор, который не переопределил эти значения, будет сталкиваться с прерывистыми кодами ответа 500. По этой причине я не могу понять, почему FcgidMaxRequestsPerProcess и PHP_FCGI_MAX_REQUESTS не имеют одного и того же значения по умолчанию. Возможно, это связано с тем, что настройка этих двух директив как таковых дает тот же чистый результат, что и установка PHP_FCGI_MAX_REQUESTS в ноль; документация в этом отношении неоднозначна.
Третье решение - полностью отказаться от Fast-CGI в пользу сопоставимой альтернативы, такой как suPHP или старый добрый CGI + SuExec. Я провел базовый тест производительности в различных режимах PHP и получил следующие результаты:
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/ . Однако есть несколько недостатков:
Как следствие, вы сказали в своем вопросе следующее:
Сначала я использую APC, поэтому PHP контролирует свои собственные процессы, а не FastCGI.
Если вы не используете mod_fastcgi (а не mod_fcgid), и если вы не выполнили шаги, аналогичные приведенным в нескольких абзацах выше, APC потребляет ресурсы безрезультатно. Таким образом, вы можете отключить APC.
Примите одно из следующих трех мер:
Я где-то читал (имея дело с lighttpd, а не с apache), что php по какой-то причине не может обрабатывать более 500 запросов. 501-й запрос взорвется по любой причине.
Извините, у меня нет дополнительной информации, но по крайней мере стоит попробовать.
tl; dr попробуйте установить PHP_FCGI_MAX_REQUESTS на 500 и посмотреть, исчезнет ли проблема сама собой.
Протестируйте его, и я хотел бы услышать, является ли это проблемой только с lighttpd или это общая проблема.
Почему мое приложение PHP время от времени возвращает ошибку 500?
"Эта проблема, по-видимому, связана с малоизвестной проблемой PHP: PHP перестает принимать новые FastCGI-соединения после обработки 500 запросов; к сожалению, во время выполнения кода очистки PHP существует потенциальное состояние гонки, в котором PHP может завершать работу, но все еще имеет сокет открыт, поэтому лайт может отправить запрос номер 501 в PHP и "принять" его, но тогда PHP, кажется, просто завершает работу, вызывая возврат 500 из лайтса.
Чтобы ограничить эту возможность, установите 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 установлен так высоко.
Еще раз спасибо Бен