O documento discute a evolução e otimização de um sistema legado de entrega de anúncios online chamado boo-box. O sistema cresceu 10x em um ano e passou por problemas de desempenho e escalabilidade que foram resolvidos através de monitoramento, redução de I/O, cache e desenvolvimento de um novo sistema chamado Shuriken.
3. Nelson Haraguchi - @nelsonmhjr
Desenvolvedor Ninja da boo-box desde outubro
de 2010.
Rubysta desde 2008.
Programador Web desde 2006.
Tenho cabelo comprido desde os
8 anos de idade.
4. Objetivo da Palestra
Transmitir a experiência de escalabilidade e performance que
temos de um sistema que cresceu 10x em um ano.
Performance vs Escalabilidade
Sistemas Legados
O sistema boo-box
Evolução do sistema boo-box e dicas de otimizações
Novo sistema boo-box
6. Performance vs Escalabilidade
Sistema que é rápido e Sistema que,
potente. independente do
Mas tem a limitação do crescimento do
“motor” do sistema. “trabalho”, entrega
Para aguentar o com a mesma
crescimento temos que performance, seja ela
trocar o “motor”. boa ou ruim.
14. Sistemas Legados
Mas isso só incomoda VOCÊ!
Para a maioria das pessoas o legado do sistema é
TRANSPARENTE
Cabe a nós medir, estudar e convencer de que
o sistema é Legado o suficiente para
valer ($$$) mais a pena desenvolver algo novo.
20. A boo-box trabalha para
gerar valor aos 150 mil sites
conteúdos produzidos e blogs
na internet brasileira,
fazendo a
28 mil
intermediação entre Publishers
grandes anunciantes e
os Publishers, os
formadores de opinião
65 milhões de
pessoas atingidas
da web.
30. Evolução do sistema
Primeiro Problema: Estatística Diária
O LOG era processado num batch diário
Chegou a demorar 8 horas para processar
um dia
Consequência: Campanhas com
otimização atrasada
Solução:
31.
32.
33. Evolução do sistema
Primeiro Problema: Estatística Diária
Triggers do MySQL processam as inserts e
geram estatística em tempo real.
Mas isso gerou outro problema: Inserções
demoradas
34. Evolução do sistema
Segundo Problema: Inserções Demoradas
Com as triggers as Inserts estavam
demorando e atrasando a request
Consequência: Aumento no tempo de
resposta
Solução: Separar a camada de log da
request
35.
36. Evolução do sistema
Segundo Problema: Inserções Demoradas
Instalamos Beanstalkd nos servidores de
aplicação, e eles são consumidos
separados da request.
38. Evolução do sistema
Terceiro Problema: Filas Atrasadas
Mesmo separado, não podemos deixar a
estatística atrasar tanto. Principalmente
quando dependemos dela para otimizar a
veiculação.
Solução:
39.
40. Evolução do sistema
Terceiro Problema: Filas Atrasadas
Com a Engine Blackhole do MySQL, as
triggers são executadas, mas os dados
não vão para o disco, assim é possível
gerar muito mais estatística.
Adicionamos um Slave para fazer o
storage do LOG
41. Evolução do sistema
Quarto Problema: Estatística Grande Demais
Com muitos GB de dados para ler e gerar
a estatística, otimizar a veiculação e gerar
relatórios começa a se tornar um
problema.
Solução:
44. Evolução do sistema
Quinto Problema: Latência de Arquivos Estáticos
Servidores lá fora, são mais baratos que
aqui. Mas isso tem um custo de latência.
Consequência: Ads demoram mais a
aparecer
Solução: CDN
45. Evolução do sistema
Sexto Problema: O crescimento da Rede
Não é bem um problema. Crescer é o que
queremos.
O sistema que processa a requisição é
escalável, mas precisamos adicionar mais
servidores.
Solução: Melhorar a performance
47. Evolução do sistema
Melhorar a Performance: Monitore
[287.2/s in last 5s: 1436 total:29353] DISPATCH: 0.01920s
[236.2/s in last 5s: 1181 total:30502] DISPATCH: 0.01861s
[272.8/s in last 5s: 1364 total:31834] DISPATCH: 0.02096s
[271.0/s in last 5s: 1355 total:33157] DISPATCH: 0.02142s
[271.4/s in last 5s: 1357 total:34482] DISPATCH: 0.02194s
[268.6/s in last 5s: 1343 total:35793] DISPATCH: 0.02069s
48. Evolução do sistema
Melhorar a Performance: Monitore
[40.8/s in last 5s: 204 total:204] DISPATCH: 0.06690s
[48.8/s in last 5s: 244 total:422] DISPATCH: 0.06430s
[46.0/s in last 5s: 230 total:626] DISPATCH: 0.07387s
[46.2/s in last 5s: 231 total:831] DISPATCH: 0.06803s
[40.2/s in last 5s: 201 total:1006] DISPATCH: 0.07426s
[43.0/s in last 5s: 215 total:1195] DISPATCH: 0.06251s
[106.6/s in last 5s: 533 total:533] DISPATCH: 0.02058s
[141.6/s in last 5s: 708 total:1213] DISPATCH: 0.02255s
[138.0/s in last 5s: 690 total:1875] DISPATCH: 0.02035s
[146.0/s in last 5s: 730 total:2577] DISPATCH: 0.01853s
[144.4/s in last 5s: 722 total:3271] DISPATCH: 0.02036s
[147.6/s in last 5s: 738 total:3981] DISPATCH: 0.02013s
49. Evolução do sistema
Melhorar a Performance: Monitore
Call Hits Avg. Time
get_compatible_ads 16 0.23063
Saving on beanstalk 905 0.00792
validate_realtime 400 0.00561
get_optimized_ad 357 0.00418
get_compatible_ads cached 384 0.00370
51. Evolução do sistema
Melhorar a Performance: Reduzir I/O
Revisão de Querys
Máquina Nova (ORM)
52. Evolução do sistema
Melhorar a Performance: Reduzir I/O
Cache (Memcache/Redis) é I/O
53. Evolução do sistema
Melhorar a Performance: Reduzir I/O
Um quarto das chamadas
54. Evolução do sistema
Melhorar a Performance: Reduzir I/O
Otimização do uso
Substituir do Cache
Memcached por
Redis.
Cachear o máximo
possível de uma
vez.
55. Evolução do sistema
Melhorar a Performance: Reduzir I/O
Usando MGET
No Redis
56. Evolução do sistema
Melhorar a Performance: Outras Otimizações
- Reduzir a Latência entre servidores
- Reduzir Loops do sistema
- Substituir Arrays por Hashs (ou Sets)
São otimizações que economizam muito pouco
58. Evolução do sistema
Melhorar a Performance: Ruby 1.9
O sistema não é compatível com Ruby
1.9 devido a depêndencias (gems).
Essas gems não são utilizadas no
processamento da requisição.
Solução: Implementar um novo
sistema!
60. Novo sistema
Porquê Desenvolver um Novo Sistema?
Separar o código da veiculação do resto do
sistema. (site e admin)
Conseguir testar outras VMs como JRuby,
Rubinius, YARV...
Garantir o funcionamento daquilo que não pode
ficar down.
Refatorar, Otimizar e Repensar a Arquitetura
sem se preocupar com o resto do sistema.
62. Novo sistema
1º Separar o código que precisa escalar!
Crie Testes! O Máximo possível, e migre o
teste primeiro.
Não Refatore! Pois parte da sua lógica
pode se perder.
No nosso caso reduzimos também o stack, e
objetos em memória cortando o Merb e usando
o Rack direto.
63. Novo sistema
2º Desenvolva Incrementalmente!
Separamos as Visualizações de Vitrines de
Ads que compõe 95% da nossa veiculação e
portamos primeiro.
Estamos em processo de portar as
Visualizações de Vitrines de Produtos, e
depois portaremos os cliques, e conversões.
65. Novo sistema
3º Teste Exaustivamente!
Reproduzimos um dia inteiro de requests no
sistema até que ele não gerasse erros.
Testamos também a geração de Logs e
consumo das filas.
Nota: Marshal is evil
66. Novo sistema
4º Coloque em produção!
Coloque-o em produção aos poucos para
garantir a confiabilidade.
Problemas vão acontecer!
O Shuriken subiu com Passenger e com
Unicorn, e tivemos problemas
67. Novo sistema
4º Coloque em produção!
Problemas com
Passenger
CPU Leak?
Unicorn
O problema
voltou
após um
reboot
68. Novo sistema
5º Não Jogue Fora o seu Legado!
O sistema legado deve continuar em uso, por um
bom tempo até o amadurecimento do novo
sistema.
Otimizações no Shuriken são portadas para o
legado.
Testes alcançam 100% de cobertura.
Refatorações são feitas.
O sistema legado é desligado.
69. Novo sistema
6º Repense a Arquitetura de modo Escalável!
Um sistema deve ter camadas bem definidas.
(Load Balancer, Aplicação, Cache, Database, Log,
etc...)
Cada camada deve ter sua própria estratégia de
REDUNDÂNCIA (prestando serviços) e
TOLERÂNCIA A FALHA (consumindo serviços).