quarta-feira, 28 de novembro de 2012

Prioridade zero: O banco de dados!


Vou agora começar a mostrar onde geralmente estão os principais gargalos nos sistemas desenvolvidos para web, e algumas técnicas para evitá-los.

A "prioridade número zero" em qualquer sistema que esteja apresentando lentidão e precise ser otimizado é atacar os gargalos no banco de dados.

Pode-se otimizar de tudo em um sistema: a rede, o número de servidores, o poder de processamento dos mesmos, aumentar a quantidade de memória, mas nada disso surtirá o efeito desejado sem uma prévia otimização do banco de dados.

Isso porque no final das contas, toda a cadeia de processos envolvidos dependem dele. Os pedidos dos usuários, em geral, culminam num acesso ao banco de dados.

Portanto, não compensa ficar enxugando a aplicação (por exemplo) para ganhar 10 ou 20 milissegundos na carga de uma página, se não tiver sido feito antes, um ajuste fino no banco de dados.

E, através de modificações triviais no banco de dados, pode-se diminuir segundos do tempo de resposta (em contrapartida aos milissegundos ganhos sob outra abordagem), o que representa um ganho muito mais expressivo na performance geral do sistema, impedindo o enfileiramento de requisições no servidor de aplicação.
 
Note que é assim que se melhora a performance de um sistema. Medindo-se o tempo gasto em cada pequena parte e a otimizando-a, pois cada pequeno processo desses será chamada o número de vezes que requisições forem feitas pela aplicação ao banco de dados. Então é algo que é exponencial.

Os pontos-chave a se observar no contexto do banco de dados são, portanto:

* Otimizar as queries

Tenha o hábito de medir o tempo que leva cada query do seu sistema, do início ao fim do processamento. No Oracle, por exemplo,  isso é feito com o comando "SET TIMING ON". Toda query executada após este comando terá seu tempo de processamento mostrado na tela, em milissegundos. Quanto menor o tempo gasto pela query, melhor. Diria que qualquer valor acima de 1 segundo é indesejável:

    set timing on;
 
    select dsc_serie from serie
    where ind_status = 'A';


    25 linhas selecionadas.
    real: 141 (milissegundos)



* Evitar usar a cláusula IN ou EXISTS nas queries

A cláusula IN em queries SQL são muito lentas. Dê prioridade aos joins.


* Utilizar materialized views para consultas que gerarão relatórios.

Muitos sistemas geram relatórios a partir das próprias tabelas que estão sofrendo inserções e atualizações de dados  pelos usuários do site. Isso cria uma situação de lentidão tanto para quem está requisitando o relatório quanto para quem está entrando ou atualizando dados. A solução é criar uma materialized view com um job associado, que a atualizará de tempos em tempos. Sugiro a pesquisa no Google pelo termo "ETL".

* Utilizar índices nas tabelas.

Os índices criam uma espécie de "mapa" para o banco de dados acessar as informações de forma muito, muito mais rápida. Mas, relembrando a citação de Lavoisier, em contrapartida, tornam a inserção de dados ligeiramente mais lenta, pois algum tempo é necessário para que a indexação seja realizada. No entanto, a relação custo x benefício é vantajosa.

* Restringir o número de linhas no retorno de uma query.

Quando o usuário estiver fazendo uma pesquisa digitando um nome em uma caixa de texto, por exemplo, que gera uma atualização instantânea do conteúdo da caixa (o famoso autocomplete), pode-se especificar na query o número máximo de linhas retornadas. Isso agiliza bastante a resposta. O usuário não perderá informações, pois quanto mais letras digita, mais precisa é a resposta.

* Trazer tabelas específicas inteiras para a memória real

Com a diminuição do preço da memória RAM, é muito comum termos servidores com grande oferta de memória disponível. Algumas empresas já estão utilizando esta técnica para agilizar as consultas a banco de dados - trazer TODO o conteúdo de certas tabelas para a memória real.


Há outras dezenas de técnicas de otimização possíveis no âmbito do banco de dados. Área em que  não sou especialista. Mas certamente, uma equipe de banco de dados saberá responder prontamente a qualquer pedido nesse sentido, fornecendo as melhores estratégias para diminuir o tempo de processamento das queries, que é a necessidade objetiva que tentei passar com este post.


Entretanto... Há uma técnica em especial que é uma daquelas coisas que costumamos dizer que "funciona como mágica", como diz a famosa música do Queen - "It´s a kind of magic!":
 
 
 O Cache de queries.
 
 
Será o tema do nosso próximo post. Imperdível!!!

terça-feira, 27 de novembro de 2012

O gargalo faz da garrafa o que ela é. Mas do congestionamento também!

Um dos mais importantes estratagemas do livro "A arte da guerra", escrito pelo general, filósofo e estrategista chinês Sun Tzu há dois mil e quinhentos anos atrás, enfatiza a importância de conhecer o inimigo:

"Se você conhece o inimigo e conhece a si mesmo, não precisa temer o resultado de cem batalhas. Se você conhece a si mesmo, mas não o inimigo, para cada vitória conquistada, você também sofrerá uma derrota."

Em outras palavras, para ser ótimo, é necessário conhecer o inimigo profundamente. Caso contrário, só é possível ser mediano. No contexto da otimização de sistemas, o inimigo em questão é o gargalo.

Mas o que é um gargalo? De que se trata? Por que ele nos aborrece? Ele é sempre ruim? Como evitá-lo? Onde ele aparece?

Bem, um gargalo é um funil. Nada além do que uma resistência à passagem de alguma coisa por um canal. Um filtro. Quantitativo, não qualitativo.

O gargalo de uma garrafa tem a função de restringir a quantidade de líquido que sai dela. E nesse contexto isso é bom. É a função dele, para que o líquido não derrame todo de uma vez. O gargalo é o que faz da garrafa o que ela é! Sem ele, não seria uma garrafa, mas um copo.

Por outro lado, um gargalo também faz de um engarrafamento de veículos em uma avenida ou estrada, o que ele é. E nesse contexto isso não é bom. Deve e pode ser evitado: Pode-se construir  mais vias paralelas de escoamento, definir saídas priorizando ambulâncias, carros de bombeiro, transportes de massa como ônibus, pode-se coibir motoristas que trafegam no acostamento,  induzir motoristas a seguir por uma rota alternativa, pode-se aumentar a velocidade com que os veículos passam pelos pontos de gargalo, pode-se fazer um rodízio de placas naquela via, combinando quem pode trafegar de acordo como dia da semana,  pode-se até mesmo retirar a necessidade de vários motoristas passarem ali diariamente, se forem convencidos a trabalharem de casa. Pode-se aumentar o número de guardas e câmeras na via para monitorar o comportamento do fluxo e obter informações que gerarão ações de correção.


Veja que, utilizando a analogia do engarrafamento no parágrafo acima, citei várias técnicas de otimização de sistemas web, que, quando corretamente aplicadas, podem melhorar sobremaneira o desempenho e a estabilidade de um serviço online.

Antes de optar por uma técnica ou outra (ou por todas), entretanto, é preciso identificar os pontos de gargalo do sistema, que podem estar: na rede (baixo número de rotas para chegar ao servidor de aplicação, lentidão da rede, baixo throughput do canal), no banco de dados (queries mal-escritas, ausência de índices nas tabelas, relatórios que recalculam totais todas as vezes que são chamados), na própria aplicação (páginas muito grandes, imagens muito pesadas, navegação pouco eficiente), e também no layout da estrutura física (poucos servidores de aplicação).

É muito importante, também, saber reconhecer que o sistema não é a aplicação! Já vi diversos projetos que funcionaram na fase de testes não apresentarem o mesmo desempenho ao serem postos em produção. O motivo é que testaram se a aplicação aguentava um certo número de usuários simultâneos, quando deveriam ter testado se o sistema aguentava - o que é completamente diferente.

Um sistema é um conjunto de partes que forma o todo. Portanto, a aplicação, aqui, é apenas parte dele. Há que se considerar desde o computador que o cliente usa, passando pelo canal de acesso,  considerar os servidores, o banco de dados, etc. Esse conjunto de peças é o "sistema", cuja performance deve ser testada antes de ir para produção.

Sem eliminar o gargalo o sistema está fadado a um baixo uptime.

O gargalo gera o enfileiramento no servidor de aplicação. Conforme os usuários requisitam páginas ao sistema web, utilizando seus navegadores, os servidores de aplicação tentam atendê-los da melhor maneira possível (pois é a função deles). Se uma determinada página provoca a execução de uma consulta em um banco de dados e este último demora muito para retornar o resultado, o servidor de aplicação vai colocar o usuário em uma fila e vai tentar atender outras requisições. A medida que os pedidos não estejam conseguindo ser atendidos, a fila cresce exponencialmente. O usuário, percebendo a demora, começa a ficar irritado e tende a pressionar F5 ou o reload em seu navegador, o que piora ainda mais a situação. O resultado é que o inimigo vence a batalha: o sistema sai do ar.



Nos próximos posts conheceremos como podemos enfrentar o gargalo - este inimigo indesejável - e derrotá-lo sempre. Até lá!

domingo, 25 de novembro de 2012

Tudo se resume a evitar gargalos...



Após uma década de experiência trabalhando com ajuste fino de sistemas web, posso afirmar, sem sombra de dúvidas, que a frase que intitula este primeiro post no blog sintetiza perfeitamente a idéia do que é a otimização de sistemas que necessitam de alta disponibilidade e desempenho.

Ocorre que, tal qual qualquer serviço disponibilizado a um grande público com canais finitos, há uma tendência a formação de gargalos, que são o maior inimigo do fluxo ininterrupto do processo.

Durante as olimpíadas de Londres em 2012, os organizadores se valeram de uma filosofia conhecida como "go with the flow", na qual eventualmente abriam mão da arrecadação em uma estação de trem, por exemplo, caso o processo de aquisição dos bilhetes pudesse causar um congestionamento de pessoas nas saídas (vale esclarecer que em Londres põe-se o bilhete na saída da estação). Priorizou-se (pontualmente) o fluxo ininterrupto de passageiros em detrimento do faturamento, mas a idéia era evitar situações de risco, que surgiriam se um gargalo fosse instaldo.

Os mesmos princípios podem (e devem) ser aplicados em sistemas web que precisam de um uptime elevado.

É importante salientar que, tal qual a eventual diminuição do faturamento nas estações de trem de Londres durante os jogos de grande público, haverá situações em que será preciso escolher do que abriremos mão no processo, em detrimento de algo de importância semelhante, considerando como principal objetivo o sucesso do processo como um todo.

Como disse o pai da química moderna, Antoine Lavoisier, "na natureza, nada se cria, nada se perde, tudo se transforma". Na informática não seria diferente. Portanto, a questão é mesmo, em última análise, uma arte de ajuste de custo/benefício.

Nos próximos posts mostrarei diversos conceitos e técnicas que podem ser aplicados a qualquer sistema de informática que precise de alta disponibilidade, independente da linguagem de programação utilizada (e essa é a beleza da coisa).

São informações que valem ouro.

Fique ligado!