Escalabilidade != Performance

A Escalabilidade é um requisito não funcional de arquitetura que deve ser considerado em todos os projetos porém, dependendo das necessidades do cliente (requisito funcional) e da quantidade de usuários, a escalabilidade pode um peso maior ou menor dentro do projeto.

Muita gente confunde escalabilidade com desempenho (performance) mas são duas coisas muito diferentes, apesar se um influenciar o outro. Performance é a capacidade de atender requisições dos usuários em tempo de processamento e consumo de memória aceitáveis conforme as necessidades do cliente. Já a escalabilidade é a capacidade de manter a disponibilidade e o desempenho a medida que a carga transacional aumenta. Você pode ter um sistema altamente performático em uma máquina mas que é impossível de escalar em uma arquitetura de cluster, por exemplo. Pensar em escalabilidade não é somente pensar em aumentar máquina. É pensar em IO, memória, requisição, banco de dados e assim por diante. Por exemplo, uma aplicação web que guarda muitos dados na sessão pode ser bem performática, mas se essa aplicação passar a ser usada como um web site, com milhares de usuários, a quantidade de informação na sessão (memória do servidor) tornará o sistema lento! Um HttpSession é muito difícil de escalar se for fazer uma estratégia na mão. Nesses casos uma estratégia de cache distribuído, como o memcached, poderia resolver o problema.

Tive uma experiência recente com uma aplicação web que estava apresentando problema de performance, então precisei fazer uma análise para descobrir a causa. Infelizmente essa aplicação também tem problema de manutenabilidade e nessas horas os autores nunca trabalham mais no projeto e não deixaram o endereço da casa deles para quem for dar manutenção!🙂

Analisando o código, de cara já vi que teria problemas pois o sistema não tem testes unitários. Com certeza haveria a necessidade de fazer refatorações e nem ao menos posso garantir que não vou “quebrar” o software. Os testes de unidade e/ou de integração são tão importantes quanto o projeto em si pois são eles que garantem a qualidade do software. Um programador profissional deve escrever testes, como já disse Phillip Calçado aqui! Como não há testes, a refatoração foi dividida em sprints bem curtos de no máximo uma semana. Já que o projeto está em produção, é interessante construir testes de falha e depois testes de sucesso, pelo menos para as funcionalidades mais importantes. O ideal seria que a equipe tivesse trabalhado com TDD.

Essa aplicação, escrita em Java, apresentava problemas arquiteturais de performance mesmo com uma infra poderosa com vários clusters e load balancing, e consequentemente afetou a escalabilidade pois o aumento transacional causou indisponibilidade do sistema. Portanto, com o aumento de usuários, entrada de novas funcionalidades e crescimento de registros no banco de dados, a aplicação começou a travar e apresentar muitos problema de lentidão.

Antes de começar a fazer qualquer alteração precipitada eu baixei o JProfiler para tirar uma primeira análise. A ferramenta é boa mesmo! Monitorar consumo de memória, tempo de processamento, hotspot, trabalho do garbage collection, consultas demoradas no banco de dados etc. É uma boa prática monitorar frequentemente as aplicações com um profiler para saber como está indo o desenvolvimento, evitando gargalos desnecessários. Essa prática também evitaria otimizações prematuras, como disse Joshua Bloch aqui. Por exemplo, muita gente altera concatenação de String para StringBuffer, mas nem sabe que internamente a concatenação de string seria transformada em StringBuilder pelo java.

Voltando à aplicação, de nada adiantaria sair alterando o código se o problema estiver no banco de dados. Precisei criar índices das tabelas e com a ajuda do JProfiler isso ficou bem fácil. Já na parte da aplicação, a ferramenta também me ajudou a encontrar problemas como:

  • Excesso de instanciação de objetos dentro de loops bastante grandes. Muitos desses objetos são apenas para trafegar dados dentro da aplicação. Eles não tem inteligência nenhuma, são como fantoches. Mas o que o JProfiler aponta é que o garbage collector está precisando fazer Full GC toda hora, e isso gasta tempo!
  • Muito uso de Reflection do java dentro de loops bastante grandes. Esse recurso é muito poderoso, mas deve-se tomar algumas precauções. O desempenho da aplicação é melhor quando a chamada de um método é feito da maneira convencional. Se for para dar produtividade e o overhead não for tão grande, vale a pena. Por outro lado o uso de reflection pode deixar o código difícil de entender. No caso da aplicação em análise uma solução mais Orientada a Objetos eliminaria esses impulsos por querer dificultar problemas que seriam simples. Só para uma curiosidade, o Reflection foi rescrito no java 1.4 para melhorias de performance.
  • Comparação de strings para buscar um objeto em uma lista. Essa busca de objetos pode ser otimizada pela própria linguagem utilizando, por exemplo, o método contains de um collection. Um loop utilizando Java.util.Vector pode ser transformado em um Java.util.HashSet para buscar o objeto mais rapidamente se no caso não importar a ordem dos objetos. Porém se a intenção for fazer cálculos com atributos de uma classe, como ocorre em algums pontos da aplicação, a idéia seria que a própria classe (entidade) faça o cálculo a partir de seus atributos. Isso, além de ser mais Orientado a Objetos, eliminaria a necessidade de fazer loops para buscar o objeto e setar um valor nele.
  • Loops desnecessários. Alguns loops podem ser eliminados apenas com uma solução mais orientada a objetos. Outros podem ser eliminados apenas alterando a consulta no banco de dados para já trazer um resultado calculado, por exemplo.
  • Problemas em aberturas e tempo de vida de transações de banco de dados. Esse com certeza é um dos piores mas não vale a pena eu comentar pois a solução depende de cada aplicação.
Aplicações em Ruby on Rails sofrem com a falta de thread safety, o que pode prejudicar a escalabilidade. Mais o pessoal está escalando uma grande aplicação em Rails fazendo um uso extensivo de cache de fragmentos. Que tal o GUJ rodar em Rails 7 vezes mais rápido do que roda em java? Segue o link do bate-papo.
Conclusão:

Tem muita gente dizendo que Ruby on Rails não escala por causa do case do twitter mas tá aí uma prova que mesmo uma aplicação em Java, com recursos como GC, JIT e hotspot pode não escalar, pois não é a linguagem que não escala, e sim o modelo que não foi pensado para escalar.

6 Respostas to “Escalabilidade != Performance”

  1. Paulo Silveira Says:

    Excelente post! Alias, quando temos algum framework ou servidor escalavel, com certeza ele tem, se rodado em single instance, menos performance…. pois gasta uma serie de passos, interceptadores e modelo de componentizacao pra poder ser facilmente clusterizado!

  2. Nicholas Says:

    Muito bom o artigo. Só de ler já identifiquei varios problemas que vemos na aplicação aqui na empresa e selecionamos para refatoração.
    Agora é usar novamente o JProfiler e aprender a identificar o que é realmente um gargalo na aplicação.

  3. Tupi » Blog Archive » Sobre escalabilida e performance Says:

    […] um pouco sobre Sistemas Distribuídos encontrei um ótimo post entitulado Escalabilidade != Performance. Ótimo saber que uma boa escalabilidade não depende apenas da linguagem ou máquina utilizada, mas […]

  4. Tony Fabeen Says:

    Belo Post,

    Geralmente as pessoas confundem escalabilidade com desempenho e disponibilidade.

    []s

  5. Web Sites de Alta Performance (Frontend) « Manifesto na Web! Says:

    […] falamos de performance é mais comum focar no processamento do servidor. Já escrevi um post sobre escalabilidade e performance. Porém, muitas vezes não nos preocupamos com o conteúdo que estamos escrevendo nas páginas e as […]

  6. Escalabilidade e Desempenho. Termos completamente diferentes. | Blog do Alone Says:

    […] dúvida sobre os termos “Desempenho” e “Escalabilidade”, segue um excelente post escrito por Ricardo Almeida, na qual, expõe claramente as diferenças entre Escalabilidade e […]


Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: