Недавно я перешел на установку FastCGI для PHP (Apache2-worker и mod_fcgid
). Однако, когда один скрипт PHP очень загружен, кажется, что он блокирует все другие запросы PHP. Что не так с моей конфигурацией?
Моя основная причина использования mod_fcgid
заключается в том, чтобы держать под контролем использование памяти PHP. С участием mod_php
, все отдельные вилки Apache увеличиваются в памяти после обслуживания PHP.
Я также перешел на модель apache2-worker, поскольку весь небезопасный для потоков PHP-код существует за пределами Apache.
Мой сценарий FastCGI выглядит так:
#!/bin/sh
#export PHPRC=/etc/php/fastcgi/
export PHP_FCGI_CHILDREN=5
export PHP_FCGI_MAX_REQUESTS=5000
global_root=/srv/www/vhosts.d/
exec /usr/bin/php-cgi5 \
-d open_basedir=$global_root:/tmp:/usr/share/php5:/var/lib/php5 \
-d disable_functions="exec,shell_exec,system"
Моя конфигурация Apache выглядит так:
<IfModule fcgid_module>
FcgidIPCDir /var/lib/apache2/fcgid/
FcgidProcessTableFile /var/lib/apache2/fcgid/shm
FcgidMaxProcessesPerClass 1
FcgidInitialEnv RAILS_ENV production
FcgidIOTimeout 600
AddHandler fcgid-script .fcgi
FcgidConnectTimeout 20
MaxRequestLen 16777216
<FilesMatch "\.php$">
AddHandler fcgid-script .php
Options +ExecCGI
FcgidWrapper /srv/www/cgi-bin/php5-wrapper.sh .php
</FilesMatch>
DirectoryIndex index.php
</IfModule>
Нашел ответ по адресу: https://stackoverflow.com/questions/598444/how-to-share-apc-cache-between-several-php-processes-when-running-under-fastcgi/1094068#1094068
Проблема не в PHP, а в mod_fcgid. Пока PHP порождает несколько дочерних элементов, mod_fcgid
не знает об этом и будет обслуживать по одному запросу на каждого ребенка. Следовательно, когда FcgidMaxProcessesPerClass 1
, все исполнения PHP происходят друг за другом. *
Решение представлено по ссылкам на: http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/ объясняет, как использовать mod_fastcgi
у которого нет этого ограничения. Он отправит несколько запросов одному и тому же дочернему элементу.
[*] Обратите внимание, что не используется FcgidMaxProcessesPerClass 1
приводит к множеству отдельных экземпляров PHP, ruby и т. д., при этом все они способны обрабатывать множество запросов внутри одного процесса.
Следовательно, новая конфигурация Apache для использования PHP с fastcgi:
<IfModule mod_fastcgi.c>
# Needed for for suEXEC: FastCgiWrapper On
FastCgiConfig -idle-timeout 20 -maxClassProcesses 1 -initial-env RAILS_ENV=production
FastCgiIpcDir /var/lib/apache2/fastcgi
AddHandler php5-fcgi .php
Action php5-fcgi /.fcgi-bin/php5-wrapper.sh
DirectoryIndex index.php
ScriptAlias /.fcgi-bin/ /srv/www/cgi-bin/
<Location "/.fcgi-bin/php5-wrapper.sh">
Order Deny,Allow
Deny from All
#Allow from all
Allow from env=REDIRECT_STATUS
Options ExecCGI
SetHandler fastcgi-script
</Location>
# Startup PHP directly
FastCgiServer /srv/www/cgi-bin/php5-wrapper.sh
# Support dynamic startup
AddHandler fastcgi-script fcg fcgi fpl
</IfModule>
Во-первых, ваш сценарий-оболочка и установка плохо спланированы, если только документы Apache не устарели. Прочтите «Особые соображения по PHP» в mod_fcgid документы и используйте там скрипт и пример настроек. Ваша текущая настройка будет в основном порождать кучу непригодных для использования дочерних процессов php, тогда каждый 5001-й запрос PHP будет вызывать ошибку, поскольку PHP выйдет после 5000-го запроса, но вам не хватает FcgidMaxRequestsPerProcess 5000
директива, которая сообщает mod_fcgid, что ему нужно будет запустить новый процесс PHP после 5000 запросов.
Что касается одновременных процессов PHP, каждый одновременный запрос требует своего собственного процесса PHP, поэтому вам нужно будет увеличить FcgidMaxProcessesPerClass
директива на большее число.