in ASP.NET

Cache + .NET: Cache de Objetos

Existem diversas técnicas e abordagem para melhorarmos a performance de nossas aplicações e sites. O Cache é uma excelente maneira de economizarmos recursos e melhorar a performance de nossas aplicações, basicamente técnicas de Cache consistem em manter uma versão daquele recurso em uma área de acesso rápido e otimizado (ex: memória).

Existe uma frase, que conheci através do Alexandre Tarifa e do Cleber Dantas:

“O código mais rápido é aquele que não é executado” (adaptação)

Pensando nisto decidi escrever uma série com 4 posts abordando as diversas camadas e técnicas para utilizar Cache com .NET e aplicações Web, vou abordar temas como: Cache de Objetos, OutputCache, Sistemas de Cache Distribuídos e Cache Http.

Neste primeiro post vou abordar o Cache de Objetos, que no caso do .NET consiste em manter objetos na memória do servidor, com um sistema de controle de validade, inserção, atualização, remoção e retorno dos objetos.

O Cache de objetos não contém nenhuma informação sobre o conteúdo dos itens que contem, ele funciona mantendo uma referencia para esses objetos, e fornece métodos para manipular, controlar suas dependências e definir politicas de expiração.

Nas versões anteriores ao .NET 4.0, o ASP.NET era quem provia a implementação do cache em memória, na namespace System.Web.Caching ou seja, antes do .NET 4.0 as aplicações eram dependentes do System.Web. A partir do .NET 4.0 temos uma namespace System.Runtime.Caching que contém a API para cache em aplicações web e não web.

Para este post, vamos utilizar o cache da classe System.Web.Caching.Cache. Uma instancia desta classe é criada por aplicação, e permanece valida enquanto aquela aplicação web permanece ativa. Esta instancia é uma propriedade do objeto

HttpContext.

Adicionando objetos ao Cache

Existe diversas maneiras para adicionar um objeto no cache, para este exemplo vou adicionar uma string de diversas maneiras no Cache.

Adicionando um item diretamente utilizando chave e valor:

HttpContext.Cache["chave1"]= "valor do objeto";

Adicionando um item utilizando o método Insert:

HttpContext.Cache.Insert("chave1","valor do objeto");

Adicionando um item com uma coleções de chaves de objetos no cache, o qual o objeto “chAve3” depende:

string[] dependencias = {"chave1", "chave2"};
HttpContext.Cache.Insert("chave3","valor do objeto",
    new CacheDependency(null,dependencias));

Além da dependência de outros objetos no cache, é possível ter várias outras dependência, que em caso de alteração, o objeto do cache é invalidado.

No exemplo abaixo, qualquer alteração no teste.xml faria o objeto com a chave “chave1” ser invalidado:

HttpContext.Cache.Insert("chave1", "valor do objeto 1",
    new System.Web.Caching.CacheDependency(
    Server.MapPath("teste.xml")));

Outra configuração importante no Cache é a politica de expiração com prazos definidos.Existem duas maneiras de configurar o tempo de expiração: sliding expiration e absolute expiration (detalhes).O tempo de expiração do Cache tem duas maneiras de ser configurado:

  • Absolute Expiration: O objeto em Cache irá expirar em uma determinada data, a partir do momento de inserção do objeto no Cache, independente do seu uso ou não.
  • Sliding Expiration: O objeto em Cache irá expirar após o tempo configurado, a partir da ultima requisição do objeto em Cache.

No exemplo abaixo eu uso Absolute Expiration, o objeto ficará no Cache por 2 minutos:

var objetoCacheado = "Objeto no Cache";

//Absolute Expiration
Cache.Insert("chave1", objetoCacheado, null, DateTime.Now.AddMinutes(2),
            System.Web.Caching.Cache.NoSlidingExpiration);

Neste segundo exemplo, com Sliding Expiration o objeto ficará no Cache por 2 minutos após o ultimo acesso a ele:

var objetoCacheado = "Objeto no Cache";

//Sliding Expiration
Cache.Insert("chave2", objetoCacheado, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
                        TimeSpan.FromMinutes(2));

 

Outra maneira de adicionar um objeto no cache é utilizar o método Add, o que retorna o objeto que representa o item no cache

var objetoCacheado = "Objeto no Cache";

var objetoQueRepresentaoItem = (string)HttpContext.Cache.Add(
    "chave1",
    objetoCacheado,
    null,
    DateTime.Now.AddMinutes(2),
    Cache.NoSlidingExpiration,
    CacheItemPriority.Default,
    null);

Uma opção de configuração durante a inserção de um objeto no Cache é a prioridade de manutenção daquele objeto na memória, que é um Enum

Retornando objetos do Cache

Para retornar um objeto que esteja no Cache é só acessar o objeto através da chave que foi utilizada para armazenar o objeto, caso o objeto não esteja no cache, o valor NULL será retornado.

Como o Cache é volátil, o exemplo abaixo utiliza uma abordagem de desenvolvimento que verifica se o objeto com a chave “chave1” está no Cache, caso ele não esteja, o valor é armazenado no Cache e retornado, caso ele esteja no cache, o valor é retornado:

string cachedString;
cachedString = (string)HttpContext.Cache["chave1"];

if (cachedString == null)
{
    cachedString = "valor da chave no cache";
    HttpContext.Cache.Insert("chave1", cachedString);
}

 

Removendo objetos ao Cache

O Cache do ASP.NET é volátil, um objeto pode ser removido por diversos motivos como:Cache cheio, o objeto expirou ou alguma dependência do objeto foi alterada. Além desses meios, um item do Cache pode ser removido da seguinte maneira:

HttpContext.Cache.Remove("chave1");

 

Exemplo de uso

Como exemplo, vou criar um estrutura para manter as informações de diversos menus (dinâmicos) de um site no cache, no exemplo utilizei um cache de 15 minutos, é impressionante como cenários de alta escala, algum segundos de Cache é a diferença entre 5000 requisições ao banco de dados, contra somente 1 requisição.

Menu

public class Menu
{
    public List<string> Items { get; set; }
}

MenuRepository

public class MenuRepository
{
    public Menu Load(int menuId)
    {
        //TODO:Carregar do banco
        return new Menu();
    }
}

MenuService (responsável por orquestrar se o objeto será retornado no cache ou diretamente do banco de dados e armazenado no cache antes de retornar):

public class MenuService
{
    public Menu Load(int menuId)
    {
        var cacheKey = string.Format("menu_{0}", menuId);

        var menuNoCache = (Menu)System.Web.HttpContext.Current.Cache[cacheKey];
        if(menuNoCache==null)
        {
            var menuRepository = new MenuRepository();
            menuNoCache = menuRepository.Load(menuId);

            System.Web.HttpContext.Current.Cache.Insert(
                cacheKey,
                menuNoCache,
                null,
                DateTime.Now.AddMinutes(10),
                Cache.NoSlidingExpiration);
        }

        return menuNoCache;
    }
}

 

Evitar transferência de redes, idas ao banco de dados e execução de algumas queries podem ser fundamentais no ganho de performance.

Espero que este post seja útil, no próximo post falarei um pouco sobre OutputCache.

Estou a disposição para duvida, criticas e sugestões

Abs

Rodolfo

  • Anonymous

    Muito bom!

    Esperando pelos próximos posts 😉

  • http://cleytonferrari.com/ Cleyton Ferrari

    Muito bom o artigo, bem didatico, gostei da parte do Sliding
    Expliration, a idéia seria pra usar em processos que demorem para gerar
    cache? tipo: enquanto recebe acesso mantenha o cache, se passar X tempo,
    faça um novo cache.

    Fiz uns tentes equi e funciona muito bem, já
    tinha brincado com cache HTTP, mais o de objeto ainda não tinha
    brincado, muito bom mesmo o artigo parabens!

  • Bruno Salgueiro

    Muito bom cara, tenho uma sugestão, que tal colocar alguma coisa sobre CDN’s?

  • http://www.rodolfofadino.com.br/2013/10/cache-net-outputcache/ Cache + .NET: OutputCache – // Rodolfo Fadino

    […] eu disse em um post anterior (Cache + .NET: Cache de Objetos), existem diversas técnicas para conseguirmos melhorar a performance de nossas aplicações web. […]

  • Luís Gabriel Nascimento Simas

    Rodolfo, eu tenho algumas entidades, eu posso colocá-las no Cache? qual seria a boa prática? colocar no repositório ou apenas colocá-las no tratamento da camada de apresentação?

  • Carlos Rogerio

    Muito bom o artigo, parabéns…