3 Estratégias para sincronizar cache na camada de aplicação
Tags: backend, caching, java, distributedsystems
Published: 2023-05-09 02:26:07

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.

{% embed https://dev.to/jordihofc/turbinando-seus-microsservicos-com-spring-cache-e-redis-4p1f %}

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.


![Diagrama de fluxo, sobre comportamento da estratégia cache-a-side](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaidsqxbcwklubb3u46m.png)


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](https://www.zup.com.br/blog/design-principle-solid). Então a boa prática é que seja utilizado interceptors de programação orientada a aspectos [AOP](https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html), 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.

![Diagrama de fluxo, sobre comportamento da estratégia read-through](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdsmdh3endmw2z8n7xgj.png)

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.


![Diagrama de fluxo, sobre comportamento da estratégia write-behind](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ms3mswg03msxke9n22n4.png)

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](#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](#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](#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.