Оптимизация одновременных запросов ImageMagick с использованием redis / php-resque

Я работаю над сайтом, который использует ImageMagick для создания изображений. Сайт будет получать сотни запросов каждую минуту, и с помощью ImageMagick это приведет к сбою сайта.

Таким образом, мы реализовали Redis и Php-resque, чтобы генерировать ImageMagick в фоновом режиме на отдельном сервере, чтобы он не разбивал наш основной. Проблема в том, что для получения изображений все еще требуется очень много времени. Пользователь может ожидать до 2-3 минут для запроса изображения, потому что сервер так занят обработкой этих изображений.

Я не знаю, какую информацию вам дать, но я больше ищу совет. Я думаю, что если мы сможем сократить начальное время процесса для запроса ImageMagick, то, очевидно, это поможет ускорить количество изображений, которые мы можем обработать.

Ниже приведен образец сценария ImageMagick, который мы используем:

convert -size 600x400 xc:none \( ".$path."assets/images/bases/base_image_69509021433289153_8_0.png -fill rgb\(255,15,127\) -colorize 100% \) -composite \( ".$path."assets/images/bases/eye_image_60444011438514404_8_0.png -fill rgb\(15,107,255\) -colorize 100% \) -composite \( ".$path."assets/images/markings/marking_clan_8_marking_10_1433289499.png -fill rgb\(255,79,79\) -colorize 100% \) -composite \( ".$path."assets/images/bases/shading_image_893252771433289153_8_0.png -fill rgb\(135,159,255\) -colorize 100% \) -compose Multiply -composite \( ".$path."assets/images/highlight_image_629750231433289153_8_0.png -fill rgb\(27,35,36\) -colorize 100% \) -compose Overlay -composite \( ".$path."assets/images/lineart_image_433715161433289153_8_0.png -fill rgb\(0,0,0\) -colorize 100% \) -compose Over -composite ".$path."assets/generated/queue/tempt_preview_27992_userid_0_".$filename."_file.png 

Моя теория заключается в том, что причина этого занимает довольно много времени из-за процесса окраски изображений. Есть ли способ полностью оптимизировать этот процесс?

Любой, кто имеет некоторый опыт работы с тяжелыми нагрузками процессов imagemagick или может увидеть некоторые очень простые способы оптимизации наших запросов, я был бы очень любезен.

Спасибо 🙂

Solutions Collecting From Web of "Оптимизация одновременных запросов ImageMagick с использованием redis / php-resque"

Ваша команда на самом деле сводится к следующему:

 convert -size 600x400 xc:none \ \( 1.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 2.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 3.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 4.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 5.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 6.png -fill rgb\(x,y,z\) -colorize 100% \) -composite \ result.png 

Мои мысли таковы:

Пункт 1:

Первый -composite на пустой холст кажется бессмысленным – предположительно, 1.png – это PNG 600×400 с прозрачностью, поэтому ваша первая строка может избежать операции компоновки и сэкономить 16% времени обработки, изменив на:

 convert -background none 1.png -fill ... -colorize 100% \ \( 2.png .. \( 3.png ... 

Пункт 2

Я поместил эквивалент вашей команды в цикл и выполнил 100 итераций, и это занимает 15 секунд. Затем я изменил все ваши чтения PNG-файлов на файлы MPC – или файлы Magix Pixel Cache. Это сократило время обработки до менее 10 секунд, то есть на 33%. Magic Pixel Cache – это всего лишь предварительно распакованный, предварительно декодированный файл, который можно читать непосредственно в память без какого-либо усилия процессора. Вы можете предварительно создать их, когда ваш каталог изменится и сохранит их вместе с файлами PNG. Сделать то, что вы делаете

 convert image.png image.mpc 

и вы image.mpc и image.cache . Затем вы просто измените свой код, чтобы выглядеть так:

 convert -size 600x400 xc:none \ \( 1.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 2.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 3.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 4.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 5.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \ \( 6.mpc -fill rgb\(x,y,z\) -colorize 100% \) -composite \ result.png 

Пункт 3

К сожалению, вы еще не ответили на мои вопросы, но если ваш каталог активов не слишком велик, вы можете поместить это (или эквиваленты MPC выше) на RAM-диск при запуске системы.

Пункт 4

Вы должны обязательно баллотироваться параллельно – это принесет наибольшую прибыль. Это очень просто с GNU Parallel – пример здесь .

Если вы используете REDIS, это на самом деле проще, чем это. Просто LPUSH свои MIME-кодированные изображения в список REDIS следующим образом:

 #!/usr/bin/perl ################################################################################ # generator.pl <number of images> <image size in bytes> # Mark Setchell # Base64 encodes and sends "images" of specified size to REDIS ################################################################################ use strict; use warnings FATAL => 'all'; use Redis; use MIME::Base64; use Time::HiRes qw(time); my $Debug=0; # set to 1 for debug messages my $nargs = $#ARGV + 1; if ($nargs != 2) { print "Usage: generator.pl <number of images> <image size in bytes>\n"; exit 1; } my $nimages=$ARGV[0]; my $imsize=$ARGV[1]; # Our "image" my $image="x"x$imsize; printf "DEBUG($$): images: $nimages, size: $imsize\n" if $Debug; # Connection to REDIS my $redis = Redis->new; my $start=time; for(my $i=0;$i<$nimages;$i++){ my $encoded=encode_base64($image,''); $redis->rpush('images'=>$encoded); print "DEBUG($$): Sending image $i\n" if $Debug; } my $elapsed=time-$start; printf "DEBUG($$): Sent $nimages images of $imsize bytes in %.3f seconds, %d images/s\n",$elapsed,int($nimages/$elapsed); 

а затем запустите нескольких сотрудников, которые все сидят там, выполняя BLPOPs заданий, чтобы сделать

 #!/usr/bin/perl ################################################################################ # worker.pl # Mark Setchell # Reads "images" from REDIS and uudecodes them as fast as possible ################################################################################ use strict; use warnings FATAL => 'all'; use Redis; use MIME::Base64; use Time::HiRes qw(time); my $Debug=0; # set to 1 for debug messages my $timeout=1; # number of seconds to wait for an image my $i=0; # Connection to REDIS my $redis = Redis->new; my $start=time; while(1){ #my $encoded=encode_base64($image,''); my (undef,$encoded)=$redis->blpop('images',$timeout); last if !defined $encoded; my $image=decode_base64($encoded); my $l=length($image); $i++; print "DEBUG($$): Received image:$i, $l bytes\n" if $Debug; } my $elapsed=time-$start-$timeout; # since we waited that long for the last one printf "DEBUG($$): Received $i images in %.3f seconds, %d images/s\n",$elapsed,int($i/$elapsed); в #!/usr/bin/perl ################################################################################ # worker.pl # Mark Setchell # Reads "images" from REDIS and uudecodes them as fast as possible ################################################################################ use strict; use warnings FATAL => 'all'; use Redis; use MIME::Base64; use Time::HiRes qw(time); my $Debug=0; # set to 1 for debug messages my $timeout=1; # number of seconds to wait for an image my $i=0; # Connection to REDIS my $redis = Redis->new; my $start=time; while(1){ #my $encoded=encode_base64($image,''); my (undef,$encoded)=$redis->blpop('images',$timeout); last if !defined $encoded; my $image=decode_base64($encoded); my $l=length($image); $i++; print "DEBUG($$): Received image:$i, $l bytes\n" if $Debug; } my $elapsed=time-$start-$timeout; # since we waited that long for the last one printf "DEBUG($$): Received $i images in %.3f seconds, %d images/s\n",$elapsed,int($i/$elapsed); 

Если я запускаю один генераторный процесс, как указано выше, и он генерирует 100 000 изображений по 200 кбайт каждый и читает их с 4 рабочими процессами на моей разумной спецификации iMac, это занимает 59 секунд, или около 1700 изображений / с могут проходить через REDIS.

Очередь обрабатывается по очереди за раз? Вы пытались выполнить параллельные задания, которые будут работать параллельно, поэтому вы будете работать сразу несколько элементов, если это так?