Neste artigo, veremos como uma solução de cache distribuído pode melhorar drasticamente o desempenho geral e a taxa de transferência de seu aplicativo baseado em microsserviços.
Em um aplicativo típico baseado em microsserviços, vários microsserviços trabalham juntos enquanto permanecem fracamente acoplados e escaláveis. O aplicativo possui serviços que são necessários para atender aos principais requisitos de negócios, como acompanhar e processar dados críticos de negócios. Há também microsserviços dedicados adicionais que lidam com identidade e autenticação, integridade e monitoramento de carga, além de servir como gateways de API.
Um recurso importante desse aplicativo é que cada microsserviço seja projetado, desenvolvido e implantado de forma independente usando qualquer pilha de tecnologia que você desejar. Como cada microsserviço é um aplicativo autônomo autônomo por direito próprio, ele também mantém seu armazenamento persistente separado, seja um banco de dados relacional, um NoSQL DB ou até mesmo um sistema de armazenamento de arquivos legado. Isso permite que os microsserviços individuais sejam dimensionados de forma independente e torna as alterações de infraestrutura em tempo real muito mais gerenciáveis.
NCache Adicionar ao carrinho Microsserviços com NCache Dimensionar Pub/Sub em microsserviços
Por que seu microsserviço precisa NCache?
Há casos em que ainda surgem gargalos durante o aumento de transações no aplicativo. Isso é predominantemente comum em arquiteturas onde os microsserviços armazenam dados em bancos de dados relacionais que não permitem escalonamento. Em tais situações, expandir o microsserviço implantando mais instâncias dele não resolve o problema.
Para combater esses problemas, você pode introduzir facilmente NCache como seu cache distribuído na camada de cache entre seus microsserviços e os armazenamentos de dados. NCache também ajuda como um agente de mensagens de editor/assinante escalonável na memória para permitir comunicações assíncronas entre microsserviços.
Escalabilidade por meio do Pub/Sub
A comunicação de microsserviços é frequentemente implementada usando o modelo Publicador/Assinante que permite a troca de mensagens entre microsserviços, mantendo-os fracamente acoplados. Nesse sentido, NCache funciona como um agente de mensagens Pub/Sub escalonável na memória por meio do qual todos os microsserviços que compõem o aplicativo podem publicar e assinar eventos. O recurso de escalabilidade e confiabilidade inerente com NCache clustering são traduzidos automaticamente quando chegamos ao pub/sub. Saiba mais sobre NCache como agente de mensagens no ambiente de microsserviços através do nosso blog em Dimensionamento da comunicação de microsserviços .NET com Pub/Sub na memória.
NCache Adicionar ao carrinho Mensagens do Pub/Sub em NCache Dimensionar Pub/Sub em microsserviços
Escalabilidade por meio de cache
NCache oferece escalabilidade em tempo real, permitindo que você adicione quantos nós de servidor desejar em seu cluster de cache em execução sem incorrer em qualquer tempo de inatividade do aplicativo. Usando NCache não apenas melhora o desempenho geral dos microsserviços individuais, atuando como um armazenamento rápido na memória, mas também facilita um aumento acentuado no tempo de resposta e na disponibilidade do aplicativo por meio de sua arquitetura de clustering. Isso é especialmente verdadeiro ao considerar fluxos de trabalho envolvendo dezenas de microsserviços espalhados por vários hosts.
Como usar NCache para Cache de Dados?
Com o NCache No lugar, se um microsserviço requer dados, ele primeiro verifica o cache em vez de acessar diretamente o banco de dados todas as vezes. Dado que os dados acessados com mais frequência geralmente representam uma pequena parte de todos os dados disponíveis no armazenamento de dados, ter esses dados já armazenados em cache e disponíveis para uso reduz bastante a latência relacionada ao banco de dados, além de facilitar a carga no banco de dados, pois a maioria das solicitações de dados são atendidas pelo próprio cache.
Vendo como um aplicativo baseado em microsserviços é inerentemente mais lento do que quando construído usando uma estrutura de design monolítica, fica claro que você precisa do ganho de velocidade oferecido por NCache. NCache, em um nível de microsserviço, pode ajudar a alavancar o poder de uma arquitetura de microsserviços enquanto reduz a latência geral observada durante transações longas que abrangem vários serviços trabalhando sequencialmente.
NCache tem vários recursos prontos para uso que fornecem controle refinado sobre as operações de cache. Essas operações incluem a aplicação de consistência de cache usando expiração e sincronização de banco de dados, APIs avançadas que ajudam a implementar recursos de cache-aside e cache-through usando provedores de origem de apoio. NCache também fornece operações de consulta semelhantes a SQL no cache usando consulta SQL, além de servir como provedores de cache para mapeadores relacionais de objeto (ORM), como EF Core.
Para começar com NCache em seu aplicativo baseado em microsserviços, a primeira coisa que você precisa é configurar os serviços. Isso fornece as informações necessárias que seus microsserviços precisam para começar a usar NCache. Uma visão geral de como você pode criar um contexto mútuo entre NCache e seu aplicativo baseado em microsserviços é mostrado abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public IServiceProvider ConfigureServices(IServiceCollection services) { //Add additional code here services.AddDbContext<CatalogContext>(options => { var cacheID = configuration["CatalogCache"]; if (string.IsNullOrEmpty(cacheID)) cacheID = "CatalogCache"; NCacheConfiguration.Configure(cacheID, DependencyType.Other); // Changing default behavior when client evaluation occurs to throw. // Default in EF Core would be to log a warning when client evaluation is performed. options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning)); //Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval }); var container = new ContainerBuilder(); container.Populate(services); return new AutofacServiceProvider(container.Build()); } |
O que você precisa fazer agora é implantar um controlador com a lógica que permite que ele obtenha um item do cache se o encontrar lá. Caso contrário, o controlador busca o item no banco de dados e o armazena no cache. A implementação de tal controlador é mostrada abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
[Route("api/v1/[controller]")] [ApiController] public class CatalogController : ControllerBase { private readonly CatalogContext _catalogContext; private readonly CatalogSettings _settings; private readonly ICatalogIntegrationEventService _catalogIntegrationEventService; public CatalogController(CatalogContext context, IOptionsSnapshot<CatalogSettings> settings, ICatalogIntegrationEventService catalogIntegrationEventService) { _catalogContext = context ?? throw new ArgumentNullException(nameof(context)); _catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService)); _settings = settings.Value; } [HttpGet] [Route("items/{id:int}")] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType(typeof(CatalogItem), (int)HttpStatusCode.OK)] public async Task<ActionResult<CatalogItem>> ItemByIdAsync(int id) { if (id <= 0) { return BadRequest(); } CatalogItem item = null; var cache = _catalogContext.GetCache(); string catalogItemKey = "CatalogItem:" + id; //Getting item from cache item = cache.Get<CatalogItem>(catalogItemKey); if (item == null) { item = await _catalogContext.CatalogItems.SingleOrDefaultAsync(ci => ci.Id == id); cache.Insert(catalogItemKey, item); } // Your logic here if (item != null) return item; return NotFound(); } } |
NCache Adicionar ao carrinho Microsserviços com NCache
Percorramos seus detalhes para conhecer os verdadeiros encantos de NCache em microsserviços.
Mantenha o cache atualizado, sempre
Há uma advertência importante ao usar um cache relacionado ao cache que retém dados "antigos" quando comparados ao conteúdo do armazenamento de dados primário subjacente. Para garantir que qualquer microsserviço receba dados atualizados de seu cache, você precisa atualizar os dados do cache regularmente. Felizmente, NCache oferece recursos como Sincronização de banco de dados e Expiration para garantir que os dados permaneçam consistentes com os do armazenamento de dados primário.
Você pode manter um nível de sincronização do cache com o armazenamento de dados simplesmente adicionando um intervalo de tempo de expiração aos itens armazenados em cache. Uma vez expirado, NCache remove o item armazenado em cache para que as solicitações subsequentes para essas mesmas informações resultem no armazenamento em cache dos dados atualizados. NCache oferece ambos absoluto assim como Deslizamento estratégias de expiração e você pode usar qualquer uma delas dependendo da natureza transitória dos dados em questão.
Como exemplo, o trecho de código a seguir mostra com que facilidade você pode introduzir a expiração absoluta em um item de cache específico:
1 2 3 4 |
var cacheItem = new CacheItem(product); var expiration = new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5)); cacheItem.Expiration = expiration; cache.Insert(key, cacheItem); |
Para usar a expiração deslizante, tudo o que você precisa fazer é alterar o ExpirationType como tal:
1 |
var expiration = new Expiration(ExpirationType.Sliding, TimeSpan.FromMinutes(5)); |
Um requisito importante ao definir expirações em qualquer cache para manter a consistência dos dados do cache é que os tempos de expiração definidos devem estar de acordo com a rapidez com que a parte específica dos dados está mudando no armazenamento de dados. Se você definir os tempos de expiração muito curtos, os dados poderão ser removidos desnecessariamente e resultarão em uma viagem de armazenamento de dados desnecessária e cara; se o tempo de expiração for muito longo, dados obsoletos podem ser usados.
NCache Adicionar ao carrinho Expiração de dados em NCache
Encontrar os valores ótimos para tempos de expiração, portanto, requer conhecimento profundo dos padrões de mudança de estado dos dados, o que geralmente não é viável. Quando os requisitos de consistência de cache se tornam mais rigorosos, as estratégias de sincronização de banco de dados são a abordagem recomendada. NCache fornece várias estratégias de sincronização de banco de dados a esse respeito.
Usando-os, você pode sincronizar o cache com o armazenamento de dados sem precisar entrar nos padrões de acesso a dados de cada parte da informação, conforme necessário ao usar a expiração. Agora, sempre que houver qualquer alteração nesse item no lado do armazenamento de dados, o cache poderá remover esse item automaticamente sem demora.
Para ver isso em ação, o trecho de código a seguir demonstra como você pode sincronizar NCache com um banco de dados SQL Server adicionando NCache Dependência SQL nos itens em cache.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Creating SQL Dependency string query = "SELECT ProductName, UnitPrice FROM dbo.Products WHERE CategoryID = 'Dairy';"; SqlCacheDependency sqlDependency = new SqlCacheDependency(connectionString, query); // Get orders that contain products with given category ID Order[] orders = FetchOrdersByProductCategoryID("Dairy"); foreach (var order in orders) { // Generate a unique cache key for this order string key = $"Order:ProductCategory-Dairy:{order.OrderID}"; // Create a new cacheitem and add sql dependency to it CacheItem item = new CacheItem(order); item.Dependency = sqlDependency; //Add cache item in the cache with SQL Dependency cache.Insert(key, item); } |
Consulta SQL no Cache
NCache oferece aos seus microsserviços a capacidade de consultar dados de cache indexados por meio de um mecanismo de consulta semelhante ao SQL. Esse recurso é valioso nos casos em que os valores das chaves nas quais as informações necessárias são armazenadas são desconhecidos. Isso também abstrai grande parte das chamadas de API de cache de nível inferior e torna o código do aplicativo bastante mais fácil de entender e manter. Esse recurso prova ser adequado exclusivamente para você, se estiver mais confortável com comandos do tipo SQL.
Um trecho de código de exemplo demonstrando o uso do NCache O recurso de consulta SQL é fornecido abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
string query = "SELECT * FROM FQN.Product WHERE ProductID > ?"; // Use QueryCommand for query execution var queryCommand = new QueryCommand(query); // Providing parameters for query queryCommand.Parameters.Add("ProductID",50000); // Executing QueryCommand through ICacheReader ICacheReader reader = cache.SearchService.ExecuteReader(queryCommand); // Check if the result set is not empty if (reader.FieldCount > 0) { while (reader.Read()) { string result = reader.GetValue<string>(1); // Perform operations using the retrieved keys } } else { // Null query result set retrieved } |
As consultas SQL podem funcionar com índices de consulta, o NCache estruturas de dados distribuídas, bem como tags de cache. Siga o link para mais informações sobre como usar o NCache Recurso de consulta SQL.
NCache Adicionar ao carrinho Consulta SQL em NCache
Read-Thru e Write-Thru
Com o NCache Provedores de fonte de dados conjunto de características NCache como a única entrada na camada de acesso a dados da perspectiva do microsserviço; se um microsserviço requer dados, ele só precisa acessar o cache. O cache fornece os dados se estiverem disponíveis no cache, mas se não estiverem, ele prossegue e recupera os dados do armazenamento de dados usando um manipulador de leitura em nome do cliente, armazena-os em cache e os apresenta ao microsserviço.
Da mesma forma, ao utilizar um manipulador de gravação, um microsserviço só precisa executar uma operação de gravação (Adicionar, Atualizar, Excluir) no cache e o cache executa a operação de gravação relevante no armazenamento de dados automaticamente.
Além do mais, você pode até forçar o cache a recuperar dados diretamente do armazenamento de dados, independentemente de o cache conter uma versão possivelmente obsoleta. Isso é crítico quando o microsserviço requer informações atualizadas e se baseia nas estratégias de consistência de cache mencionadas anteriormente.
O recurso Provedor de Fonte de Dados de apoio não apenas agiliza o código do seu aplicativo, mas quando usado junto com os muitos NCache recursos de sincronização de banco de dados disponíveis, o cache é mantido com dados atualizados recarregados automaticamente, prontos para computação.
O trecho de código a seguir ajudará você a começar a usar o Read-Thru em seus microsserviços:
1 2 3 4 5 6 |
// Specify the readThruOptions for read through operations var readThruOptions = new ReadThruOptions(); readThruOptions.Mode = ReadMode.ReadThru; // Retrieve the data of the corresponding item with reads thru enabled Product data = cache.Get<Product>(key, readThruOptions); |
Da mesma forma, você pode implementar Write-Through usando:
1 2 3 4 5 6 |
// Enable write through for the cacheItem created var writeThruOptions = new WriteThruOptions(); writeThruOptions.Mode = WriteMode.WriteBehind; // Add item in the cache with write-behind cache.Insert(key, cacheItem, writeThruOptions); |
Para obter informações mais detalhadas sobre como usar esses provedores, consulte nossa documentação em Cache de leitura e Cache de gravação.
NCache Adicionar ao carrinho Provedores de fonte de dados em NCache
Cache Core EF
Núcleo do Entity Framework (EF) é um poderoso Mapeador Relacional de Objetos (O/RM) frequentemente usado em aplicativos .NET corporativos. E porque é tão popular, NCache oferece uma Provedor de cache EF Core que permite adicionar perfeitamente o cache no código relacionado ao EF Core usando métodos de extensão como FromCache. Isso permite que os desenvolvedores do EF Core não estejam intimamente familiarizados com NCache APIs para ainda aproveitar o poder de NCache.
O código a seguir demonstra a facilidade de uso do NCache Provedor de cache do EF Core para introduzir o cache em sua lógica de aplicativo de microsserviço existente.
1 2 3 4 5 6 7 8 9 |
var options = new CachingOptions { // To store the result as collection in cache StoreAs = StoreAs.Collection }; options.SetAbsoluteExpiration(DateTime.Now.AddMinutes(_settings.NCacheAbsoluteExpirationTime)); // Get items from cache. If not found, fetch from database and store in cache. item = await _catalogContext.CatalogItems.DeferredSingleOrDefault(ci => ci.Id == id).FromCacheAsync(options); |
Você pode encontrar mais informações sobre a API do EF Core Caching Provider e como ela pode ajudar seu caso de negócios em NCache Provedor EF Core.
NCache Adicionar ao carrinho EF Core Cache em NCache
Resumindo tudo
Os microsserviços são construídos com a intenção específica de serem autônomos; que você pode desenvolver, testar e implantá-los independentemente dos outros microsserviços. Isso serve para tornar todo o aplicativo altamente escalável, além de estar aberto a processos rápidos de Integração Contínua/Implantação Contínua (CI/CD).
No entanto, apesar de todas as vantagens que os microsserviços oferecem em termos de escalabilidade e rápidos ciclos de vida de desenvolvimento, existem certos aspectos de uma pilha de aplicativos que causam problemas. Entre esses aspectos estão os bancos de dados relacionais que não permitem o dimensionamento necessário para lidar com o aumento da carga e é aí que uma solução de cache distribuído como NCache brilha.
NCache tem vários recursos prontos para uso para ajudá-lo a tornar o cache de dados uma adição simples e intuitiva ao seu aplicativo de microsserviços. Isso inclui sincronização de banco de dados, expiração, cache do EF Core, consulta SQL e muito mais.
NCache Adicionar ao carrinho Baixar NCache Comparação de edições