[Решено] Большой файл вгружается в ноду, но не появляется. AmazonS3.

Главные вкладки

Аватар пользователя meloff meloff 15 октября 2013 в 13:50

Всем привет. Запустил сайт и под посетителями выяснилось, что нужно срочно менять способ хранения файлов.

Ночью установил на сайт модуль AmazonS3, AWS SDK for PHP, нужные библиотеки, все настроил, все работает, небольшие файлы грузятся. Но проблема в загрузке больших файлов. В php.ini я установил лимит в 6442450944 байт, это 6гб. Выбираю файл весом 600мб через стандартную грузилку в ноде, нажимаю загрузить, загрузка доходит до 100% где-то за 40мин (yota мать её) и.... ничего не происходит. Ни ошибок, ни сообщений в логах, но файл не появляется в интерфейсе, и не появляется в s3, как будто бы я его и не загружал вовсе.

Если нажать сохранить ноду, то файл опять снова начинает загружаться, так как выбран в аплоадере, после загрузки открывается белая страница с бесконечной загрузкой. Может у нее и есть конец, но пока что терпения дождаться у меня не хватило, а посетители тем более не будут ждать.

Сайт на nginx'е и php-fpm. Подскажите пожалуйста, куда ковырять?

Комментарии

Аватар пользователя meloff meloff 15 октября 2013 в 18:10

Поменял модуль AmazonS3 на Storage API, проблема осталась. Поймал ошибку: "HTTP запрос AJAX завершен неправильно. Следует отладочная информация. Путь /file/ajax/field_file/und/0/form-тутмногобукв/x-progress-id%многобукв СатусТекстом ОтветТекстом: 502 Bad Gateway nginx ReadyState: undefined" я так понимаю надо копать в сторону nginx.. только вот куда?

Аватар пользователя sg85 sg85 15 октября 2013 в 20:45

Странно что это вылетает в режиме fastCGI, возможно не может запустить дополнительный процесс ввиду нехватки памяти(на сервере), других мыслей пока в голову не приходит, нагрузку на сервер во время заливки файла смотрели? хотя бы тем же top`ом.

Аватар пользователя meloff meloff 15 октября 2013 в 21:41

Сейчас смотрю, пишет во время загрузки, что mysql отъедает 42.3% php-fpm 5%, nginx 0.6% а всего у меня пока что 512мб за минус убунты. Но это, мне кажется, ничего не дает, т.к. ошибка вылетает уже после загрузки до 100%, браузер в этот момент что-то обновляет и вылетает ошибка ajax.
+ Хотя может вы и правы.. обратил внимание, что во время загрузки свободной памяти практически нет..

Аватар пользователя meloff meloff 17 октября 2013 в 12:40

В своих поисках я дошел до того, что установил на свою ubuntu пакет s3fs и примонтировал папку хранилища в папку сайта. И опять похожие симптомы.. мелкие файлы грузятся нормально, а файл в 100мб после загрузки становится 0байт. И..! Даже если закинуть файл в эту папку через WinSCP, который работает по протоколу SFTP, файл догружается до 100% и вылезает ошибка!
Я подозреваю, что проблема кроется в каких-то таймаутах..

Аватар пользователя meloff meloff 20 октября 2013 в 2:02

Проблема в s3fs у меня была в опции multipart. Если команде примонтирования директории задать опцию "-o nomultipart", то начинают передаваться большие файлы. Но s3fs я побоялся использовать, т.к. при загрузке большого файла у меня повис vds наглухо.. Опасное решение как мне кажется. И я вернулся к ковыряниям модулей amazon s3, storage api, и нашел еще один модуль - s3 file system.

За это время я уже по 30ть раз перелопатил конфиги nginx'а и php-fpm.. Сейчас играюсь с модулем s3 file system и обнаружил одну вещь. Собственно sq58 был прав - проблема в оперативной памяти. Сейчас у меня свободно 220мб, но как только я начинаю грузить файл, оперативная память постепенно заполняется до 100%, что может значить только одно - файл грузится в оперативку. По заполнении памяти на 100%, файл продолжает куда-то грузиться, только вот грузиться ему уже видимо некуда и по окончании происходит ошибка 500 Bad Gateway. Это кстати в FF, в chrome ошибка вроде как 502. Если кто знает как избежать переполнения памяти, буду благодарен.

Итого, варианты которые мне видятся:

Использовать модуль S3 Cors. Он отлично загружает файлы и в целом работает нормально, даже прогресс бар работает, но у него есть значительный косяк.. Если вгрузить файл в поле, затем файл удалить и выбрать новый файл - отваливается кнопка загрузить. Чтобы загрузить новый файл, нужно перезагружать страницу. Если поле необязательное, то это еще пол беды. Самое интересное начинается если поле обязательное. Я уже плохо помню, в голове все перемешалось, но в если поле с файлом обязательное, то-ли файл невозможно удалить из поля и заменить новым, то-ли можно сохранять ноду даже если поле не заполнено.. А мне нужно именно обязательное поле для моего проекта.. и к сожалению я не программист..

Вариант второй.. Написать волшебную секцию в nginx, которая сама будет авторизоваться и напрямую передавать файлы в s3.. Думаю это возможно, т.к. я встречал вот тут https://coderwall.com/p/rlguog решение как загружать файлы из не публичного s3. Думаю можно сделать и наоборот, но знаний у меня для этого маловато.

Вариант третий.. Дождаться когда автор модуля fine uploader https://drupal.org/node/2115563 портирует модуль в D7. Насколько я понимаю оригинальный fine uploader позволяет грузить файлы напрямую в s3.

Вариант четвертый.. Все же прикрутить какую-то монтировалку хранилища s3 напрямую в систему. Пока что пробовал s3fs, но у меня почему-то не работает multipart и попробовал s3ql, но он какой-то странный.. забрасывает в s3 кучу своих файлов.. и я не уверен, что он подойдет для моих целей.. на д7 пока не проверял. Может есть еще какие-то варианты?

Вариант пятый.. Либо все же как-то избежать переполнения памяти с модулями amazon s3, storage api и s3 file system, либо купить сервак с 5гб+ оперативы.. Последнее для меня не выполнимо пока что..

Если у кого-то есть рабочее решение по загрузке больших файлов на s3, я буду очень рад его услышать. Меня интересуют любые варианты. Если вы можете доработать модуль s3 cors, можете написать в личку свои расценки. Пока что на 100% рабочих решений я не нашел.

Аватар пользователя sg85 sg85 20 октября 2013 в 2:28

Можно попробовать заменить php-fpm на apache в режиме mpm-prefork(только не на продакшене), на сколько помню он все время висит в системе единым процессом(тут могу заблуждаться), по крайней мере проблема bad gateway должна отвалиться, правда чую я, что он сдохнет от чего-то другого...

Аватар пользователя meloff meloff 21 октября 2013 в 0:51

Спасибо за комментарий! Но хотелось бы уточнить.. я не так давно в линукс.. и поэтому у меня вопрос назревает - загрузка файлов, я имею ввиду upload файлов, в кеш, который отъедает оперативную память это норма или просто что-то не то с моей конфигурацией? Т.е. возможно загрузить файл на сайт размером, допустим, 5гб, даже если свободной памяти всего 500мб? Разум говорит мне конечно же да, но да деле я не уверен как это происходит..

Аватар пользователя sg85 sg85 21 октября 2013 в 1:54

Честно говоря сам с подобными проблемами не сталкивался... Правда и S3 не юзал...

"meloff" wrote:
Т.е. возможно загрузить файл на сайт размером, допустим, 5гб, даже если свободной памяти всего 500мб?

можно

Кстати, для загрузки больших файлов на сервер апач действительно может оказаться более удачным решением нежели php-fpm, особенно, если сей процесс нужно контролировать(в случае с nginx+fastCGI это будет всем костылям костыль).

Аватар пользователя meloff meloff 23 октября 2013 в 12:14

Все же по вашему совету я попробовал установить apache и поднять уже на нем сайт. Я получил тот же самый результат. Да и в целом apache работал более медленно и mysql выдавал кучу ошибок. При желании можно было конечно все настроить и ускорить, но мне не очень хотелось этого делать, тем более когда нужный результат такой же и уже есть рабочая и более-менее прокачанная конфигурация с nginx'ом и ш.. акселерраторами.

Поэтому после экспериментов, я восстановил бекап со старой конфигурацией (digitalocean волшебная вещь) и начал искать решение.. и нашел такую вещь как plupload. Его прелесть в том, что он умеет шинковать фалы на заданные кусочки, а потом собирать кусочки в единый файл. Тестовая загрузка 500мб файла в директорию сайта прошла успешно. И я решил совместить его с предыдущим опытом, чтобы все-таки как-то отправить файл в s3.

Я несколько раз перепробовал модули, что использовал раньше, заметил что отправка файла обрывается строго на 30 секундах, и понял что проблема кроется где-то еще.. Поиски заветной цифры дали свои плоды.

Во первых в модуле storage api содержится вот такой вот блок:

<?php
$options = array(
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_AUTOREFERER => TRUE,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_LOW_SPEED_LIMIT => 256,
CURLOPT_LOW_SPEED_TIME => 60,
CURLOPT_FILE => $fp
);
?>

В модуле amazon s3 есть аналогичные строки, но поменяв их ничего не изменилось, загрузка продолжала обрываться на 30 секундах и я стал искать дальше и нашел в /etc/php5/fpm/pool.d/www.conf параметр "request_terminate_timeout". Установив его в 0, отсылка файлов перестала выдавать 502 ошибку, скрипт научился ждать ответа бесконечно. И тут у меня получилось в первый раз закинуть файл в 200мб на s3. Но я не был уверен, что пользователи будут ждать столько времени.. если файл большой, то иногда после загрузки приходится ждать полчаса, пока файл прикрепится.

Затем, посмотрев скринкаст, я узнал что storage api умеет отсылать файлы не только сразу на s3, но и по крону. Сначала файлы грузятся в папку сайта, а по запуску крона отправляются в целевое место, и пользователям не нужно ждать еще кучу времени после загрузки файла.

Настроив все это дело и запустив крон я в первый раз отправил в 3s файл размером 500мб Smile Сейчас на начальную загрузку у меня стоит plopload, что в нем хорошо - он умеет прикреплять файлы по внешним ссылкам, показывать прогресс бар даже на nginx без upload progress, в нем есть drag'n'drop и он старается не перегружать память. Правда делает это несколько странно.. Сначала он забивает всю свободную память, а когда остается 30мб, начинает резать файлы. У меня в настройках стоит резать по 10мб, и видно что оперативка скачет с 20мб на 30ть по мере нарезки кусочков. На отправку файлов по крону настроен storage api. Только когда начинает работать крон, по top'у создается впечатление что сервер щас рухнет. Рано или поздно все равно придется перелезать на более мощный серв, но не раньше того как сайт начнет зарабатывать хоть что-то, а для начала я думаю мне этого хватит Smile

Есть еще одна затея и связана она с модулем plupload. Имея прямые руки, его можно настроить отправлять файлы напрямую в s3. Я встречал обсуждения как это сделать, в стандартных примерах модуля есть пример отправки в s3. Но у меня руки кривые, поэтому пока что это планы на будущее.

Спасибо за помощь! Smile

Аватар пользователя meloff meloff 24 октября 2013 в 13:31

Все же меня интересует как можно получить файл из закрытой директории s3 с помощью nginx и, второе, как его загрузить на s3 используя стандартный file_field. Это уже далековато от тематики друпала, но если кто знает как это можно сделать, буду рад помощи. Пока что добиваюсь либо ошибок method not allowed при попытке аплоада или сообщение о неправильной сигнатуре при попытке загрузки.. Из незащищенной директории я могу скачивать без проблем, рабочий location есть тут http://www.drupal.ru/node/101020, а вот с авторизацией не получается. nginx/1.1.19

Аватар пользователя sg85 sg85 24 октября 2013 в 18:58

"meloff" wrote:

Все же меня интересует как можно получить файл из закрытой директории s3 с помощью nginx и, второе, как его загрузить на s3 используя стандартный file_field. Это уже далековато от тематики друпала, но если кто знает как это можно сделать, буду рад помощи.

location это лишь один из способов, так же можно использовать символические ссылки, правда в этом случае нельзя забывать, что file_scan_directory, коим друпал любит обходить sites/default/files, не считает их за каталоги, что так же очень удобно при работе с огромным числом файлов. Впрочем, оба способа имеют свои плюсы и минусы.

Проблемы с закрытием доступа можно решить тем же друпалом, по принципу этого http://www.drupal.ru/node/104625

Аватар пользователя meloff meloff 24 октября 2013 в 20:37

Да ничего Smile Кстати у меня вроде получилось сделать авторизацию на редиректе к файлу, который лежит на амазон s3. Немного кривовато, но работает, если просто открыть в браузере адрес "букет.s3.amazonaws.com/каталог/файл.zip" выдает access denied, если через редирект сайта, дает скачать, т.е. файлы теперь полностью защищены. Вот источник https://github.com/lovelysystems/nginx-examples/blob/master/s3/nginx/ngi...

Nginx вот с таким конфигом:

<?php
./configure --prefix=/etc/nginx --sbin-path=/etc/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-debug --with-http_addition_module --with-http_dav_module --with-http_gzip_static_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl --with-mail --with-mail_ssl_module --with-http_secure_link_module --with-http_image_filter_module --add-module=../nginx-upload --add-module=../nginx-upload-progress --add-module=../lua-nginx-module --add-module=../ngx_devel_kit-0.2.19 --add-module=../set-misc-nginx-module-0.22
?>

Также необходимо установить пакеты:
<?php
apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev
?>

А location скачивания выглядит сейчас так:

<?php
location ~* /internal_redirect/(.*)filenameis:(.*) {

proxy_connect_timeout 86400;
proxy_send_timeout 86400;
proxy_read_timeout 86400;

internal;
resolver 8.8.8.8;

access_log /var/log/nginx/internal_redirect.access.log;
error_log /var/log/nginx/internal_redirect.error.log;

set $name $2;
set $pathname директория/$2;
set $url $1;
set $bucket "названиебукетабезс3амазонточкаком";

set_by_lua $now "return ngx.cookie_time(ngx.time())";

set $aws_signature '';

set $aws_access_key аккесскей;
set $aws_secret_key секретныйаккесскей;

set $string_to_sign "$request_method\n\n\n\nx-amz-date:$now\n/$bucket/$pathname";
set_hmac_sha1 $aws_signature $aws_secret_key $string_to_sign;
# encode the signature with base64
set_encode_base64 $aws_signature $aws_signature;
proxy_set_header x-amz-date $now;
proxy_set_header Authorization "AWS $aws_access_key:$aws_signature";

rewrite .* /$pathname break;
proxy_set_header Host $bucket.s3.amazonaws.com;
rewrite .* /$pathname break;

#set $bucket 's3-eu-west-1.amazonaws.com'; #может лучше этот использовать т.к. EU
proxy_hide_header Content-Disposition;
add_header Content-Disposition 'attachment; filename="$name"';
proxy_max_temp_file_size 0;

proxy_pass http://$bucket.s3.amazonaws.com;
}
?>

Ссылку у меня генерит rules. После нажатия кнопки http://сайт.ру/node/download/5/ идет проверка купил ли пользователь продукт 5, затем рулс редиректит на ссылку /internal_redirect/http://букет.s3.amazonaws.com/директория/файл.zipfilenameis:файл.zip на которую срабатывает location.

Теперь бы сделать наоборот, закачку файлов через nginx на s3, но пока не получается.