Мое веб-приложение позволяет пользователям загружать файлы, которые хранятся на s3, через мои серверы. Когда пользователь запрашивает файл, мой веб-сервер извлекает его из s3, а затем отправляет его клиенту.
Недавно я развернул балансировщик нагрузки, сделав мои текущие настройки следующим образом:
Обратите внимание, что в настоящее время у меня есть только один веб-сервер для упрощения отладки.
После того, как я развернул балансировщик нагрузки, я заметил, что загрузка больших файлов (размером более 4 МБ) завершалась ошибкой с таймаутом шлюза 504 через 60 секунд.
Я просмотрел журнал ошибок балансировщика нагрузки nginx для сайта и увидел несколько таких записей:
[error] 11770#11770: *40 upstream timed out (110: Connection timed out) while reading response header from upstream, client: XXXX, ...
Когда я посмотрел журнал ошибок nginx веб-сервера для сайта, я увидел похожие записи:
[error] 6632#6632: *41 upstream timed out (110: Connection timed out) while reading response header from upstream, client: ...
[error] 6632#6632: *85 upstream timed out (110: Connection timed out) while reading response header from upstream, client: ...
[error] 7163#7163: *41 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ...
[error] 7505#7505: *41 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ...
[error] 7505#7505: *91 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ....
И глядя на журналы ошибок php-fpm на моем веб-сервере:
WARNING: [pool www] child 3011, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (64.950545 sec), terminating
WARNING: [pool www] child 3011 exited on signal 15 (SIGTERM) after 1140.059968 seconds from start
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
WARNING: [pool www] child 4260, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (68.171099 sec), terminating
WARNING: [pool www] child 4260 exited on signal 15 (SIGTERM) after 160.005837 seconds from start
NOTICE: [pool www] child 4271 started
Я объяснил это тем, что у моих тайм-аутов выполнения php и тайм-аутов соединения nginx слишком мало, поэтому я увеличил их, выполнив следующие действия:
proxy_read_timeout 600s;
в /etc/nginx/nginx.conffastcgi_read_timeout 600;
в блок местоположения .php.max_execution_time = 600
и default_socket_timeout = 600
в конфигурацию php-fpm.request_terminate_timeout = 300
в /etc/php/7.0/fpm/pool.d/www.confЭто в некоторой степени устранило мою первоначальную проблему, так как теперь я могу загружать файлы большего размера (проверено до 25 МБ).
После указанных выше изменений конфигурации я могу загружать файлы без тайм-аута, однако для начала загрузки требуется слишком много времени (~ 300 секунд), а сама загрузка идет медленно (небольшая проблема).
Процесс загрузки файла следующий:
Для справки, на веб-сервере выполняется следующая функция:
public function show($projectID, $documentID, $revisionID, $fileID)
{
$fileEntry = File::find($fileID);
$path = $fileEntry->path();
$file = Storage::get($path);
$size = Storage::size($path);
return Response::make($file, 200)
->header('Content-Type', $fileEntry->mime)
->header('Content-Disposition', 'attachment; filename="' . $fileEntry->original_filename . '"')
->header('Content-Length:', $size);
}
Я понимаю, что я дважды обрабатываю файлы и в будущем переключусь на подписанные перенаправления URL-адресов s3, но есть другие части приложения, где это не будет практично (захват коллекции файлов, архивирование и отправка клиенту) и, следовательно, будет хотел бы получить некоторое понимание.
Что могло быть причиной этой проблемы? Я не думаю, что когда-либо сталкивался с этой проблемой до развертывания балансировщика нагрузки.
Если я загружаю файл непосредственно из s3, время загрузки составляет лишь часть от общего времени при передаче через мой сервер, поэтому я не верю, что проблема заключается в двойной обработке. Это может быть связано с размером буфера или памяти?
Дополнительная информация:
Хорошая редакция, все намного яснее.
Похоже, это тайм-аут приложения в PHP. Я предполагаю, что PHP полностью загружает большие файлы во временное место, а затем возвращает их, а не передает их обратно напрямую. Этим объясняется задержка, но не столько низкая скорость. Я даже не знаю, практична ли прямая потоковая передача прямо с S3 обратно через ваш стек - исследуйте, если требуется (вами). Я бы также посмотрел, имеет ли значение PHP5, я нашел PHP7 менее надежным в нескольких крайних случаях.
Я бы отслеживал точное время, когда запросы приходят, попадают на каждый сервер и ответы возвращаются каждым сервером, чтобы вы могли полностью отслеживать запрос. Это особенно верно для уровня PHP: добавьте ведение журнала, когда сервер приложений получает запрос, когда он извлекается из S3 и когда он начинает отправлять его обратно клиенту.
Скорость загрузки немного озадачивает. Я бы нашел способ проверить скорость между вашим PHP-сервером и S3 - сделайте завиток или что-то в этом роде - это может быть простая проблема с пропускной способностью или задержка, уменьшающая доступную пропускную способность. Обходной путь может заключаться в использовании CloudFront, но, вероятно, нет, так как это ускорит загрузку только при втором запросе, а не при первом.
После того, как вы все это сделаете, если вы еще не разработали, опубликуйте информацию, которую вы обнаружите, особенно точное время, когда несколько запросов попадают на каждый уровень, и время, когда ответы возвращаются.