Otimizando a performance do seu sistema – Cache

Quantas vezes já experienciamos, seja num caixa de supermercado ou num balcão de fast-food, a frustração de ouvir do atendente a frase “Desculpe, meu sistema travou”. Frustrante pra nós, que ficamos parados esperando o sistema voltar a funcionar, desesperador para a atendente que vê sua fila crescer em clientes, impacientes. Preocupante para o gerente da loja, que vê clientes desistirem das compras e deixarem reclamações nas caixinhas. Aborrecedor para o dono que vê sua produtividade caindo…

Enfim! Acho que já consegui te convencer da importância do bom desempenho de um sistema!

Meu sistema está lento. E agora?

O primeiro passo é identificar os pontos de lentidão, ou gargalos. Comece investigando os cenários em que essa lentidão fica mais evidente. A menos que nesses cenários seu sistema faça operações muito custosas, como processamento de imagem ou geração de grandes relatórios, os gargalos devem ser no acesso a dados, seja banco de dados ou serviços externos.

Mas então, o que fazer?

Um desenvolvedor te dará as seguintes alternativas: Índice no Banco de Dados e Cache. Respectivamente.

O responsável pela infraestrutura de banco de dados do seu sistema provavelmente já fez um levantamento das consultas mais utilizadas e criou os índices necessários nas tabelas. Então esse não deverá ser o caminho a ser seguido. Índices de banco nem sempre representam ganho geral. Funciona como uma solução de compromisso. Em uma oportunidade futura podemos discutir sobre índices de banco.

Nos resta, então, o Cache: e é nele em que iremos nos aprofundar.

Em computação, Cache é definido como toda estrutura de acesso rápido que faz o intermédio entre a aplicação, onde ocorre um processo, e uma estrutura de armazenamento de dados que armazena informações necessárias no processo. O objetivo do Cache, então, é disponibilizar essas informações necessárias ao processo sem que haja necessidade de acessar o dispositivo de armazenamento, que geralmente é demorado, e com isso ganhar velocidade.

Esse artigo procura discutir as estratégias de cacheamento que podem ser empregadas em uma aplicação. Das estratégias que serão discutidas aqui, vamos dividí-las quanto ao Ciclo de Vida e quanto a Abordagem.

Ciclo de Vida

O ciclo de vida de uma estrutura de Cache está diretamente ligado à quão dinâmica é a informação que ele armazena.

Perenes

Alguns parâmetros de configuração do sistema podem ficar armazenados em banco de dados afim de dar flexibilidade ao sistema evitando alterações em código quando tais configurações mudam. Porém, tipicamente, essas configurações não mudam. Ou mudam raramente e geralmente aliadas a uma nova publicação. Nesse cenário, temos consultas sendo realizadas a banco de dados sempre retornando o mesmo valor. Diante disso, uma boa abordagem é inicializar tais configurações em Cache, sendo eager-load ou lazy-load. Assim, enquanto seu sistema estiver operando, ele só terá realizado consulta em banco para obter tais configurações uma única vez.

Longa Duração

Seu sistema pode ter algumas entidades que, apesar de não serem alteradas com frequência, não se encaixam na abordagem acima por serem grandes e/ou terem muitos registros.

 

Exemplo: Um sistema de vendas para uma concessionária de automóveis deve consultar as informações do veículo como modelo, potência, consumo, valor de tabela, tamanho do bagageiro, entre outros. Durante o dia são várias requisições para tal valor. Esse valor, porém, não deve variar com um período menor que uma semana. Ainda, existe um número considerável de modelos, o que inviabiliza carregar todos em memória.

 

A melhor abordagem, portanto, seria, ao carregá-lo (após uma requisição de alguma tela) deixá-lo por algum tempo (mais ou menos uma hora) em Cache, para que futuras requisições nesse intervalo possam utilizar o valor em Cache, economizando a consulta ao banco.

Nessa abordagem é importante um conhecimento da lógica de negócio e um estudo mais aprofundado das entidades para sintonizar o tempo de Cache.

Por Transação

Mesmo entidades dinâmicas podem ser armazenadas em Cache. Basta garantir que, enquanto em Cache, ela não será alterada no banco. É possível ter essa garantia se pensarmos em transação. Dentro de uma transação, pode ser necessário obter a mesma entidade em diferentes momentos sem que seja possível trafegá-la pelo código.

 

Exemplo: Em um sistema de caixa eletrônico de banco, existem vários clientes (caixas eletrônicos) consumindo serviços centralizados. Milhares de contas correntes fazem requisições ao servidor ao mesmo tempo, porém, não é possível acessar, em duas máquinas, a mesma conta corrente. Em uma operação bancária, saque, por exemplo, informações da conta serão alteradas, como o saldo. Porém, durante a requisição que o caixa eletrônico faz ao serviço, a conta corrente terá o mesmo valor, e apenas ao final da transação será alterada.

 

Abordagem

Objeto

Nos exemplos anteriores essa abordagem foi a utilizada. O que está em memória é o próprio objeto utilizado e ele é buscado através da sua chave no banco. Nessa abordagem o Cache é um intermediário entre aplicação e banco de dados, e se difere do último na velocidade.

Método

Uma outra abordagem é armazenar em memória resultados de operações lentas.

Exemplo: Um sistema de e-Commerce precisa sempre estar alinhado com a situação do estoque da loja, por questões logísticas. O valor e prazo do frete, por exemplo, pode depender da posição em que o produto se encontra no estoque. Quando um cliente busca pelo produto no site, o sistema deve verificar se esse produto está disponível em estoque. Ao realizar a compra, é necessário informar também a quantidade de produtos que estão disponíveis. No banco de dados existe uma tabela para o produto, com informações de marca, valor, especificação, outra para o item, com informações para nota fiscal, código único, e uma terceira para o estoque, que relaciona item com a sua posição no estoque e sua disponibilidade de pronta entrega. Na tabela de item pode existir ainda uma informação sobre “reserva” para impedir que outro cliente compre aquele produto enquanto um primeiro já o colocou em seu carrinho de compras. Quando um usuário faz a busca pelo produto, entra na sua página ou o adiciona em seu carrinho de compras, é necessário varrer essas três tabelas e consistir informação de quantos itens do produto estão disponíveis para a pronta entrega. Essa consistência pode ficar ainda mais complexa caso existam vários centros de distribuição no país e essa disponibilidade seja ponderada pela logística envolvida na entrega do item para o cliente. Bom, essa validação é muito complexa, mas é fácil imaginar que ela não vai ter alterações significativas durante o processo de compras do cliente. E nem é tão crítica, a menos quando na efetivação da compra. Esse método de validação teria como parâmetros o id da sessão do usuário, o CEP de entrega, o produto pesquisado e, como saída, um agrupamento de itens com diferentes prazos e preços de frete. (Ex.: 6 itens existem no centro de distribuição da mesma cidade e está a pronta entrega e frete grátis. Já outros 15 itens estão num centro de outro estado e tem prazo de 10 a 15 dias e frete a R$10,00). A abordagem seria fazer um Cache da estrutura de agrupamento de itens tendo como chave o método do código que faz essa validação e os parâmetros (sessão, CEP e item). Aqui, existe uma premissa de que estamos comprometendo a precisão dessa validação em prol do desempenho e assumimos o risco de errar algumas vezes quando o mesmo item é comprado por outro usuário durante o fluxo de compra. Esse risco é minimizado quando, para a operação crítica de venda, não fazemos uso do Cache para garantir que o cliente comprará um item disponível.

A utilização correta de Caches pode melhorar a performance do seu sistema. Com as estratégias corretas de cacheamento, você vai evitar transtornos e aumentar os graus de satisfação dos usuário (diretos e indiretos) do seu sistema!

 

Por: Thalisson Scarabelli
Revisão: Dandara Chaves

 

Fonte da imagem: UOL

Deixe um comentário