Cache pode não ser a solução do seu SQL
Há muitos anos, venho trabalhando como consultor de aplicações web de alto desempenho e constantemente me deparo com implementações de cache para evitar requisições ao SQL.
Será mesmo que o cache é a salvação do seu SQL? É o cache a sua solução? Pra mim, não!
Em geral, developers não tem o hábito de estudar e entender como as consultas SQL são geradas pelo Entity, nem como são processadas no SQL, razão pela qual quase sempre suas consultas não são performáticas. Além do mais, cotidianamente me deparo com lógicas que denigrem o acesso à dados, geralmente fazendo mau uso da conexão ao servidor de dados, ou consultando dados em Loops ou ainda trazendo informações absolutamente desnecessárias para o contexto da lógica.
Em geral, a primeira medida é criticar a performance do servidor de dados e implementar de forma indiscriminada, um cache em memória para evitar uma segunda consulta.
Quandas vezes vocês não viram a famosa lógica:
Se não está no cache, pega no banco, preenche o cache e retorna para o usuário.
Essa prática muito comum, apenas mascara o real problema das aplicações que geralmente, estão com a modelagem equivocada ou acessando dados incorretamente.
Pergunto para você developer: Quantas queries suas, você analisou o Plano de Execução? Ou viu através do Output, a real consulta SQL que está sendo executada pelo Entity ou NHibernate?
Além do mais, será que a lógica que você está usando, contempla reaproveitamento do resultado da consulta? Ou dentro de um laço, você está consultando mais informações, ainda que inconscientemente por conta do LazyLoading?
Nesses casos, que a aplicação apresenta falta de performance no acesso à dados, a primeira medida é implementar o cache seguindo a lógica supracitada. E no fundo o que está acontecendo, é mascarar o problema, nada mais.
Um cache mal planejado, pode ser tão ou mais grave que um acesso ruim aos dados. De modo geral, as implementações não esperam múltiplas requisições, como ocorre quando o cache é reiniciado, causando novamente múltiplos acessos à base, evidenciando novamente o problema de lógica.
Um cache mal planejado também pode honerar de forma significativa, os recursos de memória dos servidores e, quando há um Cluster Web com várias máquinas, ao menos uma requisição por máquina chegará ao SQL Server, e continuará lenta.
Um cache mal planejado pode inclusive, derrubar toda sua rede devido ao alto tráfego de dados desnecessários. Já vi casos de servidor web não aguentar a demanda ao se comunicar com o Redis em testes de stress.
Um cache mal planejado, geralmente não está com sua classe "manager" orientada à objetos e quase sempre, expõe por toda a aplicação, as chaves de cache. Além de fugir dos conceitos de SOLID, pode causar problemas ao permitir gravação ou deleção de dados equivocados.
Para finalizar, deixo algumas perguntas chaves para ajudar na análise de suas soluções:
- Seu dado, precisa estar cacheado com todas as informações que lá estão?
- Seu foi planejado, ou só está lá para evitar acesso ào SQL?
- Se você tiver um Farm Web, suas máquinas possuem cópias diferentes do seu cache? Como você garante integridade?
- Qual o tamanho do seu cache em chaves e bytes?
Espero que esse pequeno artigo possa levá-los a refletir sobre a forma como as informações são tratadas em cache e sua respectiva necessidade.
Até breve,
Lucas Massena - Enterprise .NET Architect