Программисты с Etsy.com поделились опытом, как им удалось эффективно решить задачу по пакетному ресайзингу фотографий с 1,5 Мб до 3 Кб (после смены дизайна оказалось, что старые превью-окошки не вписываются в новые шаблоны страниц). Задача не такая банальная, как кажется. Дело в том, что Etsy.com - крупный интернет-аукцион, и количество изображений различных товаров превышает 135 млн штук.
Ради шутки они прикинули, сколько займет эта работа вручную в "Фотошопе". Если на каждую фотографию отдать по 40 секунд, то выходит 170 лет непрерывного труда. Затем они начали считать, можно ли отдать пакет в облако EC2 и во сколько это встанет. Посмотрев на получившуюся сумму, программисты решили поискать другой способ.
В итоге им удалось завершить обработку 135 млн фотографий всего за 9 дней, задействуя четыре 16-ядерных сервера. Средняя скорость обработки составила 180 изображений в секунду.
Они использовали три инструмента.
- GraphicsMagick, это форк ImageMagick, который обеспечивает лучшую производительность благодаря поддержке многопроцессорной обработки. Гибкие параметры командной строки дают возможность тонкой настройки производительности.
- Perl. Казалось бы, куда без него. Но это вовсе не обязательный инструмент, потому что ребята не использовали библиотеку GraphicsMagick-Perl, а все команды написали вручную, и они могут быть написаны на любом другом языке.
- Система мониторинга Ganglia использовалась для построения графиков, чтобы визуализировать процесс и сразу понять, какое звено выполняет роль "бутылочного горлышка" и тормозит работу - поиск изображений, копирование файлов, ресайзинг, сравнение с оригиналом, копирование результатов обратно.
Чтобы настроить GraphicsMagick, сначала была сгенерирована тестовая страница с 200 изображениями разной степени сжатия, которую представили руководству. Они выбрали картинки приемлемого качества. Здесь очень важно, чтобы руководство не видело на странице информацию о параметрах компрессии каждой картинки, размерах файлов и т.д. (даже в именах файлов нельзя намекать на это) - тогда их решение будет полностью беспристрастным.
После этого было сделано сравнительное тестирование всех фильтров из комплекта GraphicsMagick на предмет того, какой из них обеспечивает чуть лучшее быстродействие.
Результирующие изображения должны были иметь размер 170 х 135 пикселов. В процессе тестирования было обнаружено, что ресайзинг предварительно уменьшенного изображения обеспечивает лучшее качество и более высокую скорость, чем ресайзинг непосредственно полноразмерного оригинала. Автор программы GraphicsMagick подтвердил это и посоветовал пользоваться функцией запроса уменьшенного изображения, которая поддерживается самим форматом JPEG.
Затем программу запустили для тестирования на реальных серверах и выяснилось, что "бутылочным горлышком" является вовсе не CPU, а файловая система (NFS seek time). Фактически, CPU был загружен всего на 1%. Пришлось переписать скрипт для запуска процессов по параллельному поиску фотографий - это значительно повысило производительность, до 15 изображений в секунду. Но этот результат опять же не может удовлетворить, потому что на такой скорости вся работа займет 104 дня.
Решили использовать 16-ядерный сервер Nehalem, но оказалось, что GraphicsMagick распарралелливает каждую задачу на 16 частей, а потом собирает их вместе. То есть он делает избыточную работу для каждой маленькой задачки - в результате скорость ресайзинга понизилась до 10 изображений в секунду. Пришлось менять настройки, и ситуацию исправили.
После этого провели еще один важный тест, чтобы определить оптимальное соотношение потоков в Perl (children) и GraphicsMagick (threads). Оказалось, что самая высокая производительность достигается при использовании двух процессорных ядер на задачу. Теоретически она составляет 140 изображений в секунду на одном сервере - расчетная скорость выполнения 11 дней. Это было то, что надо.
Процесс запустили на четырех 16-ядерных серверах Nehalem. В реальности скорость была не такой высокой - опять все тормозила NFS, но в сумме четыре сервера стабильно выдавали около 180 изображений в секунду.
Анатолий АЛИЗАР