Сравнение инструментов для генерации thumbnails: imgproxy, thumbor, imaginary, picfit, imageproxy и weserv/images

15 ИЮНЯ 2022

------------------------------------------------------------------------

Наш телеграм-канал: t.me/@mailsgun_online

Youtube: youtube.com/@mailsgun_online

------------------------------------------------------------------------

Обновить

Предыстория

Жил был один новостной проект. Время шло, одни фичи добавлялись, вторые удалялись… Одной из важнейших фишек была генерация превьюшек к картинкам (thumbnails), а именно — быстрая генерация (до 5 минут) всех thumbnails. Все было хорошо, пока не начали поступать жалобы, что, иногда, генерация не успевает за 5 минут все сделать. Начали «копать» и обнаружили интересную вещь: мы генерим 112 превьюшек к одной картинке. Нашей «радости» не было предела. После небольших дискуссий было решено увеличить maxReplicas до 60 в HPA (проблема возникала когда загружалось больше 80 картинок), так как это самое быстрое и дешевое решение.

Наши дни

Пришёл новый проект и ему потребовались thumbnails. Сервер немного опережал фронт, поэтому у нас было время на R&D.

Первым был найден imgproxy, а потом уже все остальные (см заголовок). Так же нам на глаза попалась следующая статья. Она, конечно, очень смахивала на заказную (что в результатах и будет видно), но все равно очень интересно.

Перед тем как приступить к тестированию, нужно было определиться, что мы хотим в итоге:

  • приемлемый RPS (от 10)

  • возможность работы с S3 (Minio)

  • кеширование сгенерированных превьюшек

  • защита от URL tampering

Краткий обзор каждого инструмента

Imgproxy

Github (5k starts, latest release — 2021-09-07)

Плюсы:

  • самая «живая» из всех (на момент написания статьи — последний релиз 8 дней назад)

  • подробная документация

  • большой список возможностей (имеется PRO версия со своими фичами)

  • есть защита от URL tampering (есть примеры генерации сигнатур для разных ЯП — https://github.com/imgproxy/imgproxy/tree/master/examples)

  • может «читать» оригиналы картинок не только по http, а и по S3, Google Cloud Storage и Azure Blob Storage

  • есть готовый helm chart

Минусы:

  • нет готового механизма кеширования (это принципиальная позиция: imgproxy does one thing — resizing remote images — and does it well. It works great when you need to resize multiple images on the fly to make them match your application design without preparing a ton of cached resized images or re-doing it every time the design changes.)

thumbor

Github (8.6k starts, latest release — 2020-02-27)

Плюсы:

  • больше всего звезд на гитхабе

  • есть разные плагины

  • есть защита от URL tampering

  • есть встроенный механизм кеширования

Минусы:

  • может «читать» с S3, но как выяснилось — плагин для S3 написан на Python 2.7, а мы выбрали Release 7.0.0a5 который использует Python 3. В итоге эти штуки не взлетели вместе

  • единственное кеширование, которое работает — file_storage, что не есть хорошо, если говорить в контексте k8s

imaginary

Github (3.8k starts, latest release — 2020-08-12)

Плюсы:

  • есть защита от URL tampering

  • очень прост в настройке

  • есть интересная фишка: запросы GET | POST на /info — «Returns the image metadata as JSON»

Минусы:

  • нет S3

  • нет кеширования

Отдельное слово хочу добавить про генерацию сигнатуры (защита от URL tampering). Все что есть в документации: Enable URL signature (URL-safe Base64-encoded HMAC digest). Хорошо если ты пишешь на Go, можно зайти в исходники и найти это дело: https://github.com/h2non/imaginary/blob/master/middleware.go#L173

У нас же был PHP…

Пришлось потратить много времени, что бы отыскать это.

Если вкратце, то параметры в URL должны быть в определенном порядке (отсортированы по abc): height=240&url=XXX&width=320&sign=YYY. Если вы написали следующее: width=320?height=240&url=XXX&sign=YYY, то сигнатура в этом случае не совпадет и вместо картинки вы увидите текст об ошибке.

picfit

Github (1.5k starts, latest release — 2020-09-11)

Плюсы:

  • есть защита от URL tampering

  • прост в настройке (все настройки в json файле)

  • есть кеширование в Amazon S3, DigitalOcean S3, Google Cloud Storage.

Минусы:

  • нет готового докер образа в docker hub (но в репе есть Dockerfile)

  • как оказалось позже, кеширование работает напрямую с Amazon (те. нельзя сделать s3_endpoint=http://minio:9000). Кеширование на файлах есть, но нам не подходит

imageproxy

Github (2.6k starts, latest release — 2020-04-03)

Плюсы:

  • есть защита от URL tampering

  • есть кеширование в S3 и много куда еще (и даже in-memory LRU cache)

Минусы:

  • нет механизма upscale (если у вас картинка 1920×1080, то вы никак не сможете получить 3840×2160). Upd: @garfik подсказал параметр scaleUp, после его добавления — все взлетело.

weserv/images

Github (908 starts, latest release — 2021-09-07)

Плюсы:

  • простой и быстрый

  • есть встроенное кеширование на уровне nginx proxy

Минусы:

  • нет защиты от URL tampering

  • нет S3

Тестирование

Был собран docker-compose стенд (там можно найти все исходники), все что могло работать с кешом — было запущено в отдельных контейнерах:

  • thumbor настроен с файловым кешом

  • picfit настроен с файловым кешом

  • imageproxy настроен с in-memory кешом

Полный docker-compose.yaml:

version: '3.8'
services:
  imgproxy:
    image: darthsim/imgproxy:v2.17
    ports:
      - 8080:8080
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
    environment:
      - IMGPROXY_CONCURRENCY=1
      - IMGPROXY_USE_ETAG=true
  thumbor:
    image: minimalcompact/thumbor:7.0.0a5
    ports:
      - 8081:80
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
  thumbor-cache:
    image: minimalcompact/thumbor:7.0.0a5
    ports:
      - 8082:80
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
    environment:
      - RESULT_STORAGE_EXPIRATION_SECONDS=3600
      - RESULT_STORAGE_FILE_STORAGE_ROOT_PATH=/tmp/thumbor/result_storage
      - RESULT_STORAGE_STORES_UNSAFE=True
      - RESULT_STORAGE=thumbor.result_storages.file_storage
  imaginary:
    image: h2non/imaginary:1.2.4
    command: -enable-url-source -cpus 1
    ports:
      - 8083:80
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
    environment:
      PORT: 80
  picfit:
    build:
      context: .
      dockerfile: ./.docker/picfit/Dockerfile
    ports:
      - 8084:3001
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
    environment:
      - PICFIT_CONFIG_PATH=/config.json
  picfit-cache:
    build:
      context: .
      dockerfile: ./.docker/picfit/Dockerfile
    ports:
      - 8085:3001
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
    environment:
      - PICFIT_CONFIG_PATH=/config_cache.json
  imageproxy:
    image: willnorris/imageproxy:latest
    ports:
      - 8086:8080
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
    environment:
      - IMAGEPROXY_SCALEUP=true
  imageproxy-cache:
    image: willnorris/imageproxy:latest
    ports:
      - 8087:8080
    environment:
      - IMAGEPROXY_CACHE=memory:100:24h
      - IMAGEPROXY_SCALEUP=true
  weserv-images:
    image: ghcr.io/weserv/images:5.x
    ports:
      - 8088:80
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
  weserv-images-without-cache:
    build:
      context: .
      dockerfile: ./.docker/weserv-images/Dockerfile
    ports:
      - 8089:80
    restart: always
    deploy:
      resources:
        limits:
          cpus: 1
networks:
  default:
    driver: bridge
    ipam:
      config:
        - subnet: 172.10.10.0/24

Результаты

Выводы

Серебряной пули нет. Кто-то хорош в одном, кто-то в другом. Где-то есть кеширование, где-то его нет и тд.

На данный момент мы остановились на Imgproxy. Да, в ней нет кеширования готовых превьюшек, но там есть ETag/Cache-Control/Expires HTTP headers. Плюс есть возможность добавить watermarks и много чего еще. Да и обновляется регулярно.

P.S. Несколько слов про чтение оригиналов с S3 и по http: так как мы разворачивали Minio S3 рядом с генераторами превьюшек — разницы в производительности не было, от слова совсем.

PPS. Добавил weserv/images по просьбе @mazaxakon.

Всего голосов 7: ↑6 и ↓1 +5

  • 19 сентября в 22:12
    Всего голосов 35: ↑32.5 и ↓2.5 +30

    Просмотры 13K

  • 3 сентября в 09:11
    Всего голосов 11: ↑11 и ↓0 +11

    Просмотры 1.7K

  • 11 апреля в 16:07
    Всего голосов 12: ↑12 и ↓0 +12

    Просмотры 7.3K

  • сегодня в 02:30
    Всего голосов 146: ↑146 и ↓0 +146

    Просмотры 11K

  • вчера в 21:44
    Всего голосов 113: ↑111 и ↓2 +109

    Просмотры 15K

  • вчера в 22:44
    Всего голосов 110: ↑102 и ↓8 +94

    Просмотры 11K

  • вчера в 19:16
    Всего голосов 38: ↑38 и ↓0 +38

    Просмотры 1K

  • сегодня в 12:00
    Всего голосов 45: ↑41 и ↓4 +37

    Просмотры 3.8K

Source: habr1

Ну и напоследок напоминаю вам о нашем новом проекте vkserfing bot.