in C#

Cache + .NET: Sistemas de Cache Distribuído

Neste terceiro post da série de Cache + .NET vou abordar sistemas de cache distribuído, um conceito muito importante em cenários de grande escala e muita concorrência. É muito importante testar e utilizar sistemas de cache distribuído quando o uso e cenário fizer sentido, isso varia muito do perfil e tamanho de sua aplicação e volumes de acesso.

Sistemas de Cache Distribuídos

Para este post vou caracterizar um sistema de cache distribuído como um sistema heterogêneo, que armazena objetos em memória, por determinado tempo, e com um ferramental de inserção e manutenção (purge, insert, get), executado em diversos servidores, e que se conecta com seus clientes ou demais partes do sistema utilizando TCP/IP (exemplo), proporcionando uma grande escalabilidade horizontal (adicionando mais servidores), redundância, resiliência, disponibilidade e performance.

Outro fator muito importante em sistemas de cache distribuídos é a divisão clara de responsabilidades e alocação de recursos, com eles um servidor de cache tem a única responsabilidade de oferecer o serviço de cache, bem diferente do cache na memória de um web server, que tem diversas responsabilidades como processamento das páginas, de arquivos estáticos e outras funções.

Sistemas de cache distribuídos são cruciais se você tem um cluster com vários servidores para consumir e utilizar o cache, se você tem 5 web servers, todos podem compartilham as mesmas informações que estão em um sistema de cache distribuído, todos estão escrevendo e lendo do mesmo cache. Se o servidor A lê um conteúdo do banco de dados e coloca no cache, um outro servidor B ou C pode se beneficiar, acessando diretamente o cache que já foi “carregado” anteriormente.

Desvantagens

Se sua aplicação não possui um cluster ou nbl com vários servidores, sendo executada em um único servidor, provavelmente um sistema de cache distribuído não trará muitos ganhos, para este cenário o cache do .NET provavelmente será a melhor opção.

Acessar o cache em sistemas distribuídos traz uma pequena perda de performance devido a comunicação vida rede entre a aplicação e o sistema de cache (por isso é extremamente importante analisar a qualidade e latência da rede de comunicação)

Além disso, um sistema de cache distribuídos é executado em uma outra máquina, o que significa que você precisa provisionar, instalar, configurar, manter e monitorar o sistema.

Memcached

image

O Memcached é um sistema de cache distribuído em memória, gratuito, open source e extremamente performático. Ele pode ser utilizando em Windows ou Linux, em ambientes de produção eu aconselho fortemente o uso do Memcached instalado no CentOS como sistema operacional. Com essa dupla, eu mantenho máquinas de perfil extremamente baixo (4cores, 2Ram) em um ambiente virtualizado (utilizando o Hyper-V) que conseguem atender ambientes de produção com +- 10.000 hits por minuto.

Memcached.ClientLibrary

Existem diversas maneiras para utilizar e se comunicar como o Memcached, utilizando a plataforma .NET, uma das bibliotecas para isso é a Memcached.ClientLibrary, que pode ser instalada utilizado o Nuget Package Manager.

PM> Install-Package Memcached.ClientLibrary

Com ele instalado é possível armazenar e consultar objetos armazenados no Memcached.

image

Após adicionar o Memcached.ClientLibrary, podemos instanciar o Pool com os sevidores de Memcached, e utilizar os principais comandos do Memcached. Notem que o objeto armazenado tem que ser Serializable.

class Program
{
    static void Main(string[] args)
    {
        //Servidores de memcached
        var servers = new string[] { "127.0.0.1:11211" };
        var pool = SockIOPool.GetInstance();
        pool.SetServers(servers);
        pool.Initialize();

        var chave = "usu_1";
        Usuario usuario;

        var client = new MemcachedClient();
        //Verifica se a chave existe
        if (client.KeyExists(chave))
        {
            //Retorna a chave
            usuario = (Usuario)client.Get(chave);
        }
        else
        {
            //Consulta no banco por exemplo
            usuario = new Usuario() { Nome = "Rodolfo", Id = 123 };
            //Armazena no cache  por 15min
            client.Set(chave, usuario, DateTime.Now.AddMinutes(15));
        }

        //Remove do cache
        client.Delete(chave);
    }
}
[Serializable]
public class Usuario
{
    public int Id { get; set; }
    public string Nome { get; set; }
}

 

Dicas

  1. Cuidado com o tamanho do objeto que você for armazenar, desenvolva uma aplicação para que o cache se “reconstrua” sem muito impacto (ao invés de colocar uma tabela inteira em um chave, coloque ela gradativamente, separada em diversas chaves, isso favorece e melhora a performance da aplicação);
  2. Cuidado com a rede, por se tratar de uma comunicação em um sistema extremamente rápido,acessar o servidor de cache não pode ser impactado por uma rede com muita latência, utiliza sempre rede local;
  3. Pense em uma estratégia para economizar ao máximo consultas e processamento de informações desnecessárias, ou que podem ser cacheadas;
  4. Cuidado com chaves muito grande, utilizar chaves muito grandes para armazenar os objetos no cache pode provocar um maior overhead do que o necessário.

Bom espero que este post seja útil, estou a disposição para dúvidas, criticas e sugestões.

Abs

Rodolfo

  • Bruno Salgueiro

    Rodolfo você mencionou sobre o problema de performance entre a aplicação e o sistema de cache, será que se configurarmos a comunicação da rede para net/tcp, não diminuiria esse overhead?

  • http://www.rodolfofadino.com.br/ Rodolfo Fadino

    Fala Bruno, tudo bom? Então, a maioria dos sistemas de cache distribuídos utiliza TCP (o que é performático, desde que você tenha uma rede de comunicação entre os servidores com uma boa performance e sem latência), pelo o que eu li o net.tcp é um modelo de comunicação e binding de aplicações .NET (ServiceModel) e que utiliza o TCP http://msdn.microsoft.com/en-us/library/system.servicemodel.nettcpbinding.aspx http://msdn.microsoft.com/en-us/library/ms731343.aspx