29 of maio de 2009

A infraestrutura de servidores Web do Sistema boo-box

Institucional, Tecnologia Postado por

Nos últimos anos uma série de padrões de arquitetura de softwares web se consolidaram e foram popularizados em frameworks que facilitam o desenvolvimento e a manutenção destes sistemas. Ao mesmo tempo, servidores tiveram o custo reduzido e o acesso facilitado. Criar um projeto web se tornou mais simples, ágil e barato, mas se ele prosperar será preciso lidar com um velho desafio: escalabilidade.

A boo-box passou por esse desafio e hoje possui uma infraestrutura em camadas, capaz de escalar horizontalmente e que hoje tem robustez pra servir milhares de requisições por minuto. Neste post iremos apresentar algumas soluções usadas atualmente pra garantir boa performance do Sistema de Publicidade Para Mídias Sociais, como Ruby, MERB, CouchDB, Thin, Nginx, Beanstalkd.

Screenshot do glTail rodando no server Kami

A infra boo-box

Nossa infraestrutura é uma combinação de softwares Open Source consolidados há anos, como MySQL, com outros mais recentes e pouco usados, que em geral consomem menos recursos, são mais simples ou apenas mais adequados à situação.

É importante salientar que este texto reflete a situação da infraestrutura atual (maio de 2009). A taxa de novos Publishers associados ao Sistema e crescimento de visitação dos Publishers já associados nos leva a alterar semanalmente a estrutura de servidores, adicionando novas máquinas ou modificando componentes da aplicação.

 

Identificação dos servidores

Nomear servidores sempre é uma decisão difícil para o time de desenvolvedores, alguns usam nomes de planetas, elementos da tabela periódica, nomes de letras gregas. Nós usamos nomes de personagens do anime Dragon Ball Z.

Static Files

Arquivos estáticos são os que não dependem de processamento do servidor, como imagens, CSSs, JavaScripts. Na estrutura boo-box eles ficam em um subdomínio que aponta diretamente para um servidor dedicado, diminuindo a carga dos nossos load balancers.

Os arquivos estáticos são carregados previamente para a memória RAM, melhorando o tempo de resposta do Sistema. Esta máquina roda o servidor HTTP nginx.

Load Balancers

São as máquinas que recebem as requisições dos usuários e direcionam a carga para um dos servidores de apliçação. Na infra boo-box há dois load balancers, ambos associados ao DNS para boo-box.com

O load balancer precisa responder muito rapidamente, por isso ele não processa regras de negócio. Cada um dos servers roda o servidor HTTP nginx.

Cluster de aplicação

O cluster de aplicação é composto pelo conjunto de servidores que processam nossas regras de negócio. São eles que decidem que anúncio será exibido na vitrine, o que acontece quando há um clique, o que fazer com os dados de novo Publisher cadastrado no Sistema.

Cada server roda aproximadamente 100 instâncias do framework Ruby MERB com o servidor HTTP Thin (não, nós não usamos RubyOnRails :).

Cluster de banco de dados

Quando uma informação precisa ser gravada em nosso sistema, como novo Publisher cadastrado, alteração nas preferências, ou exclusão de anunciante, esses dados são guardados em nosso banco de dados.

O cluster de banco de dados contém a máquina Vegeta (Master), que recebe as informações a serem gravadas no banco, e máquinas secundárias Bulma e Ubb (Slave) de onde os servers de aplicação lêem os dados.

Como notado por um leitor do blog, o nome do personagem é Uub, mas o ninja que batizou o server precisou digitar o nome usando os pés porque nossos braços estavam estendidos pra cima energizando uma Genki Dama, digitar com os pés é difícil, ele errou a tecla e o nome server e ficou Ubb mesmo :)

Dividir escrita e leitura em diferentes servidores foi uma das mais eficientes atitudes que tomamos nos últimos meses pra melhorar performance e uptime do Sistema boo-box.

Este cluster roda um banco MySQL, dividido entre os servidores segundo escrita e leitura.

Um caso real de uma empresa contribuindo com a comunidade de Software Livre :)

Usamos o Sequel como ORM na comunicação entre aplicação e banco de dados. Quando precisamos replicar o banco, gerando a estrutura de Master e Slave, o Sequel não conseguia ler do Slave, por mais que fizéssemos tudo conforme a documentação.

Entramos em contato com os desenvolvedores do ORM no canal de IRC e, após algumas horas de testes, resolvemos o problema em conjunto.

Este é apenas o mais recente dos casos, nós já contribuímos com a comunidade de Software Livre de diferentes maneiras, fazemos isso porque temos consciência que nossa tecnologia é fruto do Open Source.

Cluster de log do Sistema

Todas as ações ocorridas em nosso Sistema são gravadas no log do Sistema. Vitrines visualizadas, cliques em anúncios, ações efetuadas em sites de parceiros, tudo fica no log.

Periodicamente processamos o log raw (cru), geramos estatísticas e fazemos um backup. Com isso liberamos o log raw para receber mais dados sem perder as informações do passado e mantendo uma boa performance no Sistema.

Usamos o Analogger como componente de log, porém, questões de performance e escalabilidade fez com que buscássemos outra solução. Atualmente o log do Sistema está sendo migrado para estrutura MySQL, e é dividido em máquinas Master (escrita) e Slave (leitura).

Cache de produtos

A maior parte dos anúncios exibidos nas vitrines boo-box são produtos ofertados por e-commmerces. Como as informações dos produtos não precisam ser mantidas ao longo do tempo fazemos um cache temporário dos dados.

O cache confere robustez ao Sistema, que continua funcionando mesmo que o e-commerce demore pra responder ou saia do ar.

Nossa estrutura de cache de produtos é formada por dois componentes principais:

Fila

Usamos Beanstalkd como serviço de fila para requisições de produtos. Cada vitrine boo-box tem tags associadas, cada nova tag ainda não cacheada é inseria nesta fila que será consumida nos próximos segundos, não atrapalhando o fluxo de funcionamento da aplicação.

Há um serviço independente que consome a fila, indo nos e-commerces procurar pelos produtos relacionados com cada tag e colocando os dados nas máquinas de cache.

Cluster de cache de produtos

Cada servidor que armazena dados de produtos roda CouchDB, um banco de dados de documentos JSON.

O principal recurso consumido por estas máquinas é espaço em HD, lotamos centenas de gigabytes em poucos dias, principalmente por conta da heterogeneidade das ofertas exibidas no Sistema boo-box, são milhões de produtos diferentes.

O resultado

Screenshot do glTail rodando no servidor Korin

Nas últimas semanas o tempo de resposta e uptime do Sistema boo-box melhorou visivelmente por conta das soluções acima apresentadas, resultado do trabalho e experiência dos ninjas.

Se você tem alguma crítica, dúvida ou sugestão, estamos sempre dispostos a ouvir, a caixa de comentários é pra você :)

Post escrito por Marco Gomes e Mauricio Maia.

  1. Dirceu Jr. | maio 29, 2009 @ 17:59 - Responder

    Caramba! Cresceu o bixin, ehehe.
    Estão de parabéns ;D

    Ein, agora com Ruby 1.9 não tem mais lock global do interpretador e threads são eficientes. Acho que não precisaria mais desse absurdo de servidores de aplicação (100 instâncias Thin em 1 server eu já achava muito).

    Com menos instâncias diminui também o número de conexões (sockets) com as outras partes da aplicação (beanstalkd, mysqld, analogger, couchdb)…

  2. DBZ Fan | maio 29, 2009 @ 18:17 - Responder

    O nome do personagem eh Uub e nao Ubb.

  3. Marco Gomes | maio 29, 2009 @ 18:41 - Responder

    @dbzfan: Pronto, fiz uma errata no texto explicando o porque do nome ser Ubb e não Uub ;)

  4. Felipe Hummel | maio 29, 2009 @ 20:05 - Responder

    Opa Marco!
    Fiquei com uma dúvida. Vocês contratam algum host privado? Ou já tem o próprio “data center” de vocês?

    Gostei como vocês separaram cada parte em um VPS separado.

    Abraço!

  5. Diego Sana | maio 29, 2009 @ 20:10 - Responder

    Marco e Maurício: obrigado por compartilharem suas soluções. Esse é um assunto que muito me interessa por eu já ter precisado montar uma estrutura assim e estar no momento tentando projetar a infra pra uma nova web app que estou desenvolvendo e que vai ser write-heavy. Uma curiosidade: vocês poderiam dizer quantas requisições servem por dia e o número de QPS nos horários mais críticos?

    Quanto a sua infra-estrutura, alguns comentários:

    – Por que vocês não usam o memcache? Talvez o fato de que “lotamos centenas de gigabytes em poucos dias” torne muito caro fazer todo o cache em memória, mas deve haver alguns datasets de uso mais frequente que caibam em RAM e possam beneficiar a performance de sua aplicação, já que o memcache (principalmente se usado com o build liberado pelo facebook) é claramente muito mais rápido que o couchdb.

    – Vocês já consideraram o mongodb? Tenho estudado ele bastante e os testes estão me animando muito. Até pela descrição dada pelos próprios desenvolvedores dele, o mongodb me parece uma solução mais apropriada (em relação ao couchdb) tanto para o cache de produtos quanto (em relação ao mysql) para seu cluster de log de sistema.

    – Vocês chegaram a tentar fazer sharding de suas databases mysql e distribuir diferentes databases por diferentes servidores? Na aplicação que desenvolvi (flogão, com escrita intensiva), um cluster com quatro servidores mysql com databases distribuídas tinha performance muito superior a um cluster com um master e três slaves. Fazer isso adiciona certa complexidade na aplicação, mas talvez seja interessante pra vocês estudarem essa possibilidade com carinho, porque pode chegar o dia em que seu master vai começar a não dar conta das escritas (como o meu master não dava), e aí esse esquema de replicação vai se complicar.

    – Uma última curiosidade: que versão e que storage engine do mysql estão usando? Já deram uma olhada nos patches de alta performance e no xtradb, ambos da percona?

    Abs.

  6. Marco Gomes | maio 29, 2009 @ 20:11 - Responder

    @felipe: Todos os slices descritos aqui ficam na Slicehost, um hosting que é da Rackspace e provê VPSs confiáveis e com preço justo. Tudo intermediado e administrado pela Vilago do @crisdias ;)

  7. Maurício Maia | maio 30, 2009 @ 13:43 - Responder

    Diego,

    – Nós usamos memcached entre os bancos MySQL e a aplicação, mas seguimos a linha (do Flickr) de que o banco de dados precisa dar conta sozinho. O memcached é só uma forma de diminuir a latência.

    – Estamos considerando o mongoDB sim. Fizemos um pequeno teste com ele e nas próximas semanas vamos ver como ele se sai no lugar do CouchDB. Sobre os logs, preferimos seguir com o MySQL pois é uma parte muito importante para o negócio da boo-box. Para logs menos críticos o mongoDB seria uma ótima opção.

    – O sharding do MySQL será o próximo passo para escalar o banco de dados da aplicação. Por enquanto, fazemos sharding apenas do CouchDB.

    – Na nova estrutura de logs estamos usando os builds da Percona e pretendemos testar o XtraDB.

    Como dissemos no texto, estamos sempre ajustando a estrutura e estudando novas possibilidades :)

    Abs

  8. Felipe Hummel | junho 1, 2009 @ 13:29 - Responder

    Mais 3 perguntas rápidas:

    1 – Pela imagem vocês tem 18 máquinas VPS, todas tem 8GB? Isso tem um custo alto $, e todos os nós realmente precisam de toda essa memória?

    2 – Onde vocês encontram bom material sobre escalabilidade em serviços Web?

    3 – Como vocês começaram? Apenas uma máquina que rodava tudo? :D

  9. João Paulo Faria | junho 1, 2009 @ 13:36 - Responder

    Legal a estrutura de vocês.

    Só tenho uma sugestão, que seria bem interessante no quesito banco de dados.

    Uma coisa que sempre prezo, quando configuro uma estrutura é que tudo seja totalmente transparente a aplicação.

    Nos últimos meses estive implementando uma grande estrutura de replicação com mysql e configurei uma replicação circular com load-balance em 8 servidores mysql.

    A idéia de usar servidores distintos para leitura e para escrita é bem legal, mas você estaria desperdiçando um servidor que é utilizado para escrita, para leitura quando o mesmo estivesse ocioso.

    É ai que entra a idéia do load-balance. O lb serve justamante para isso, para mandar escrita e leitura para os servidores mais ociosos.

    Utilizei o mysql-proxy para fazer este trabalho e inclusive dentro dele é possível personalizar por exemplo em quais servidores a escrita e leitura pode ser feita.

    Enfim, é possível personalizar praticamente tudo e tudo fica transparente para aplicação.

    Vou tentar desenhar uma estrutura de exemplo de banco de dados que ficaria rendundante e teria uma otima performance.

    Aplicação

    |
    |

    mysql-proxy-master mysql-proxy-slave
    | |
    | |
    -> mysql-01 <-
    / \
    mysql-02 mysql-04
    \ /
    mysql-03

    Quando for preciso mais performance, basta adicionar mais servidores mysql, sendo assim toda a estrutura de banco de dados seria transparente a aplicação e totalmente escalonável.

    Espero ter ajudado.

    Abs.

    João Paulo Faria

  10. João Paulo Faria | junho 1, 2009 @ 13:44 - Responder

    Infelizmente o desenho em ASC não funcionou no post, então vou explicar pela forma descritiva.

    Primeiro passo seria criar dois servidores utilizando o mysql-proxy. Um seria o master e o outro o slave, neles seria instalado algum sistema de cluster HA, como o heartbeat, se o servidor master caisse o slave assumiria.

    A configuração dos servidores mysql-proxy seria idêntica, onde setariamos as funcionalidades de load-balance e faillover caso algum servidor mysql caisse.

    Nos 4 servidores mysql estariam configurados como MASTER-MASTER, ou seja, todos seriam master de algum servidor e slave de outro, isso faria com que a replicação funcionasse em modo circular.

    E por ultimo, a aplicação conectaria sempre no mysql-proxy que estivesse UP.

    Abraços.

    João Paulo Faria

  11. Mauricio Maia | junho 1, 2009 @ 14:37 - Responder

    Felipe,

    1 – Nem todos têm 8GB, como os web servers, load-balancers e fila.

    2 – highscalability.com é um bom ponto de partida. As principais referências são blogs de desenvolvedores de startups, material de conferencias internacionais, blogs da tecnologia que você está usando, irc. Alguns livros também valem muito a pena (como Building Scalable Web Sites, High Performance MySQL).

    3 – Isso mesmo, uma máquina só e rodando PHP! Depois lançamos os widgets em Ruby numa nova máquina. Mas o Sistema de Publicidade Para Mídias Sociais já nasceu com uma estrutura semelhante a do post, em 4 máquinas.

  12. Maurício Maia | junho 1, 2009 @ 15:15 - Responder

    Jõao Paulo,

    estamos de olho no MySQL Proxy, mas ainda não nos aprofundamos. Interessante a estrutura que você propôs, só precisamos adicionar a possibilidade de fazer sharding dos dados.

    Obrigado pela sugestão!

    abs

  13. João Paulo Faria | junho 1, 2009 @ 16:41 - Responder

    Marco,

    Estou postando a imagem do schema.

    http://yfrog.com/09replicationschemaj

    Espero ter ajudado.

    abs

  14. João Paulo Faria | junho 1, 2009 @ 22:19 - Responder

    Tem um detalhe muito importante que esqueci de mencionar.

    Que é o no caso de um servidor dos quatro servidores mysql cair. Tem que fazer uma configuração a parte utilizando o próprio mysql para mudar automaticamente o master do servidor que estava copiando os dados do servidor que caiu.

    Este link aqui explica detalhadamente este problema no final.

    http://www.onlamp.com/pub/a/onlamp/2006/04/20/advanced-mysql-replication.html?page=5

    Lembrando que para isto funcionar, deve-se usar o MySQL a partir da versão 5.1

    Eu estou tentando desenvolver um método utilizando o próprio mysql-proxy para não precisar utilizar este método utilizado no link acima.

    Quando tiver notícias eu posto aqui.

    Abs.

  15. Brunno Gomes | junho 16, 2009 @ 15:25 - Responder

    Muito interessante o texto. Obrigado por compartilhar como funciona a estrutura de vocês.

    Uma pergunta:

    Vocês já consideraram serviços tipo Amazon Web Services (S3, EC2 etc.)? Gostaria muito de saber se sim, e se preferiram fazer tudo in-house, porque ?

  16. Dirceu Pauka Júnior | outubro 30, 2009 @ 18:47 - Responder

    Esse post me dá orgulho xD

    Hoje em dia, o que é mais importante na infra da boo-box? nginx + memcached?

    Que tal um post da experiência com o CouchDB? Creio que não foi *muito* boa mas foi interessante, certo?

    E o futuro? HBase? Google Apps (não relacional :/)? MySQL na Amazon (ou em outra mysql “cloud”)?
    Tem como fugir do Hadoop? Lucene/Solr?

    :P

  17. Ygor Lemos | setembro 13, 2011 @ 16:44 - Responder

    Muito legal a infra de vocês!!!

    Só duas considerações para futuro estudo:

    1 – MySQL Cluster com NDB – Acredito que talvez não seja o caso atual, mas como o boo-box está crescendo logariticamente eheheh talvez em breve vocês possam pensar em uma solução MySQL Cluster que escala muito melhor e mais rápido e tem uma performance bem maior do que replicação simples, além de poder contar com múltiplos Masters :)
    Existe uma versão paga pela Oracle (eca :p) e a versão community free do MySQL Cluster… o mínimo indicado é de 5 máquinas para se começar a brincar, mas o ganho de performance é exponencial.

    2 – Para cache de conteúdo estático, estudem o Varnish. Hoje é usado em setups monstruosos e tem um ganho de performance bem legal, inclusive quando comparado ao nginx :)

    No mais, parabéns pelo crescimento e pela infra… U are true Ninjas! ;)

  18. Alex | setembro 30, 2011 @ 1:47 - Responder

    É raro ver um post tão esclarecedor quanto esse, gostei muito mesmo.
    Várias duvidas, quando ao load balance e replicações foram resolvidas na minha cabeça.

    Porem já perguntei a algumas pessoas que tem grandes infra estruturas, mas nunca me responderam descentemente isso, não sei se é um super segredo, mas acho que não da nada.

    Queria saber mais ou menos sobre a estrutura do banco de dados. Não precisa falar as tabelas reais, mas por exemplo, uma tabela gigante de usuários, como é feita? Digo, usuarios_01(usuarios até uma faixa de id), usuarios_02 e assim por diante. Ou é feita da forma normal usando só uma tabela?

    Creio que os bancos de dados de escrita são innodb e os de leitura(slave) são myisam, seria isso?

    Espero não ter perguntado nenhum super segredo.
    Abraços e sucesso!

  19. Felipe Marques | novembro 11, 2015 @ 12:16 - Responder

    As imagens do post estão quebradas…

    • Bárbara Oliveira | novembro 11, 2015 @ 14:12 - Responder

      Oi, Felipe!

      As imagens estão abrindo normalmente. Verifique novamente, por gentileza. Se preciso for, abra o post em uma janela anônima do seu navegador.

      Abraços,