5 dicas simples de escalabilidade com Ruby


Escrever aplicações Ruby e Rails, justamente pela alta produtividade dessa plataforma, permite a criação e implantação de um novo projeto em um curto espaço de tempo. Colocar o projeto rapidamente em produção para receber feedback dos clientes faz parte da cultura ágil.

Mas e se a aplicação atingir um público maior que o esperado inicialmente? Excelente para os negócios? Mas o aumento considerável de carga será absorvido pelo seu sistema? Quais as chances de o sistema escalar a ponto de atender a nova demanda sem problemas?

Código bonito e boas práticas de desenvolvimento geralmente não são suficiente. Um ambiente mal configurado tem grandes chances de estragar tudo. E, nessas horas, um contato com administração de sistemas faz uma grande diferença! Conhecer bem a plataforma e tecnologia usada é essencial. Algumas dicas para sua aplicação rodar mais suave ao usar Ruby:

1) Configure o Apache ou o Nginx para servir conteúdo estático

Por mais óbvio que pareça, grande parte dos desenvolvedores esquece desse detalhe. Normalmente a aplicação responde muito bem, e você só vai sentir esse problema quando estiver tentando manter uma aplicação no ar. Normalmente as requisições de javascripts, css, imagens, acabam por serem servidas pelo seu servidor de aplicação (thin, mongrel, passenger, etc), quando poderiam ser servidas diretamente pelo servidor web que está à frente da sua estrutura.

2) Garanta um número mínimo de instâncias pré-carregadas

Lembrando a época que usávamos FastCGI, é saudável manter um número mínimo de instâncias da sua aplicação equivalente a quantidade de CPUs que uma máquina possui, visando diminuir o risco de sofrer o dog-pile-effect, que é gerado por uma sequência de solicitações a um recurso que ainda não estava pronto para ser servido. O tempo de subir mais processos da aplicação é suficiente para que o seu sistema simplesmente saia do ar.

3) Dimensione o uso de memória da máquina

Uma das piores situações que podem acontecer com um servidor é precisar utilizar excessivamente a memória virtual (paginação ou swap). Os sistemas operacionais modernos, como Linux e BSD, fazem uso da região de swap para conseguir melhorar a performance do acesso aos dados em disco, retirando programas inativos da memória RAM e usando-a para fazer cache do sistema de arquivos. Em contrapartida, quando falta memória RAM, o que era pra otimizar o sistema acaba por ser uma grande tragédia; sistemas que estão paginando por necessidade acabam por ser muito mais lentos (afinal, acesso a disco é muito mais lento do que acesso à memória RAM), e a grande e esmagadora parte de processos de aplicações web são focada em IO (IO-bound), o que faz com que uma aplicação que precisa de disco fique esperando o constante trabalho do sistema em reorganizar a memória para acesso.

Em linhas gerais, não existe um número mágico para quantidades e consumo de memória; você deve efetuar testes para poder ter uma estimativa do comportamento do seu sistema sob carga constante, em situações de stress, ou em condições de baixo volume de acessos. Uma ferramenta excelente para este tipo de teste é o JMeter.

4) Utilize um balanceador de carga, mesmo em uma máquina só

Essa é uma dica que literalmente salva vidas durante um aumento inesperado de acessos. Ao invés de colocar o sistema atendendo diretamente as requisições, faça uso de um bom balanceador de carga, como o HAProxy, que possui qualidades fantásticas no quesito escalabilidade e estabilidade. No caso do HAProxy, ele permite adicionar mais servidores sem sequer derrubar as conexões em atividade.

5) Não confie no caminho otimista

A melhor forma de ver como um sistema se comportará em produção, é ir desligando os pedaços e ver se o sistema se recupera de uma falha. Desligue o banco de dados: quando ele retorna, o seu sistema se recupera? Tente outras situações: mate um processo, reinicie o servidor web, e veja se o seu sistema consegue se recuperar sozinho de situações inesperadas. Um bom ajuste de timeouts pode fazer toda a diferença durante uma falha inesperada de serviços.


No curso RR-75, tratamos ainda de outros assuntos de escalabilidade, bem como performance e recursos avançados de Ruby e Rails. No fim, escalar aplicações não é uma tarefa impossível. Pequenos ajustes e algumas configurações são capazes de multiplicar a escalabilidade de suas aplicações. Mas são atitudes importantes para não sofrer indisponibilidade no pior momento, bem quando seu sistema começa a receber mais atenção e usuários.

5 Comentários

  1. Tiago Peczenyj 08/12/2010 at 10:35 #

    Uma tecnica interessante é saber o limite fisico da maquina de acordo com a aplicação. Sera que a primeira coisa q “engargala”é I/O, CPU ou Rede? Sabendo disso é interessante dimensionar a arquitetura de forma que uma maquina suporte apenas 40% desse gargalo, por exemplo, para o caso de perder metade das maquinas pela perda de um roteador ou algo do gênero, assim a outra metade fica apenas com 80% da capacidade (em teoria).

    Se vc usa uma cloud que se ajusta isto pode ser desnecessário, a princípio.

    Outra coisa é limitar o limite máximo de conexões e controlar a rajada. Uma coisa é suportar 8000 conexões simultâneas, outra é aguentar 100 conexões num curtissimo espaço de tempo. Respeitar as métricas e ter um health-check decente também ajudam.

  2. Leandro Storoli 08/12/2010 at 12:53 #

    Bem bacana!! Eu tenho estudando bastante Rails, e inclusive estou fazendo o RR-75 com o Davi. Posts desse tipo são muito bem vindos, eu tenho achado pouco conteúdo na net sobre profiling e benchmark de aplicações Rails, acho que uma comunidade tão unida como a do Rails tinha que se preocupar também em prover essas informações de como otimizar e escalar as aplicações em Rails e não só mostrar como o Rails é Ágil, pois isso já é bem visível, rssr. Muito bom o post.

  3. douglas.campos 09/12/2010 at 08:39 #

    @pac_man
    Bem lembrado! Tentar montar um baseline com essas informações é realmente muito útil pra poder prever o crescimento também (nossa estrutura atual atende até X clientes, etc).

    Quando você fala de cloud, você se referia a PaaS, certo?

    Em relação às rajadas, o HAProxy faz um excelente trabalho em “represar” esses bursts, e ir entregando aos poucos para os nós de processamento. Uso isso faz tanto tempo que nem tinha me lembrado disso.

    Excelentes dicas!
    []’z

  4. Umgeher 09/12/2010 at 09:47 #

    Pessoal, assim ate’ Pascal escala.

  5. Naiguel Santos 02/10/2017 at 13:26 #

    Olá,muito bacana e valiosas suas dicas. Gostaria de fazer uma pergunta sobre uma dúvida que estou tendo a algum tempo para implementar em minha aplicação com Ruby on Rails. Alguém saberia me informar como posso fazer para que eu utilize vários projetos iguais que cada um será para um cliente com banco de dados separados, mas que eu consiga incluir o model, controller, views e routes de apenas um projeto? Que eu consiga fazer alterações nesses arquivos e elas reflitam nos outros projetos também, como um ‘require’ desses arquivos nos projetos, porém cada projeto estará em endereços diferentes no servidor. Me entendem? Aguardo ansioso por alguma resposta é dicas. Abraço e bons trabalhos para todos.

Deixe uma resposta