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?
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 habilidade 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
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
Aumentando escala e performance: Caching
- Cache é um mecanismo para reduzir o custo de acesso a recursos.
- No cache de páginas web, replicamos as páginas processadas em servidores, evitando o seu processamento a cada consulta.
- Existem vários mecanismos de implementação de cache
- Cache simples
- O cliente requisita uma informação ao cache, se a informação existir, o cache responde, se não existir, o cache consulta o servidor, guarda uma cópia da resposta e responde ao cliente.
- Problemas:
- Limitação de carga de acesso (pode virar um gargalo)
- Se o cache falhar os usuários perdem acesso ao recurso
- Capacidade limitada de armazenamento, implica em alta taxa de objetos inexistentes

- Cache cooperativo
- Um conjunto de caches cooperam entre si para o armazenamento da informação requisitada. Quando a informação não existe em nenhum cache, então há a requisição ao servidor
- Problemas:
- Como localizar o conteúdo entre os caches?
- Multicast
- Demora para descobrir que ninguém tem o conteúdo
Alta replicação de conteúdo nos caches
- Estrutura de diretórios
- Transferência entre diretórios consomem banda
Pontos de falhas nos diretórios raízes


- Cache pode ser usado entre vários componentes da arquitetura de N camadas
- Entre o browser e o servidor web (cache de páginas web)
- Entre o servidor web e o servidor de aplicações (cache de objetos java e de EJBs)
- Entre o servidor de aplicações e o SGBD (cache de consultas ao banco de dados)
- Entre o servidor de aplicações e sistemas de terceiros
- etc.
- Cache só funciona para informações resultantes de consultas.
Aumentando escala e performance: Balanceamento de carga
- Um "cluster" é um grupo de servidores executando aplicações web simultaneamente, trabalhando como um único servidor.
- O balanceamento de carga é o mecanismo onde a carga do sistema é distribuida para diferentes nodos de um cluster de servidores, buscando aumentar a escala e manter a performance do sistema.
- Resultado:
- Aumentando o numero de servidores há o aumento de escala.
- Aumentando a redundancia há aumento de disponibilidade.
- Pergunta: Porque um cluster aumenta a disponibilidade do um sistema
- Existem vários algoritmos para orientar o balanceamento de carga:
- Random: A carga é distribuída aleatoriamente entre os nodos
- Weight-based: A carga é distribuída na proporção dos pesos dos nodos
- Minimum-load: Requisições vão para o nodo com menor carga
- Least connections: Requisições para os nodos com menos conexões
- Least response time: Ordenam-se os servidores por tempo de resposta e direcionam-se as requisições aos que tem maior tempo de resposta
- Least bandwidth: Direciona as requisições aos nodos com maior banda
- URL hashing: Faz um mapeamento entre a url requisitada e o ip dos nodos
- Network proximity: Usado para balanceamento em escala global (Global Server Load Balancing - GSLB), as requisições são enviadas ao nodo mais próximo de quem está fazendo a requisição.
- Programmatic parameter-based: As requisições serão direcionadas dependendo dos seus parametros. Muito usado para distribuir a carga de acordo com a natureza da requisição.
- DNS Round robin: Um dos mecanismos mais utilizados. O servidor DNS mapeia um nome a um conjunto de IPs e responde um IP diferente a cada solicitação de nome.
DNS Round Robin
- Vamos focar no DNS Round Robin pois ele é um dos mais usados e possui algumas desvantagens que nos ajudarão a entender melhor o mecanismo de balanceamento de carga.
- Vamos antes revisar o funcionamento do DNS
- 1: o cliente entra o nome do servidor no browser
- 2: o servidor DNS retorna o IP associado ao nome requisitado
- 3: o cliente requisita o conteúdo ao IP fornecido

Figure from:http://www.onjava.com/lpt/a/1228
- No DNS Round Robin, o servidor DNS associa vários IPs a um mesmo nome e "circula" os IPs a cada requisição.
- Os diversos clientes serão direcionados aos diferentes IPs retornados pelo servidor DNS.
Figure from:http://www.onjava.com/lpt/a/1228
- O DNS Round Robin é simples.
- Os servidores DNS suportam o Round Robin, exigindo pouca configuração.
- Não exige mudanças na aplicação web
- A aplicação desconhece a existencia do mecanismo de balanceamento de carga.
- Problemas com o DNS Round Robin:
- Esquema de cache de dns no browser do cliente faz com que o cliente busque sempre o mesmo IP associado ao DNS, sem consultar o servidor DNS.
- Se um dos servidores cair, o servidor DNS continua fornecendo seu IP, afetando a disponibilidade do sistema
- Não considera tempo de transação, carga do servidor, congestionamento da rede, etc.
- Perguntas:
- Como fica a sessão do usuário, quando o sistema usa Round Robin?
- Como resolver o problema de disponibilidade do DNS Round Robin?
Dicas para resolver problemas de Performance e Escalas (J2EE)
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
Exercício: Considerando a performance e escala na arquitetura
- Vamos agora projetar a arquitetura para um sistema de locação de filmes de DVD onde o usuário poderá locar filmes pela Internet.
- Vamos levantar requisitos não-funcionais de escala e performance para dois cenários e discutiremos a implicação dos requisitos na arquitetura do sistema.
- Cenário 1: Locadora com poucos clientes e baixa taxa de acesso
- Performance:
- O sistema deve responder às consultas em menos de 1 segundo, em uma LAN de 10 mb/s
- Escala:
- O sistema deve atender a 30 usuários simultâneos
- Deve aceitar um volume de 100 usuários por minuto
- Cenário 2: Locadora com muitos clientes e alta taxa de acesso
- Performance:
- O sistema deve responder às consultas em menos de 1 segundo, em uma LAN de 10 mb/s
- Escala:
- O sistema deve atender a 1000 usuários simultâneos
- Deve aceitar um volume de 60000 usuários por minuto
- Tarefa: Fazer um esboço da arquitetura do sistema da locadora para os dois cenários
Referências e links sobre o assunto: