Опытным путем, я установил, что способ работы с изображением на сайте – лакмусовая бумажка качества. Посмотри как человек работает с изображениями в пяти размерах и можно сделать вывод обо всем проекте. Причина вполне понятна, я не встречал книги или статьи, где описана логика хранения, обновления и работы с изображением, если кто-то укажет её в комментариях – буду признателен. Каждый придумывал свой велосипед сервисов, который умел сохранять по определённой структуре каталогов или в базе. Шло время, сайты на поддержке развивались, где-то менялись размеры изображений, где-то добавлялся новый функционал, который требовал нового размера ранее загруженных изображений. Каждый шаг добавлял новый виток уже отлаженной процедуры: походим по всем изображениям – оригиналам, меняем размер и сохраняем в нужных параметрах. Долго, дорого.
Ручное управление рано или поздно приведет к сбою, потребует лишних денег для проверки в тестовой среде. Я приступил к поиску подобной проблемы у других, ведь давно известно, что если у тебя какая-то проблема, то ты не первый, кто с ней столкнулся. Достаточно быстро я вышел на облачные сервисы изменения изображений, кэширования и размещения. Я был восхищен простотой решения, используя ссылку на оригинал изображения и управляющие параметры в ней можно получать обрезанные, сжатые, перевернутые, сдвинутые, прозрачные, изображения с нанесенным текстом и эффектами и многое, многое другое. Один из таких сервисов, показавшийся мне наиболее простым и удобным, я решил опробовать. Для этого я составил список необходимого мне функционала и решил снять временные характеристики, ведь ни для кого не секрет, что скорость работы сайта является очень важным параметром с точки зрения пользователя и поисковых систем.
Примерный список по памяти:
- Изменение ширины, пропорциональное изменение высоты.
- Изменение высоты, пропорциональное изменение ширины.
- Обрезка изображения в заданных границах.
- Вписывание изображения в границы прямоугольника.
- Кэширование и хранение результатов на стороне сервиса, при этом его регулярное обновление в зависимости от ETag и MaxAge.
- Время получения измененного изображения новым пользователем из России.
- Доступность https.
- Приемлемая цена сервиса и прозрачность его оплаты.
Я прошелся по функциональным требованиям, каждое из них было отражено с примером использования и полностью устраивало, была краткая инструкция по использованию и небольшая панель управления для наблюдения за статистикой и уменьшением баланса.
Параллельно я смотрел скорость и, сказать честно, я не ожидал хороших результатов по скорости, так как на карте расположения серверов обработки и хранения России не оказалось. Но раньше замечал, что скорость в Европу и США бывает значительно лучше, чем до соседнего города, потому решил проверить. Результаты оказались приемлемыми, около 35-60 ms на изображение при изменении ширины изображения с 3000 до 500 и 30-150KB результате.
Дальше кэширование было основано на MaxAge и Last-modified, ETag отсутствовал и никак не транслировался с исходного сервера хранилища, но я не смог придумать ситуации, когда он может понадобится, если есть Last-modified. MaxAge, при правильной настройке, спокойно перетекал на сервис. Мне стало интересно, каким образом сервис отрабатывает изменение оригинального изображения на сервере хранилище. В голове было три алгоритма, по первому он должен был перед тем, как вернуть изображение – обратиться к исходному хранилищу и посмотреть у него Last-modified, по второму он должен был в фоне сравнивать информацию о том, что хранится на сервисе и у хранилища раз в какое-то время, например, полученное через MaxAge и третий, когда следующее обновление назначалось через MaxAge, но происходило только если клиент делает запрос. Решил установить простым экспериментом, изменив оригинал и запросив от сервиса изображение. Тогда я обнаружил, что изображение не изменилось, значит сервис не обращается к хранилищу до определенного момента. При этом если изменить изображение снова, то оригинальное изображение будет взято из кэша сервиса, а не с хранилища. Дальше, меняя MaxAge, я добился обновления оригинального изображения в кэше сервиса.
В моем списке цена стояла на последнем месте по порядку, но не по приоритету. Я был неприятно расстроен ценой (цены привожу на сегодняшний день) от 500$ за план с SLA, при этом план по количеству доступов к оригинальному изображению тоже устраивал плохо, каждая 1000 изображений оплачивалась отдельно. При этом было непонятно, как считаются доступы к оригинальному изображению. Считается ли доступом повторный запрос ранее измененного изображения из кэша сервиса, без использования кэша браузера, т.е. новым пользователем, но раньше кто-то его уже вызывал и изменил. Вопрос этот возник потому, что у нас на одном из проектов было больше 150 новых оригинальных изображений каждый день, которые просматривали не менее 5 тысяч человек ежедневно. На запросы из кэша приходились только ~50% запросов. Ответ был простым, после загрузки в кэш сервиса изображения, все операции с ним безлимитные и ограничение только по расходуемому трафику. Прикинув количество изображений выходило порядка 150 долларов ежемесячно без учета трафика.
Все бы хорошо, но настал 2014 год и доллар стал уверенно преодолевать границы разумного, доброго, вечного. Бабло начало побеждать зло и было принято решение, создать свой сервис по изменению изображений налету. Так появился внутренний проект, а недавно (около года назад) я и команда опубликовали бета версию для публичного тестирования. Сервис построен с использованием технологий Microsoft .NET, и NoSQL Redis для кэширования оригинальных изображений. С нами работают разные страны, в совокупности около 15 сайтов. Один из наших клиентов, сайт из Вьетнама популярной вьетнамской музыки, насколько мы можем судить, откуда он узнал о нашем сервисе до сих пор остаётся загадкой. Посещаемость каждого из сайтов от 50 до 30 000 человек в день. Наша целевая аудитория это относительно небольшие (до 50 000 – 100 000 человек в день. Размер оригиналов изображений до 10MB каждого, ограничен внутри системы) информационный сайты, интернет-магазины, каталоги продукций и просто сайты с отзывчивым дизайном и желанием уменьшить трафик или восполнить пробелы с пережатием изображений в старом IE.
Архитектура
Первой версией проекта была прямолинейная обработка, никакой авторизации и полная свобода действий для пользователей сервиса. Скажу сразу – это плохая идея, по всем параметрам кроме удобства пользователя, пока сервис не упадёт под нагрузкой недобросовестных пользователей или напрямую нарушающих законодательство. Лучше всего это показать на схеме и обозначить основные компоненты.
Всю статистику запросов, все параметры кэширования мы хранили на Redis. Там же хранили оригиналы и обработанные файлы, потому что хотели добиться максимальной скорости отдачи контента пользователю, минимизировав участия дисков. Запустив наш прототип, поняли, что он вполне жизнеспособен и покрывает требования по одному из сайтов с лихвой (5 000 — 10 000 пользователей в сутки). Разместили на собственном железе, приступили к использованию. Проблемы начались, когда мы захотели масштабироваться. Не потому, что мы получили какой-то предел решения, а потому, что к нам начали проявлять интерес другие клиенты и мы стали опасаться, что не справимся с нарастающей нагрузкой.
Так родилась вторая версия сервиса. Версия, построенная на очереди поверх Redis и микросервисах, слушающих события этой очереди. Фасад остался за IIS, но сильно похудел и стал проксировать запросы к нужным сервисам. Появились ограничения как на количество файлов, так и на их размер, привязка к доменному имени, чтобы избежать недобросовестных пользователей и указать владельца соответствующим структурам, в случае их интереса. Появился DNS с Round Robin и возможностью выдавать адреса относительно предполагаемого адреса клиента (CDN).
Схема позволила нам разнести сервисы обработки, дублировать их с точки зрения отказоустойчивости и производительности, независимо отправлять в обслуживание конечные точки без остановки всей системы. Более того, сервисы перестали быть географически привязанными.
Вторую версию сервиса мы продолжаем развивать. Мы очень хотим получить от пользователей обратную связь. У нас есть список возможного развития, с новыми функциональными возможностями:
- Нанесение текста на изображение — уже реализовано
- Установка качества в контексте домена, правил и/или операции (сейчас это жесткое значение OptimalCompression)
- Добавление выбора системы — плана кэширования оригинальных изображений
- Добавление источников, отличных от сайта (например Amazon или новоиспеченный Mail с его холодным хранилищем)
- Размещение дополнительных сервисов за пределами центрального региона
Нужно – не нужно, важно – не важно, поэтому при регистрации выдается план Early Adopter, с 500MB хранилища, до 5 доменов, 2000 оригинальных изображений. Он останется с вами, только если вы не удалите аккаунт (это можно сделать самостоятельно из панели управления в любой момент времени). Все предложения можно и нужно отправлять по контактам поддержки или в комментариях тут. Учитывайте, что план Early Adopter гибкий и, если вам необходимы большие масштабы, просто напишите в поддержку. Высока вероятность, что вам помогут. Также если интересно, как какая-то из частей устроена внутри – пишите. Я постараюсь ответить на все вопросы, где-то просто привести примеры кода.
Спасибо!
Контакты. Я старался подойти к статье объективно, не нарушать правила топиков и рекламы, чтобы поделиться с вами своими мыслями о простоте подхода. Больше вам спасибо за внимание и время. Контакты сообщу в личном сообщении или комментарии, при наличии интереса.
Комментарии (18)
technik
08.04.2018 22:10Скажите, а на вашем сервисе можно решить не менее актуальную задачу по сжатию изображений?
В частности имеется допустим много папок на нескольких доменах, с кучей изображений размером примерно под 10 Гб на каждом и нужно их сжать максимально, чтобы оптимизировались под проверку по Google Page Speed и GTmetirx.
Также следить за актуальностью и допустим раз в сутки увидеть новые файлы и аналогично сжать их.
Я знаю что есть подобные сервисы, но при текущих объёмах (и курсе доллара) суммы получаются какие-то очень внушительные.vladimirkolyada Автор
08.04.2018 22:17Нет, к сожалению пока нет такого параметра, как quality, но вопрос интересный. У вас они в разных форматов? У нас основной кейс это кэширование пережатых изображений, а вот просто компрессии нет. Плюс сами мы не можем узнать, появились у вас файлы или нет, т.е. запрос всегда идёт от клиентов, по сути — их браузеров. Первый запрос строит изображение, остальные его из кэша подтягивают, который с использованием ETag и Last-modified обновляется. Те сервисы, что я встречал и искал, все равно работали по запросу клиента. Но каждый из них имел тот или иной API, можно соответственно вызывать его скриптом, а не браузером. В любом случае писать что-то. Я не подскажу универсального рабочего решения к сожалению.
mgremlin
09.04.2018 18:54Интересуюсь ссылкой.
В принципе, у меня реализован собственный велосипед, между делом кроющий cloudinary :-) но всегда интересно посмотреть на чужое решение.
Тем более — на .NET и IIS (?!). Мы-то на go морочились, чтоб это пошустрее работало…
Насчет серверов — интересная тема: наш милтер картинок живет во франкфуртском ДЦ DO, оригиналы хранятся на AWS в германии же, и сколько мы ни пытались обработку/кэш перенести в РФ — ни черта не получилось. Тупо о-о-чень ме-е-едленно… В смысле, после прогрева кэша — все чудесно за счет меньшего пинга, но когда картинку надо выдрать из S3 для обработки — очень все плохо. Возникает ощущение, что наши компании, предоставляющие сервис VPS, экономят на аплинках в европу(?).
Ждем AWS или DO в России.vladimirkolyada Автор
09.04.2018 19:30Да, на .NET и IIS. Нас не очень волнует первичная обработка, основной кейс работы заключается в том, что картинка создана, она лежит на Redis и отдается исключительно от туда, там же в фоне мониторинг и обновляется по мере необходимости. Ну и по верх этого панель прикручена, с графиками и небольшой статистикой, для понимания. Ссылка imagecdn.ru статья с главной ушла, надеюсь не сочтут за рекламу, уже больше суток прошло. У вас именно проблема в загрузке с AWS, тут надо искать каналы, которые позволят получить достойную скорость, возможно в каких-то ДЦ он и будет в России.
mgremlin
09.04.2018 20:18Спасибо, посмотрю.
vladimirkolyada Автор
09.04.2018 20:38Можете попробовать каналы у мэйла (mail.ru), они тут свой ДЦ для других открыли, публичный доступ и дают 3000р на тестирование. Там и хранилища есть, виртуалки можно развернуть, все по взрослому, но сам не пробовал. Зарегистрировался, но пока не использовал, вот хочу инстансы пары сервисов там запустить ради эксперимента.
mgremlin
10.04.2018 10:10Дорого у мэйла, я видел релиз про облако.
Я кучу разных пробовал, последний, например, vscale селектеловский.
Всем хороши парни, можно бы их рекомендовать, но вот в данном аспекте полный швах.
mgremlin
10.04.2018 14:43Знач, так, отчитываюсь.
попробовать не удалось: не работает, множественные проблемы.
1. с главной ссылка на cp дает 404. при исправлении руками схемы на http прокатывает, можно регнуться. И даже добавить домен.
2. Но даже при этом условии отдает XML
<Error><Message>An error has occurred.</Message></Error>
картинку тестил вот такую:
У меня ее вертит как хошь с каменным лицом.vladimirkolyada Автор
11.04.2018 09:21Спасибо! Все просто, вы не подтвердили домен, в cp.imagecdn.ru в таблице доменов первая колонка, солнышко должно превратиться в галочку. Для этого нужно кликнуть на галочку, вернется файл, который нужно бросить в корень домена для подтверждения. Потому вам и возвращается ошибка. А вот с https спасибо, действительно, сертификата на панели нет, что более чем плохой тон, я этот вопрос решу на днях, а на корневом домене наверняка ссылка стоит вида \\:domainname, потому он и схватил https. Такая мелочь и так неприятно в результате.
П.С. Когда мы делали сервис, нам показалось что самое простое верифицировать его через файл на хосте, заморочки с DNS как-то сложнее, а файл с хэшем бросил и бросил себе, тем более после подтверждения его сразу можно удалить.mgremlin
11.04.2018 11:49Ну а я вот хотел попробовать картинку из инета. Это чужой домен, просто там картинка красивая и удобная. Но даже если бы я использовал большинство своих — у меня тупо нигде нет возможности быстро положить файл и отдать его из корня: везде сплошные прокси на апп сервера, nginx, в лучшем случае — статик генераторы с фиксированным деревом.
Или вот я бы мог использовать какой-нибудь свой S3, так там тоже в корень ничего не добавишь.
То есть, просто для того, чтобы потестить latency и качество обработки изображения мне надо:
1. продраться сквозь дебри регистрации на сайте
2. добавить домен, причем, несмотря на мой более чем 30летний опыт разработки, я не сумел сразу сделать этого правильно
3. зайти на VPS sshем, поменять конфиги вебсервера, уложить в специально созданный корень этот файл.
4. положить в корень этому домену картинку или настроить прокси
Не крутовато ли? Просто чтоб попробовать?
Ну уж сделали бы счетчик, что ли — 3 картинки (или 30) отдаем без регистрации… Да и все остальное, имхо, избыточно. Вот лично я даже по описаниям и прочему не увидел явного преимущества перед тем же Cloudinary, а если еще и просто попробовать настолько непросто… Или вы так, чисто теоретически хвастаетесь, а какое-либо использование не планируется?
vladimirkolyada Автор
11.04.2018 10:11Все, теперь сайт доступен по https с правильным сертификатом. Если активируете домен и попробуете — буду признателен.
vladimirkolyada Автор
09.04.2018 19:34А как вы обрабатываете? Первичная обработка, нет картинки в кэше. Прямо пришел запрос — обработали — сразу отдали? Или как-то интереснее? Волнует меня тема эта.
mgremlin
09.04.2018 20:17Ну а как еще можно?
Пришел запрос на thumb, если в кэше нет — отдали на бэкенд. Он проверяет кэш оригиналов, если есть — обрабатывает оригинал из кэша. Если нет, вытягивает картинку из AWS, сделал с ней что надо, отдал. И оригинал, и обработанный экземпляр кэшатся.
ну там много всякой мути по дороге…
Да, ессно, кэши разные: оригиналы кэшатся ненадолго, в расчете на то. что если кто-то запросил один размер, то есть большой шанс, что ему и другой размер той же картинки понадобится. А вот уменьшенные варианты кэшатся всерьез.vladimirkolyada Автор
09.04.2018 20:33Можно это делать синхронно, на общий бекенд, мы так делали изначально. А можно асинхронно разными способами, например у нас событие просто IIS примет, создаст задание и отправит его на выполнение и будет ждать события о том, что выполнилось все и тогда получит изображение из кэша. Т.е. не результат обработки от сервисов обработки, а именно от сервисов кэша, туда же перед тем как маякнуть событием об окончании той или ной обработки, положил его обработчик, допустим CropHandler. Вариантов по сути масса. Мы делали это для распределения нагрузки по нескольким серверам независимо, без балансировки нагрузки на базе бекенда, т.е. выбора при синхронном запросе одного из набора сервисов — обработчиков.
vladimirkolyada Автор
09.04.2018 20:36А еще мне нравится, когда разносортные сервисы через общую шину решат задачи независимо, при этом можно отключать то одни, то другие, а система устойчиво работает, забавно, как живой организм.
mgremlin
10.04.2018 10:08Допускаю, что это вопрос важный, хотя ни разу у нас не возникало какой-то очереди. Обработчик всегда совершенно пустой, хотя это самый дохлый и дешевый дроплет DO.
ADSoft
Это все хорошо и замечательно — но при использовании сторонних сервисов основные проблемы:
vladimirkolyada Автор
Меня лично, как пользователя, больше заботит доступность сервиса 24/7, а не работа раз от раза. Если происходят какие-то проблемы — знать о них. Если я хочу что-то сказать — чтобы меня услышали.