Как оптимизировать изображения, загруженные пользователем, а также существующие изображения на сервере в Meteor

#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. Я не рекомендую этот способ, если у вас нет только 1-2 ГБ (https://transloadit.com/demos/file-importing/resize-all-images-in-an-s3-bucket /)
  2. Привяжите свой S3 к сервису Cloudinary и выполните преобразования с помощью Cloudinary (вам это не понравится ($$) из-за количества имеющихся у вас изображений).
  3. Я надеюсь, что в 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. Мое использование изображений ограничено, поэтому до сих пор я не сталкивался с какими-либо проблемами.