Performance e Escalabilidade
O Problema
- Na história da computação, o consumidor nunca esteve
tão próximo da empresa
- Os clientes interagem diretamente com a empresa, através de sites
web
- O que acontece quando você acessa um site e este está lento
ou simplesmente trava?
- A maioria dos usuários comuns xinga a empresa e vai em direção
ao site da empresa concorrente
- Se o usuário for da área de informática provavelmente
vai tirar um screenshot da tela e mandar para os amigos, "tirando
onda" da equipe que desenvolveu o sistema. Exemplos:





- Os requisitos de performance e escalabilidade afetam diretamente o usuário
do sistema, por isso são críticos!
- O que acontece se o sistema de envio e recebimento de declarações
de imposto de renda de pessoa física, da receita federal, travar com
uma alta carga de acessos?
Performance e Escalabilidade
- Nesta aula iremos considerar conceitos gerais de Performance e Escalabilidade
e tratar destes temas no domínio de aplicações J2EE.
- Performance é o que afeta o tempo de resposta do seu
sistema para requisições de um único usuário
- Escalabilidade é a habilidade do seu sistema de manter
o tempo de resposta com o aumento do número de usuários simultâneos
- Performance e escalabilidade são ortogonais, apesar de parecerem
fortemente relacionados
- Uma aplicação que atende mal a 5 usuários irá atender
mal a 500 ou 5000
- Se ela atende bem 5 usuários não significa que irá atender
bem 500 ou 5000
- Ações para melhorar a escala podem comprometer a performance
e vice-versa
- A performance não mede a abilidade da aplicação lidar
com o aumento carga ou lidar com o aumento da configuração
de hardware
- A escalabilidade é medida em termos do número de usuários
concorrentes que podem ser servidos por uma aplicação
Causas dos problemas de performance e escala
- Principal causa dos problemas: nós não podemos prever
a quantidade de usuários que vão usar o sistema
- Quanto maior o sucesso de um site web, maior o risco de problemas de
escala!
- Além disso, temos:
- Ataques de “Denial of Service” (DoS)
- Arquitetos de software despreparados
- A grande abstração provida por J2EE distancia o desenvolvedor
das preocupações arquiteturais
- Time-to-Market: As empresas estão colocando sistemas mais complexos
no ar, mais rapidamente, para serem mais competitivas.
- Desenvolvedores e arquitetos têm pouco tempo para aprender detalhes
das tecnologias
Como resolver os problemas?
Otimização de código versus otimização
de projeto
- Os maiores problemas de performance em aplicações J2EE não
estão relacionados a má implementação do código
- Exemplo: Chamadas excessivas a métodos remotos, geradas por mau
design, geralmente impactam muito mais na performance do sistema do que os
problemas relativos a implementação de algoritmos ou estilos
de programação.
- É importante minimizar a otimização no nível
do código:
- Otimizar código é caro
- É necessário expertise do desenvolvedor
- Perda de tempo
- Ferramentas apropriadas
- A maioria das otimizações de código são pontuais
- Princípio de Pareto: regra 80/20 (80%
do tempo de execução é gasto
em 20% do código)
- Em software a proporção 90/10 é muito
comum
- Isso significa que otimizar de 80% a 90% do
código é perda de tempo e recursos
- Devemos usar ferramentas para identificar os
gargalos do sistema e otimizar apenas estes gargalos
- A maioria dos gargalos está no código
do servidor de aplicações, causados
pela má utilização dos recursos,
conseqüência de um design mal feito.
- Otimização de código pode gerar bugs
- Otimização de código torna o código
mais difícil de entender
- Devemos codificar e otimizar quando houver necessidade
- Otimização de código pode torná-lo difícil
de manter
- Aplicações corporativas são críticas,
devem ser fáceis de manter
- Quando houver conflito entre preocupações com manutenibilidade
e otimização, a manutenibilidade deve ter maior prioridade
- Por isso escrevemos software em Java e não em C, C++ ou
Assembly! Java tem pior performance mas é mais fácil
de manter
Testando a performance e escalabilidade
- Devemos usar ferramentas que permitam a automação e repetição
dos testes
- Em geral devemos preparar a aplicação, iniciar os testes
de carga e em seguida os testes de performance
Passo 1 : Defina os requisitos de performance e escalabilidade
- Quais são os requisitos de performance e de escala?
- Quanto tempo o usuário topa ficar esperando pela resposta
do sistema?
- Quantos usuários vão utilizar a aplicação,
simultaneamente?
- Não sabemos qual é o limite máximo de ulização
de nossa aplicação (a internet é imprevisível),
mas devemos ter idéia de um limite para os testes!
- Use a experiência de sistemas semelhantes na web
- Teste sempre o pior caso
Passo 2: Prepare seu sistema para ser testado
- Configure sua aplicação como se ela fosse para produção
- Coloque a aplicação para funcionar no hardware onde ela será instalada
(ou num hardware equivalente).
- Configure o sistema de log para ambiente de produção. Logs
para debugging devem ser desativados
- Configure os frameworks, pacotes e ferramentas para melhor performance
- Por exemplo, no Tomcat habilite a compilação dos JSPs
no momento de inicialização do contexto; ou desabilite
a opção de hot-deployment do servidor de aplicação.
- O banco de dados deve ser configurado para o modo de produção.
- Use dados que reflitam a realidade, nos testes.
- Ao executar um teste de carga, faça a partir de uma máquina
diferente, pois o processamento do sistema de teste pode afetar o sistema
testado
- Verifique se os processos ativos na máquina são os únicos
que devem existir enquanto a aplicação estiver funcionando
Passo 3: Execute o teste de carga
- Em nosso exemplo vamos usar a ferramenta "Microsoft Web Application
Stress Tool". Outra alternativa é usar o JMeter, da Apache. (Links
no final do material)
- Vamos criar uma aplicação no tomcat que tem dois JSPs, um
que lista informações a partir da memória e um segundo
que lê informações que estão no arquivo. (download
do war)
Passo 4: Execute o teste de performance
- Execute o teste de carga com apenas um usuário
- Execute um perfilador para verificar os gargalos do código
Resolvendo os problemas de Performance e Escalas
Escolha e configuração do servidor
- Antes de procurar as causas dos problemas no código ou no design do seu
sistema, verifique se a causa não é externa, o servidor por exemplo.
- Escolha bem o servidor de aplicação que está utilizando
- Configure o servidor, otimize sua configuração. A maioria dos servidores
são instalados com configurações para desenvolvimento.
- Algumas otimizações comuns aos servidores de aplicação:
- Tamanho do pool de threads: muitas threads farão com que a JVM rode
com limitações pelo SO.
- Tamanho do pool de conexões ao banco de dados
- Desabilidar o suporte a recompilação automática.
- Tamanho do Pool para os EJBs
- Politicas de travamento e cache para entity beans.
- Gerente de transações utilizado. Pode ser mais eficiente desabilidar
a opção de "Two-phase commit", para transações de um único recurso
- Otimize a JVM e a configuração do SO
Desabilite os serviços não utilizados no servidor J2EE
- Evite o uso desnecessário de EJBs.
- Toda chamada a um EJB (mesmo as chamadas locais) geram um overhead
no container.
- Evite o uso do JMS (Java Messenging Service) se você não precisa de assincronia.
- Evite o uso de Entity Beans onde não traz ganhos e onde você pode resolver
o problema com uma simples chamada JDBC
- Evite duplicação de serviços no container. Se você está usando o controle
de sessão no container web, evite usar EJBs stateful session beans.
Cache
- A melhor técnica para melhorar a performance de servidores J2EE é usar
Caching.
- É possível usar caching em vários pontos da arquitetura J2EE (web, banco
de dados, ejbs, etc.)
- Em geral os servidores J2EE têm mecanismos para configuração de caches.
Quando utilizar Cache?
- Antes de implementar uma solução de caching na aplicação, temos que responder
a algumas perguntas:
- Quão lento é acessar a informação sem cache? A melhoria da performance
do sistema justifica a introdução do cache?
- Caches acrescentam complexidade ao sistema, devemos utilizar apenas
quando comprovadamente necessário
Onde usar Cache?
-
Banco de Dados
- Entity Bean
- Session EJBs
- JavaBeans rodando no container web
- Camada web
Otimização de código
- Conheça profundamente a linguagem em que você está programando e suas peculiaridades
de performance (veja links sobre performance em Java, no fim deste material)
- Evite otimização de código que reduza a manutenibilidade, a menos que seja
vital para a aplicação.
- Quanto maior o nível de abstração da aplicação o código implementa, maior
é a chance dele intervir na performance do sistema como um todo. Ex.: Código
que implementa aspectos arquiteturais como conexão a banco de dados; ou chamada
remota, como RMI.
- Algumas técnicas de otimização de código:
- Minimize a criação de objetos através de pooling de objetos.
- Use o tipo adequado de coleção. Ex.: LinkedList quando vc não sabe
quantos elementos serão armazenados;
- Use classes e métodos final;
- Evite usar System.out.
- Evite operações usando Strings. Use StringBuffers!
- Evite a geração de logs desnecessários no sistema.
- Cuidado ao usar Syncronization
- Cuidado ao usar Reflection
Referências e links sobre o assunto: