Ontem enquanto caminhava do trabalho até o carro, conversando com um colega sobre infra estrutura para um sistema que ele estava pensando em construir. Qual arquitetura seguir, qual linguagem utilizar, qual framework, se rails era o suficiente para o que ele queria ou não, se devia usar ruby ou java, se ruby escala ou não escala, consegui convencer ele de que a resposta para a pergunta inicial dele é “depende”, mas também lembrei de alguns segredos que se aplicam em todos os casos que consigo lembrar agora para se criar um sistema web altamente escalável,por conseqüência, também são segredos bastante importantes para colocar a sua aplicação na “nuvem” e também são muito importantes para você escrever os serviços que farão parte da sua arquitetura SOA ou seus serviços REST.
Ou seja, sempre mantenha estas cinco regras em mente se o sistema que você esta desenvolvendo pode crescer um dia.
Sim, eu sei que estou sendo um pouco categórico demais, e que nenhuma regra se aplica a tudo e que existem excessões para o que estou escrevendo.
Se você quer um sistema ou um serviço escalável, com certeza você quer que todas as requisições para este serviço sejam stateless.
Mas por que?
Simplesmente por que caso em um futuro próximo você precise rodar a sua aplicação em um cluster, você não prende um cliente a um nó do cluster, cada requisição pode ir para o nó do cluster que estiver com a menór carga naquele momento, fazendo com que o tempo de resposta aquela requisição seja o menor possível, mantendo o nó do cluster que vai atender a esta requisição ocupado o menor tempo possível.
Acho que já falei um pouco sobre isto, mas imagine a seguinte situação, o sistema que você acabou de publicar bombou e agora em vez de ter que atender a 5 clientes (Você, seu melhor amigo, sua mãe, seu pai, sua namorada), agora o sistema tem que atender a 1k clientes simultâneos, e você pensa: Beleza, só preciso fazer um clusterzinho aqui, coloco mais duas maquinas e tudo beleza.
O problema é que o seu sistema antes estava com um “RRT” médio de 30s ou seja, com uma maquina só, você conseguia responder a duas requisições por minuto (considerando apenas um thread por máquina para facilitar o exemplo), agora com as duas maquinas novas você consegue atender a maravilhosos 6 requests por minuto. Ou seja, você tem um baita fiasco nas mãos.
Por isto o Request Response Time, ou seja, o tempo que a sua aplicação leva para atender a cada requisição tem que ser o mais baixo possível.
Por exemplo, enquanto escrevia este post criei uma aplicação rails com um cadastro de usuários de brinquedo, gerado pelo scaffold e o RRT é de 15.6ms (alto mas a maquina esta bastante carregada agora) o que permite que com uma thread seja possível atender a 64 requisições por segundo. Em um outro sistema que trabalhei, algumas requisições por diversos motivos chegaram a demorar 20s para retornar, mas isto foi resolvido claro ![]()
Bom, acho que deu para entender o por que o RRT é tão importante. Para clarear mais a idéia, imagine a seguinte situação que você já deve ter visto diversas vezes: Uma loja grande, com fila unica e 4 caixas atendendo. Se cada um dos caixas for muito demorado, você vai passar horas na fila, e não é economicamente viável ter um caixa por usuário. então a solução viável para este problema é otimizar o trabalho dos caixas para que cada caixa seja mais rápido e consiga atender a um maior número de clientes por minuto.
Cache é uma forma de melhorar muito o RRT, imagine que a sua mega aplicação seja uma página de classificados, em que a página inicial, que todos os clientes acessam ao chegar no site. Tenha uma lista com os produtos mais baratos anunciados.
Esta página precisa de uma consulta no banco de dados para ser renderizada, mas se você pensar bem os dados serão sempre os mesmos até que alguem delete um dos produtos listados ali ou cadastre outro mais barato.
Então faz todo o sentido “guardar uma copia” da página prontinha, e só mostrar aquela cópia para o próximo que acessar a página, e simplesmente deletar esta cópia quando uma das duas situações que pode alterar a página acontecer, ai no próximo acesso a página é renderizada novamente e a copia atualizada é guardada, e novamente ficamos utilizando apenas aquela cópia até que algo aconteça que possa fazer os dados ficarem desatualizados.
Isto é chamado de “cache”, na verdade esta é uma forma bem simples de cache. Estude aos recursos de caching do framework que você esta utilizando, do servidor de aplicações, do sistema operacional, do banco de dados.
Mas não ative tudo ao mesmo tempo, o correto uso de cache vai melhorar muito a performance da sua aplicação, mas o uso incorreto pode causar muitos problemas.
Muito pouca coisa é pior para um cluster do que uma aplicação que guarda dados localmente.
Imagine só o seguinte, naquela aplicação de classificados, você resolveu que as imagens correspondentes a cada anuncio ficariam gravadas na própria maquina do servidor, barbadinha, facilita o upload.
Ai é que mora o perigo.
Quando você precisar colocar isto pra rodar em um cluster, o segundo nó do cluster quando atendendo uma requisição, vai acreditar que as imagens estão naquele nó também, mas ele nem existia quando o anuncio foi criado, o upload foi feito pra outra maquina. Isto vai fazer com que o usuário veja uma página com a imagem quebrada.
Ahh, e como resolver isto?
Bom, existem diversas formas, uma bem simples é criar um servidor de “recursos estáticos”, ou seja, tudo o que é estático no site é servido por um endereço diferente, e quando for feito o upload de uma imagem, ela deve ser salva neste outro servidor. Também é possível utilizar um serviço como o Amazon S3 que vai fazer exatamente a mesma coisa que o seu servidor de recursos estáticos, mas de fora ![]()
Outra coisa a lembrar é do banco de dados, ele também não deve ficar na mesma maquina que o servidor da aplicação, ou o endereço do banco (seja ele SQL, document driven, …) deve ser configurável. Isto por que em um cluster, o ideal é que todos os nós acessem o mesmo banco de dados, ou no mínimo que todos os bancos do cluster estejam sincronizados.
Um próxi reverso no contexto deste post vai ser utilizado para mascarar algumas das técnicas de caching, para implementar algumas técnicas de caching e principalmente para esconder do usuário que você tem diversos servidores, ele vai ser o “front-end” da sua aplicação, a mágica do cloud só pode acontecer atrás do proxy, e ele também pode esconder do usuário o fato de você usar um “servidor de recursos estáticos” sendo ele interno criado por você mesmo ou você usando um S3 da vida, o proxy reverso pode mascarar o endereço real da aplicação.
Mas nunca esqueça de um detalhe importante. Este proxy mesmo sendo vital para uma arquitetura cloud, ou um cluster menorzinho, ele acaba de adicionar um SPoF (Single Point Of Failure) se o proxy morrer, a sua mega aplicação esta fora do ar.
Bom, acho que era isto, sempre tem alguem perguntando como fazer um sistema escalável, como fazer um sistema robusto, como fazer um sistema para rodar em cluster ou na nuvem.
Este post não é a resposta final para todos os problemas, este post não responde estas perguntas para todos os casos, mas para a maior parte dos casos que me lembro agora, as dicas deste post são pontos imprescindíveis para qualquer aplicação ou arquitetura que pretenda ter um mínimo de escalabilidade.
Espero que este post seja útil para alguem, e se não concordarem com alguma coisa é só deixar um comentário.
Tags: escalabilidade, produtividade
oi Rodrigo! muito legal este seu post! estou trabalhando como arquiteto jr. na companhia onde estou atualmente, e vejo que este post irá me ajudar na caminhada para tornar-me um profissional pleno.
obrigado por compartlhar seus conhecimentos!
[Translate]
Opa Urubatan. Muitooooooo show esse post ai, eu mandei para o pessoal aqui da empresa pra eles verem que projetar sistemas não é sair escrevendo códigos na loucura. Também acho que agora vai ajudar a ver que o arquiteto as vezes é chato (exigente) com algumas coisas pq tem que pensar em tudo isso antes de projetar o sistema.
Obrigado pelo compartilhamento ai, e parabéns!
[Translate]
Muito bom post Rodrigo !!! Parabéns… o que e como vc usa para medir seu RRT ? A paz.
[Translate]
tem diversas ferramentas de testes que medem isto, uma forma que considero simples é utilizar o JMeter http://jakarta.apache.org/jmeter/index.html
Mas o Rails por exemplo imprime o tempo total de processamento (desconsiderando trafego de rede) no console quando em modo debug, em java é possível fazer o mesmo com AOP …
[Translate]
A URL do WordPress não escalou.
Afinal, são 4 ou 5 segredos?
[Translate]
o texto mudou e aumentou de 4 pra 5, mas o link é mais complicado de mudar pois quem tivesse a URL antiga teria um endereço inválido
[Translate]