Примечание: это то же самое, что и это сообщение SO, но, возможно, здесь более уместно, поскольку я подозреваю, что проблема связана с конфигурацией сервера, а не с кодом.
Я использую установку LAMP с запущенным PHP mod_fcgid
. Для большинства запросов это работает хорошо, но я заметил, что когда я загружаю файл, но прерываю загрузку до ее завершения, процесс php-cgi, обслуживающий блоки файлов, пытается записать больше данных, пока не будет IPCCommTimeout
достигнуто. По истечении времени ожидания процесс прерывается, и процесс снова начинает обслуживать другие запросы.
Эта проблема не возникает, если я использую mod_php
вместо того mod_fcgid
.
Есть ли какой-нибудь доступный параметр для fcgid, который я могу установить, чтобы он прервал его, если ничего не фиксирует вывод? Могу ли я что-нибудь сделать в PHP, чтобы справиться с этим?
Проблема не возникает, если загрузка не прерывается; Фактически, я заметил это только потому, что я пытался передать FLV-файл с помощью gddflvplayer, который, кажется, отправляет короткий запрос на получение первых нескольких кадров (которые он показывает как предварительный просмотр), а затем еще один для воспроизведения, и это вызывает та же проблема.
К вашему сведению, это часть процесса зависания cgi; он сидит так до тех пор, пока в конечном итоге не будет прерван, предположительно менеджером процесса, когда IPCCommTimeout
достигнуто. Я предполагаю, что он висит, пытаясь вывести результаты readfile()
вызов, но Apache больше не слушает (так как запрос был отменен пользователем).
root@some-machine:~# strace -p 24837
Process 24837 attached - interrupt to quit
write(3, "\5|A\313%\35\337\376\275\237\230\266\242\371\37YjzD<\322\215\357\336:M\362P\335\242\214\341"..., 17432
Журналы показывают, что запрос в конечном итоге получен из-за тайм-аута.
mod_fcgid: read data timeout in 240 seconds
Код загрузки более или менее просто использует readfile
для обслуживания файла с несколькими задействованными заголовками (примечание: в этом коде Header
более или менее просто обертка вокруг header()
чтобы не было проблем в тестах).
$filepath = '/some/path/foo.flv';
$filename = 'foo.flv';
$disposition = 'inline';
$h = Header::get();
$h->send('Pragma: public');
$h->send('Content-Transfer-Encoding: binary');
$h->send('Content-type: ' . FileSystem::get()->getMimeType($filepath));
$h->send('Content-Length: ' . FileSystem::get()->getFileSize($filepath));
$h->send('Content-Disposition: ' . $disposition . '; filename="' . $filename . '"');
$h->send('Content-transfer-encoding: 8bit');
$h->send('Expires: 0');
$h->send('Pragma: cache');
$h->send('Cache-Control: private');
flush();
readfile($filepath);
Сам сервер работает под управлением Debian Lenny со стандартными пакетами для php5-cgi
, apache2
, libapache2-mod-fcgid
, но я также получаю те же результаты на коробке разработки с Ubuntu 10.10.
Информация о пакете следующая -
[foo@bar ~]$ dpkg -l | egrep '(apache2|php5)' ii apache2-mpm-worker 2.2.9-10+lenny9 Apache HTTP Server - high speed threaded model ii apache2-utils 2.2.9-10+lenny9 utility programs for webservers ii apache2.2-common 2.2.9-10+lenny9 Apache HTTP Server common files ii libapache2-mod-fastcgi 2.4.6-1 Apache 2 FastCGI module for long-running CGI scripts ii libapache2-mod-fcgid 1:2.2-1+lenny1 an alternative module compat with mod_fastcgi ii php5 5.2.6.dfsg.1-1+lenny9 server-side, HTML-embedded scripting language (metapack ii php5-cgi 5.2.6.dfsg.1-1+lenny9 server-side, HTML-embedded scripting language (CGI bina ii php5-cli 5.2.6.dfsg.1-1+lenny9 command-line interpreter for the php5 scripting languag ii php5-common 5.2.6.dfsg.1-1+lenny9 Common files for packages built from the php5 source ii php5-curl 5.2.6.dfsg.1-1+lenny9 CURL module for php5 ii php5-ffmpeg 0.5.3.1-3 ffmpeg support for php5 ii php5-fileinfo 1.0.4-1 Fileinfo module for PHP 5 ii php5-gd 5.2.6.dfsg.1-1+lenny9 GD module for php5 ii php5-imagick 2.1.1RC1-1 ImageMagick module for php5 ii php5-mysql 5.2.6.dfsg.1-1+lenny9 MySQL module for php5 ii php5-suhosin 0.9.27-1 advanced protection module for php5
Мы могли бы рассматривать вашу проблему как «на самом деле не проблема», так как при истечении времени ожидания скрипт php завершается. Если бы он не закончился по истечении тайм-аута, у вас были бы большие проблемы :-). Затем, чтобы уменьшить время зависания, вы, по крайней мере, сможете поиграть с параметрами FcgidBusyTimeout и FcgidBusyScanInterval, http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidbusytimeout
Теперь, по сути, apache не отправляет никакой информации о закрытии tcp / ip клиента в бэкэнд fcgid. Поиск на комета вещи на переполнении стека дает отличный ответ: https://stackoverflow.com/questions/1354690/http-proxy-fastcgi-scgi-not-closing-connection-when-client-disconnected-bug-or/1384620#1384620 , где bbum дает ссылку на патч mod-fastcgi, если вы действительно хотите справиться с преждевременным концом.
Проблема сводится к блокировке сеанса PHP; по какой-то причине mod_php удается разблокировать сеанс при отмене запроса, но mod_fcgid в этом случае нет. Вызов session_write_close()
перед readfile()
(100% безопасно, так как я все равно ничего не буду делать после вывода файла, так как это повредит его) обеспечивает снятие блокировки сеанса и предотвращает зависание системы для этого пользователя.
Вы можете проверить ignore_user_abort установка и max_execution_time настройка.