No último artigo começamos a discutir sobre Cache, falamos sobre quais são os perigos e obstáculos de soluções de cache local em ambientes clusterizados. Também conversamos sobre o módulo Spring Cache, que oferecer abstrações para uso de caching na camada de aplicação em projetos Spring Boot.
Turbinando seus Microsserviços com Spring Cache e Redis
Jordi Henrique Silva ・ Feb 28 '23
Hoje iremos voltar a discutir sobre cache, porém, vamos nos concentrar em estratégias para manter o cache e a camada de dados sincronizadas.
Cache e sua importância
A verdade é que sistemas enterprise são automações que auxiliam no processo de escalada de um negócio. Isto significa que quanto mais o negócio crescer, quantos mais clientes o negócio atender, maior será o requisito de performance do sistema. O que quero dizer com isso é que otimizações precisaram ser feitas, e existem inúmeras técnicas que podem ser aplicadas, inclusive inserir uma camada de Caching.
A partir do momento que implementamos uma camada de cache, podemos usufruir de diversos benefícios, como diminuição do custo de consulta para O(1)
.E caso o banco de dados fique indisponível, o sistema continuará disponível para solicitações de leituras.
Uma camada de cache bem implementada deve se garantir que, leituras obsoletas não sejam permitidas. E que os dados estejam sincronizados com a fonte da verdade, no caso o banco de dados.
Os provedores de cache tem diversas formas para invalidação, entre elas as mais comuns são por tempo de duração em cache. E por limite de armazenamento, sendo possível definir uma capacidade máxima de objetos ou uma capacidade máxima em bytes.
Contudo, o que viemos discutir hoje são técnicas que você poderá aplicar para garantir que os dados presentes em cache não são obsoletos em relação à camada de dados.
Estratégias para sincronização de Cache
A primeira estratégia que vamos conhecer é conhecida como Cache a-side, nesta estratégia a camada de aplicação é responsável por gerenciar as camadas de dados e cache.
Cache a side
Nesta estratégia a camada de aplicação gerencia manualmente o cache e o banco de dados. Isto significa que quando um registro é buscado no banco, o mesmo é inserido no cache, o tornando disponível na próxima solicitação de leitura. O mesmo se aplica para quando um dado é atualizado.
Para entender melhor como, observe o diagrama abaixo, que demostra o comportamento da aplicação em uma consulta de dados.
O diagrama demostra que primeiro o dado é procurado em cache, como o mesmo obtêm na resposta que o dado não existe, é feito a consulta no banco de dados, em seguida o dado retornado do banco é inserido no cache.
Está é uma implementação simples, porém, misturar a lógica de negócio com lógica de acesso a cache, quebra o Princípio da Responsabilidade Única (SRP) do SOLID. Então a boa prática é que seja utilizado interceptors de programação orientada a aspectos AOP, para esconder a lógica de acesso à camada de cache, como, por exemplo, a API do Spring Cache.
Read Through
Nesta estratégia a camada de aplicação, irá se comunicar apenas com a API de Cache, e toda a lógica de gerenciamento de banco de dados será de total responsabilidade da camada de cache. As vantagens desta estratégia é que agora existe apenas um ponto de acesso a dados, então se torna mais simples a escrita e manutenção do código.
O diagrama apresentado acima, descreve o comportamento do caso de cache miss. Nesta situação o sistema, iniciará consultando se os dados existem em cache, caso não existam os dados são buscados no banco de dados, e inseridos em cache.
Write Behind
Esta estratégia é recomendada para situações onde NÃO é necessário ter uma forte consistência, pois as atualizações são feitas em lotes. Isto significa que as operações serão enfileiras, e executadas de uma só vez.
No diagrama a cima, é resumido o comportamento da estratégia de atualização de Caching para escrita. Nesta estratégia as operações de atualização são enfileiradas, até que o flush()
for executado, liberando todas as operações ao fim da transação.
O contexto de persistência da JPA, utiliza write-behind para garantir que todas as transições de estado das entidades sejam liberadas no fim da Transação em execução, ou antes, de uma consulta.
Conclusão
Implementar uma camada de caching em um projeto permite o sistema ganhe desempenho e disponibilidade, já que o custo de processamentos complexos são reduzidos, proporcionando uma maior capacidade de atender solicitações simultâneas.
Porém, antes de gozar das vantagens é necessário entender quais são as melhores práticas para manter a camada da cache sincronizada com o banco de dados. Existem diversas estratégias que podem ser utilizadas, desde fazer com que a aplicação gerêncie o cache e o banco de dados como é o caso de cache a side. Caso trabalhar com duas fontes de dados seja trabalhoso, outra solução é definir uma API de Caching que gerencie a camada de dados, implementando Read-Through. E caso não seja necessária uma consistência forte, a camada de caching poderá enfileira as solicitações e dispará-las de uma única vez, como é Write-Behind.
Lembrando que decisões como essas são complexas, e devem ser tomadas de acordo com contexto do time, projeto e tecnologias utilizadas.
Top comments (0)