#javascript #amazon-s3 #meteor
#javascript #amazon-s3 #meteor
Вопрос:
В настоящее время моя группа запускает приложение meteor с сотнями тысяч изображений, которые все очень большие в натуральную величину. Мы должны были сделать это давным-давно, но нам нужен способ оптимизировать их, чтобы ускорить загрузку. Я ищу решение, позволяющее сохранять изображение в нескольких размерах, когда пользователь загружает его из нашего приложения (например: полноразмерный, средний, эскиз), а также автоматически поворачивать и разрешать пользователю поворачивать. Мы используем Amazon S3 для размещения всех наших изображений. Нам также нужен способ конвертировать все существующие изображения в эти форматы размеров со стороны сервера.
Некоторое время назад я пытался что-то реализовать, но безуспешно. Я настроил imagemagick на нашем сервере, но у меня возникли проблемы с запуском этого в производство, потому что изображение временно сохранялось в памяти сервера для обработки, но это вызывало сбои из-за ограниченного объема памяти. У меня мало опыта в подобных вещах.
Моей второй мыслью было использовать HTML canvas для изменения размера изображений. Я думаю, это сработало бы для вновь загруженных изображений. Но я все еще ищу способ обработки существующих изображений.
Я рассмотрел:
- Возможно, в AWS есть встроенный способ их обработки. Я бы не прочь сделать это таким образом.
- Какой-то пакет Meteor / node, который может помочь в этом.
- Настройка другого сервера только для обработки изображений.
- Использование какой-либо сторонней обработки изображений.
Если кто-нибудь может дать мне несколько советов, чтобы я мог начать работу, это было бы очень полезно!
Ответ №1:
libvips может изменять размер изображений без использования памяти или диска — пиксели передаются через систему небольшими порциями, при этом декодирование и перекодирование происходят одновременно.
Например, с JPG-изображением размером 10k x 10k пикселей я вижу:
$ vipsheader wtc.jpg
wtc.jpg: 9372x9372 uchar, 3 bands, srgb, jpegload
$ /usr/bin/time -f %M:%e vipsthumbnail wtc.jpg -s 5000x5000 -o x.jpg
98720:0.65
Это 4-ядерный 8-потоковый i7. Он использует 98 МБ памяти и занимает 0,65 с реального времени. В документах есть глава, посвященная vipsthumbnail.
Для сравнения, с ImageMagick 6 я вижу:
$ /usr/bin/time -f %M:%e convert wtc.jpg -resize 5000x5000 x.jpg
1263232:2.02
1,3 ГБ памяти, и это занимает 2 секунды реального времени — примерно в 10 раз больше памяти и в 3 раза медленнее.
Поскольку vipsthumbnail использует так мало памяти, вы можете объединить его с GNU parallel, не требуя сервера с большим количеством ГБ памяти. На этом i7 я могу с пользой запускать четыре одновременно и получать ускорение примерно в 4 раза, так что, возможно, в 12 раз быстрее, чем ImageMagick в целом.
sharp — популярная привязка к узлу для libvips, которая может быть более удобной. Также есть привязки для Python, Ruby, PHP, Go, Lua и т. Д. И т. Д.
(отказ от ответственности: Я один из сопровождающих libvips, поэтому я не очень нейтрален)
Комментарии:
1. Спасибо. Это действительно выглядит как действительно хороший вариант! Кажется, все флажки установлены. Мы попробуем это сделать. Я хочу посмотреть, какие другие варианты могут появиться, прежде чем я отмечу это как ответ. Меня больше всего беспокоит, сколько времени потребуется для обработки существующих изображений, хотя я не могу ожидать, что это будет быстро с тем количеством изображений, которые у нас есть в настоящее время. 😉
Ответ №2:
Я вижу два способа для двух совершенно разных бюджетов:
- Я не рекомендую этот способ, если у вас нет только 1-2 ГБ (https://transloadit.com/demos/file-importing/resize-all-images-in-an-s3-bucket /)
- Привяжите свой S3 к сервису Cloudinary и выполните преобразования с помощью Cloudinary (вам это не понравится ($$) из-за количества имеющихся у вас изображений).
- Я надеюсь, что в AWS вы используете Cloudfront для обслуживания своих ресурсов. Независимо от технологии преобразования вы в основном будете делать 2 вещи:
- Создайте 1 лямбда-функцию для преобразования всех новых созданных ресурсов в S3. Что я делаю, так это «отслеживаю» корзину S3, и все новые поступающие вещи запускают мою лямбда-функцию, и я создаю ресурсы в 2 других папках, и в итоге получаю: полное разрешение, половинное разрешение и разрешение большого пальца. Затем в Meteor вы связываете каждый размер с тем, что вам нужно. Наиболее типичный случай — это когда у вас есть изображение профиля пользователя, которое вам нужно, чтобы увидеть его в виде полного заголовка, списка или большого пальца в чате.
- Создайте 1 лямбда-ребро (я полагаю, чуть больше $$) и подключитесь к своему краю Cloudfront, чтобы отвечать на все вызовы. Если стоимость хранения для вас не слишком высока для текущего сохраненного объема, вы можете преобразовывать свои изображения по мере их запроса и заменять старые изображения большего размера, а не запускать их массово как процесс 1 раз.
Вместо Lambda Edge вы, вероятно, могли бы настроить компьютер EC2 с Node и запустить функцию для перебора всех ваших ресурсов S3 и выполнения преобразования.
В любом случае, я чувствую, что то, что вы хотите сделать, это все AWS, не связанное с вашим Meteor. Еще одна вещь, которую нужно сделать: оптимизировать изображения перед их загрузкой. Если вы используете React с Meteor, я мог бы предоставить вам необходимые компоненты, в противном случае я могу предоставить вам компоненты, а вы напишите слой Blaze view или что-нибудь еще, что вы можете использовать.
У меня есть функции преобразования лямбда в рабочей среде на основе ImageMagic, если вам интересно пойти этим путем. Я также планирую «обновить» эту функцию, чтобы использовать Sharp (как в примере), но пока она отлично работает в производстве, переключится, когда у меня будет время. Проверьте этот пример:
Download the image from S3, transform, and upload to a different S3 bucket or folder.
const dstKeyResizedHalf = `p-half/` imageName
s3.getObject({
Bucket: srcBucket,
Key: srcKey
}).promise()
.then(data => Sharp(data.Body)
.jpeg({
chromaSubsampling: '4:4:4',
progressive: true
})
.resize(WEB_WIDTH_MAX)
.toFormat('jpg')
.toBuffer()
)
.then(buffer => s3.putObject({
Body: buffer,
Bucket: dstBucket,
ContentType: 'image/jpg',
Key: dstKeyResizedHalf,
CacheControl: 'max-age=864000'
}).promise())
.catch(err => callback(err))
}
Комментарии:
1. Это чрезвычайно полезно. Спасибо. Я думаю, что, возможно, после прочтения ответов и просмотра некоторых страниц в Интернете, Lambda — это правильный путь. Запуск функции Lambda при запросе изображения для старых изображений — блестящее решение.
2. Если вы решите использовать Lambda, пожалуйста, дайте мне знать, и я предоставлю вам необходимые биты, если вам нужно.
3. Итак, хотел обновить это. В итоге я выбрал лямбда-маршрут, и он отлично работает. Я настроил шлюз API для запуска функции Lambda. Для меня это был лучший способ, чтобы я мог получить обратную связь в конце моих приложений о том, что преобразование изображения завершено и выполнено успешно. Я также закончил настройку процесса cron для преобразования существующих изображений с помощью API gateway снова. Пока все работает отлично. Итак, спасибо за помощь!
Ответ №3:
Я использую https://www.imagemagick.org / для изменения размера, обрезки, поворота моих изображений. это работает с meteor. Это будет хорошей отправной точкой для изучения. https://github.com/CollectionFS/Meteor-CollectionFS
Комментарии:
1. Omgabee написал в вопросе, что
imagemagick
вызывает проблемы, связанные с памятью, из-за временного сохранения копий изображений в памяти.2. Мое использование изображений ограничено, поэтому до сих пор я не сталкивался с какими-либо проблемами.