Podemos colocar um servidor de cache entre nosso aplicativo e o banco de dados para tornar nossos aplicativos mais rápidos. Mas isso não é suficiente quando precisamos dimensionar nossos aplicativos. Vamos ver dois padrões de cache para melhor desempenho e como NCache os implementa.
Escalabilidade através do particionamento de dados
Com o particionamento de dados, dividimos grandes conjuntos de dados em conjuntos menores e os distribuímos entre os nós. Dessa forma, dividimos as leituras e gravações entre os nós, melhorando o desempenho geral de nossas aplicações. NCache suporta diferentes topologias de cache. Nesse contexto, uma topologia é uma estratégia de armazenamento de dados, replicação e conectividade do cliente. Existem duas topologias que implementam o particionamento de dados: a Topologias particionadas e de réplica de partição. Nessas duas topologias, NCache divide os dados em baldes e coloca esses baldes nos nós do nosso cluster.
NCache usa 1000 baldes e os divide igualmente entre os nós em um cluster. Por exemplo, se iniciarmos um cluster de cache com um único nó, NCache atribui todos os baldes ao nosso único nó. Se adicionarmos outro nó, NCache divide esses 1000 baldes em dois nós de 500 baldes. Além disso, se removermos um nó, NCache distribui seus baldes nos nós restantes.
Como NCache divide nossos dados em baldes e nós, um cliente de cache se conecta a todos os nós, mas executa operações de leitura e gravação diretamente no nó que contém um item. Mesmo que um nó não esteja disponível, um cliente de cache redireciona nossas solicitações usando os nós ativos para concluir nossas operações. NCache distribui baldes entre os nós mantendo o tamanho dos dados em cada nó quase o mesmo. Dessa forma, não apenas dividimos as leituras e gravações entre os nós, mas também aumentamos a capacidade de armazenamento do nosso cluster a cada nó que adicionamos.
Graças ao particionamento de dados, as topologias Partition e Partition-Replica dimensionam a carga da transação e a capacidade de armazenamento. Claro, Partição e Partição-Replica são apenas duas das topologias suportadas. NCache tem mais topologias com diferentes estratégias de armazenamento e replicação de dados. Por exemplo, alguns deles são adequados para aplicativos com mais leituras ou gravações.
Estratégias de cache
Com o particionamento de dados, melhoramos a disponibilidade e o desempenho de nossos aplicativos, pois podemos armazenar em cache mais itens em nosso cluster do que em um único servidor. Além disso, podemos melhorar o desempenho de nosso aplicativo escolhendo como populamos nosso cache. Existem duas estratégias para preencher nosso cache: cache-aside e Read-Through/Write-Through.
Com a estratégia de cache-aside, nosso servidor de cache fica próximo ao nosso banco de dados. Se nosso cache não contiver um item, nosso aplicativo o lê de nosso banco de dados e o armazena no cache. Com esta estratégia, o servidor de cache não interage diretamente com nosso banco de dados. Provavelmente, a estratégia de cache-aside é o que primeiro vem à nossa mente quando pensamos em cache.
Ao contrário da estratégia de cache-aside, com as estratégias Read-Through/Write-Through, nosso cache funciona como a principal fonte de dados. Aqui, nosso cache lê e grava dados no banco de dados. Portanto, essas estratégias funcionam melhor com dados de referência que lemos com frequência e mudamos periodicamente, e com linhas de banco de dados que podemos mapear facilmente para itens de cache.
Com Read-Through/Write-Through, movemos parte do código de acesso a dados de nosso aplicativo para o cache, tornando o código de nosso aplicativo mais simples e menor. NCache suporta as estratégias de cache Read-Through e Write-Through.
Cache de leitura
NCache usa um provedor Read-Through personalizado para chamar o banco de dados subjacente se houver uma falta de cache. Além disso, podemos forçar NCache para sempre ler o banco de dados, mesmo que não haja falta de cache. Nosso provedor Read-Through deve implementar o Interface IReadThruProvider. Ele contém métodos como CarregarFromSource e LoadDataTypeFromSource.
Quando tivermos um Provedor de leitura implantado em nosso servidor de cache, seja por meio do NCache Manager ou scripts do PowerShell, podemos usá-lo em nossos aplicativos clientes passando o objeto ReadThruOptions como parâmetro para o método Get, assim,
1 2 3 4 5 6 7 8 9 10 11 |
// After having NCache up and running... var key = $"Product:123456"; var readThruOptions = new ReadThruOptions { Mode = ReadMode.ReadThru }; // Retrieve a cached item with Read-Thru enabled var data = cache.Get<Product>(key, readThruOptions); // Do something with the cached product here... |
Cache de gravação
Por outro lado, com a estratégia Write-Through, NCache atualiza primeiro nosso cache e, só depois, nosso banco de dados. NCache pode atualizar nosso banco de dados de forma síncrona ou assíncrona. NCache chama atualizações Write-Through assíncronas: Write-Behind.
Nosso provedor Write-Through deve implementar o Interface IWriteThruProvider. Ele contém o método WriteToDataSource com sobrecargas para itens únicos e múltiplos e estruturas de dados. Nosso provedor Write-Through deve oferecer suporte a operações de gravação para adicionar, excluir e atualizar itens.
Semelhante à implantação de um provedor Read-Through, precisamos implantar nosso Provedor de Write-Through à nossa cache. Depois de implantar nosso provedor, em nossos aplicativos clientes, devemos passar o Opções WriteThru objeto ao inserir itens no cache, assim,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// After having NCache up and running... var product = BuildProduct(); var key = $"Product:{product.ProductId}"; var cacheItem = new CacheItem(product); var writeThruOptions = new WriteThruOptions { Mode = WriteMode.WriteThru; } // Add an item with Write-Thru enabled cache.Insert(key, cacheItem, writeThruOptions); |
Read-Through e Write-Through nos ajudam a melhorar a escalabilidade e o desempenho de nossos aplicativos. Com Read-Through, nossos itens em cache estão sempre disponíveis desde NCache pode ler itens expirados automaticamente. E, com o Write-through, nosso aplicativo não precisa esperar pelas gravações do banco de dados, pois NCache pode atualizar nosso banco de dados de forma assíncrona e, mesmo com um mecanismo de limitação, reduzindo a pressão em nosso banco de dados.
Conclusão
Esses são dois padrões de cache para melhor desempenho e escalabilidade: particionamento de dados e estratégias de cache. Podemos usar NCache para implementá-los em nossas aplicações. Com o particionamento de dados, dividimos as leituras e gravações entre os nós e aumentamos a capacidade de armazenamento do nosso cache. Nós temos NCache Topologias de partição e réplica de partição para isso. E com Read-Through/Write-Through, tornamos nosso servidor de cache a fonte de dados, tirando um pouco da pressão de nosso banco de dados.
Para saber mais detalhes sobre particionamento de dados e Read-Through/Write-Through, consulte estes dois guias: Topologias particionadas e de réplica de partição e Provedores de fonte de dados para cache. Se você quiser se beneficiar desses dois padrões de cache para dimensionar seus aplicativos, forneça NCache uma tentativa.