Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Como processar 6 milhões de imagens em uma noite

Como processar 6 milhões de imagens em uma noite

Tivemos que reprocessar todas as imagens do Elo7 para remover as malditas bordas arredondadas. Você vai ver como usamos o fantástico Sidekiq em 80 máquinas da Amazon EC2 provisionadas sob-demanda e os desafios técnicos de coordenar essa operação. Além de uma introdução ao uso de filas em aplicações.

D3ec0dda25b409d1c75525ad339ab8f6?s=128

Bruno Buccolo

April 13, 2013
Tweet

Transcript

  1. Bruno Buccolo @buccolo Como processar 6 milhões de imagens em

    uma noite.
  2. drmarket.com.br/portfolio

  3. None
  4. None
  5. None
  6. None
  7. #  product.css .product-­‐thumb  {    border-­‐radius:  15px;    .  .

     . }
  8. #  product.css .product-­‐thumb  {    border-­‐radius:  15px;    .  .

     . }
  9. #  product.css .product-­‐thumb  {    border-­‐radius:  15px;    .  .

     . }
  10. f(x) f(x) imagem  original

  11. f(x) f(x) imagem  original

  12. f(x) f(x) imagem  original Temos  que  gerar   esses  3

     tamanhos   sem  a  borda   arredondada.
  13. None
  14. Não  podemos  misturar  imagens   quadradas  e  arredondadas.

  15. Não  podemos  misturar  imagens   quadradas  e  arredondadas. Portanto,  trabalho

     noturno.  
  16. Não  podemos  misturar  imagens   quadradas  e  arredondadas. Portanto,  trabalho

     noturno.   6  milhões  de  imagens.
  17. Nos  tempos  obscuros  do  Elo7...

  18. Nos  tempos  obscuros  do  Elo7... As  imagens  de  produto  viviam

     no   banco  de  dados  MySQL  (blob).
  19. class  MoveImagesToS3    def  go_horse!        all_images  =

     load_image_list                all_images.each  do  |image|            #  get  from  mysql            #  upload  to  S3        end    end end Nos  tempos  obscuros  do  Elo7...
  20. class  MoveImagesToS3    def  go_horse!(range)        all_images  =

     load_image_list[range]                all_images.each  do  |image|            begin                #  get  from  mysql                #  upload  to  S3            rescue                #  sleep  /  retry            end        end    end end 10x Nos  tempos  obscuros  do  Elo7...
  21. 2  semanas,  fallback.js Nos  tempos  obscuros  do  Elo7... (window.onError)

  22. Como  paralelizar  o  trabalho? Como  garantir  a  confiabilidade? Como  trackear

     o  progresso? Nos  tempos  obscuros  do  Elo7...
  23. O  investimento  em  infra-­‐estrutura   geralmente  tem  um  bom  retorno.

    Lição  1:
  24. Solução

  25. Sidekiq •  Eficiente  (vs  20  Resques) •  Fácil  de  distribuir

     o  trabalho •  Tenta  novamente  o  que  falhar  (backoff) •  Interface  web  de  acompanhamento Simple,  efficient  message  processing  in  Ruby. @mperham
  26. None
  27. None
  28. convert_worker.rb xpto_worker.rb

  29. convert_worker.rb xpto_worker.rb

  30. enfileirador.rb convert_worker.rb xpto_worker.rb

  31. #  app/workers/convert_image_worker.rb class  ConvertImageWorker    include  Sidekiq::Worker    sidekiq_options  queue:

     :convert_image        def  perform(image)        #  download  original        #  convert  different  sizes        #  upload  all  to  S3        end end
  32. # enfileirador.rb all_images.each do |image| ConvertImageWorker.perform_async(image) end

  33. $  bundle  exec  sidekiq  -­‐C  config/sidekiq.yml #  config/sidekiq.yml -­‐-­‐-­‐ :verbose:

     true :timeout:  180 :concurrency:  10 :queues:    -­‐  [convert_image,  10]    -­‐  [xpto_queue,  1]
  34. enfileirador.rb convert_worker.rb xpto_worker.rb ? x

  35. jobs tempo 6.000.000 4 horas 1.500.000 1 hora 25.000 1

    minuto 417 1 segundo Qual  a  escala  do  problema?
  36. Amazon  EC2 máquinas horas custo 1 100 $10 100 1

    $10
  37. máquinas t1.micro m1.small c1.medium m1.medium m1.xlarge threads 5 .. 100

    barramento 32 ou 64 Qual  máquina  e  configuração?
  38. máquinas t1.micro m1.small c1.medium m1.medium m1.xlarge threads 5 .. 100

    barramento 32 ou 64 Qual  máquina  e  configuração? #hackday
  39. máquina t1.micro m1.small c1.medium m1.medium m1.xlarge Custo  /  Benefício

  40. máquina img/hora t1.micro 3036 m1.small 6072 c1.medium 17241 m1.medium 9554

    m1.xlarge 10416 Custo  /  Benefício
  41. máquina img/hora # maqs t1.micro 3036 494 m1.small 6072 247

    c1.medium 17241 87 m1.medium 9554 157 m1.xlarge 10416 144 Custo  /  Benefício
  42. máquina img/hora # maqs $/hora t1.micro 3036 494 0.02 m1.small

    6072 247 0.08 c1.medium 17241 87 0.165 m1.medium 9554 157 0.16 m1.xlarge 10416 144 0.64 Custo  /  Benefício
  43. máquina img/hora # maqs $/hora $ total t1.micro 3036 494

    0.02 39.53 m1.small 6072 247 0.08 79.05 c1.medium 17241 87 0.165 57.42 m1.medium 9554 157 0.16 100.48 m1.xlarge 10416 144 0.64 368.66 Custo  /  Benefício
  44. máquina img/hora # maqs $/hora $ total t1.micro 3036 494

    0.02 39.53 m1.small 6072 247 0.08 79.05 c1.medium 17241 87 0.165 57.42 m1.medium 9554 157 0.16 100.48 m1.xlarge 10416 144 0.64 368.66 Custo  /  Benefício
  45. Nem  sempre  vale  a  pena  testar   todas  as  possibilidades.

    Lição  2:
  46. máquina img/hora # maqs $/hora $ total t1.micro 3036 494

    0.02 39.53 m1.small 6072 247 0.08 79.05 c1.medium 17241 87 0.165 57.42 m1.medium 9554 157 0.16 100.48 m1.xlarge 10416 144 0.64 368.66 Custo  /  Benefício
  47. 87 máquinas c1.medium 32 bits 10 threads m1.medium Resultado

  48. •  Subir  e  configurar  uma  máquina •  Criar  uma  imagem

     dessa  máquina  (AMI)   •  Enfileirar •  Subir  80x  máquinas  usando  imagem •  Matar  80x  máquinas  no  EC2 boot git   pull sidekiq start Começando  o  processamento
  49. 3,  2,  1  ...  VAI!

  50. Accepting client connection: accept: Too many open files Accepting client

    connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files Accepting client connection: accept: Too many open files
  51. Accepting client connection: accept: Too many open files $  ulimit

     -­‐a core  file  size                    (blocks,  -­‐c)  0 data  seg  size                      (kbytes,  -­‐d)  unlimited file  size                              (blocks,  -­‐f)  unlimited max  locked  memory              (kbytes,  -­‐l)  unlimited max  memory  size                  (kbytes,  -­‐m)  unlimited open  files                                            (-­‐n)  2560 pipe  size                        (512  bytes,  -­‐p)  1 stack  size                            (kbytes,  -­‐s)  8192 cpu  time                              (seconds,  -­‐t)  unlimited max  user  processes                            (-­‐u)  709 virtual  memory                    (kbytes,  -­‐v)  unlimited $  ulimit  -­‐n  999999999
  52. [ec2-­‐user@worker:  ~]$  df Filesystem                 1K-­‐blocks 

           Used  Available  Use%  Mounted   /dev/xvda1                    8362320       418116    5506240   95%  / Disco quase cheio da máquina!
  53. Teste  e  monitore  a  sua  operação. Lição  3:

  54. Real  time  User  Monitoring  (RUM) “If  it  moves  we  track

     it.”
  55. None