Hoje eu gostaria de aprofundar em uma das principais estratégias utilizadas em bancos de dados distribuídos: replicação.
Replicar significa manter cópias dos mesmos dados em diferentes nós, então vamos entender como essas cópias são mantidas, por que a replicação aumenta a disponibilidade e a capacidade de leitura, e quais problemas surgem quando os nós não estão perfeitamente sincronizados.
O que é replicação?
Replicação é o processo de manter cópias dos mesmos dados em diferentes nós de um sistema de banco de dados.
Imagine que temos um banco principal:
Podemos adicionar réplicas:
O principal recebe alterações e as réplicas recebem essas alterações para manter uma cópia dos dados.
O objetivo da replicação não é simplesmente "ter backups". Ela pode ser utilizada para aumentar disponibilidade, capacidade de leitura e tolerância à falhas, tentando remover o SPOF (Single Point of Failure).
Primary e Replica
Uma arquitetura bastante comum utiliza o modelo Primary/Replica, também conhecido como Leader/Follower em algum sistemas.
O Primary é responsável por receber operações de escrita, como:
INSERT
UPDATE
DELETE
As réplicas recebem essas alterações e mantêm cópias dos dados.
Um fluxo simplificado seria:
A aplicação pode então utilizar o Primary para operações que alteram dados e as Replicas para determiandas operações de leitura.
Isso permite separar parte da carga.
Read Replicas
Quando uma réplica é utilizada principalmente para atender operações de leitura, podemos chamá-la de Read Replica.
Imagine uma aplicação que possui:
Se todas essas operações forem direcionadas ao mesmo banco, as leituras podem consumir uma parcela significativa dos recursos disponíveis.
Podemos distribuir parte das leituras:
Agora o Primary continua concentrando as escirtas, enquanto as réplicas podem absorver parte das leituras.
Isso pode aumentar a capacidade de leitura sem necessariamente aumentar a capacidade do Primary na mesma proporção.
Replicação não é Sharding
Essa distinção precisa ficar muito clara porque são conceitos que aparecem juntos mas na replicação, temos cópias dos mesmos dados, como já foi mencionado:
Primary:
A B C D
Replica:
A B C D
No particionamento, os dados são divididos:
Node 1:
A B
Node 2:
C D
Portanto:
- Replicação => duplicamos dados.
- Particionamento => dividimos dados.
A replicação pode aumentar a disponibilidade e capacidade de leitura. O particionamento será utilizado principalmente para distribuir armazenamento e carga entre diferentes nós.
Podemos inclusive combinar ambos:
Mas vamos deixar essa combinação para quando estudarmos sobre Sharding.
Quando a replicação acontece?
Quando uma alteração é realizada no Primary, precisamos propagá-la para as réplicas.
Imagine:
UPDATE Account
SET balance = 800
Primary registra essa alteração.
Depois, a informação precisa chegar às réplicas:
A maneira como o sistema espera ou não pela confirmação das réplicas define uma diferença muito importante entre replicação síncrona e assíncrona.
Replicação síncrona
Na replicação síncrona, o sistema espera que uma ou mais réplicas confirmem a operação antes de considerar a escrita concluída.
Um fluxo simplificado:
Imagine que o usuário altere seu saldo. O Primary recebe a alteração e precisa garantir que a réplica também tenha recebido a informação antes de confirmar a operação.
A principal vantagem é que temos uma garantia de que os dados já estão presentes em múltiplos nós quando a operação é confirmada.
Porém, isso possui um custo.
O custo da replicação síncrona
Para confirmar uma operação, precisamos esperar pela comunicação entre os nós.
Se os nós estiverem distantes ou uma réplica estiver lenta, a operação pode demorar demais.
Primary Database => Replica => 100ms
A aplicação pode precisar aguardar essa comunicação antes de receber a confirmação e isso aumenta a latência da escrita.
Além disso, se uma réplica necessária para a confirmação estiver indisponível, podemos ter dificuldades para completar novas escritas, dependendo da configuração do sistema.
Portanto, temos um tradeoff: Replica síncrona => maior garantia de consistência entre as réplicas, mas potencialmente maior latência e menor tolerância à indisponibilidade de réplicas necessárias.
Replicação assíncrona
Na replicação assíncrona, o Primary pode confirmar a escrita antes de todos as réplicas receberem a alteração.
O fluxo pode ser:
Isso reduz a latência de escrita porque o Primary não precisa esperar todas as réplicas.
Porém, agora existe uma possibilidade importante: durante algum intervalo, as réplicas podem possuir dados antigos.
Imagine:
Primary:
balance = 800
Replica:
balance = 500
O Primary já processou a alteração, mas a Replica ainda não recebeu a atualização.
Esse intervalo é conhecido como Replication Lag (importante lembrar).
Replication Lag
Replication Lag é o atraso entre o estado do Primary e o estado de uma Replica.
Imagine:
T0:
Primary = 500
Replica = 500
T1:
Primary = 800
Replica = 500
T2:
Primary = 800
Replica = 800
Entre T1 e T2, existe uma diferença entre os nós.
Essa diferença pode durar milissegundos, segundos ou até mais tempo dependendo do sistema, da carga e das condições da infraestrutura.
Esse conceito é extremamente importante porque pode produzir comportamento inesperados na aplicação.
O problema da leitura após escrita
Imagine o seguindo fluxo:
A aplicação acabou de informar ao usuário que a alteração foi concluída, mas imediatamente depois ele consulta os dados e recebe a versão antiga.
Isso pode acontecer devido ao Replication Lag.
Esse é uim exemplo bem simples de consistência eventual em uma arquitetura de replicação assíncrona em banco de dados
Uma solução possível é direcionar determinadas leituras para o Primary após uma escrita
Por exemplo:
Write => Primary Database
Read imediatamente após => Primary Database
Outras leituras => Replicas (até todas as replicas receberam a atualização necessária)
Mas isso precisa ser avaliado de acordo com o requisitos do sistema.
Quando usar replicação síncrona e assíncrona?
A decisão depende principalmente do quanto o sistema precisa garantir que uma alteração esteja replicada antes de confirmar a operação.
Replicação síncrona pode fazer sentido quando a perda de uma alteração confirmada é extremamente problemática e precisamos de maior garantia de persistência em múltiplos nós.
Replicação assíncrona pode fazer sentido quando precisamos de maior desempenho de escrita e podemos aceitar que as réplicas fiquem temporariamente atrasadas.
Não existe uma opção universalmente melhor, existe uma escolha baseada em requisitos.
Failover
Agora imagine que o Primary fique indisponível.
Se possuimos réplicas, podemos promover uma delas para assumir a função de Primary.
Isso é chamado de Failover
Por exemplo:
Antes:
Primary Database
Replica 1
Replica 2
Depois:
Primary Database (off)
Replica 1 => novo Primary
Replica 2 => continua sendo réplica
O objetivo é permitir que o sistema continue funcionando mesmo após a falha do nó principal.
Isso aumenta a disponibilidade do banco.
Failover automático
O failover pode ser realizado manualmente ou automaticamente, dependendo da infraestrutura utilizada.
Em um failover automático, algum mecanismo monitora os nós e detecta que o Primary não está mais disponível:
Durante esse processo pode existir um período de indisponibilidade ou degradação.
Por isso, dizer que "replicação elimina downtime" seria incorreto. Ela reduz o impacto de determinadas falhas, mas o failover possui tempo e complexidade próprias.
O problema da perda de dados no Failover
Aqui temos um ponto importante relacionado à replicação assíncrona.
Imagine:
Primary Database:
A B C D
Replica:
A B C
O Primary recebeu a operação D, mas a Replica ainda não recebeu.
Agora o Primary falha.
Se promovermos a Replica:
Novo Primary terá:
A B C
A operação D pode ter sido perdida.
Esse é um dos principais tradeoffs da replicação assíncrona juntamente com o mecanismo de failover.
Quanto maior o Replication Lag no momento da falha, maior pode ser a quantidade de dados que ainda não foram propagados para uma réplica promovida à primary.
Replicação e disponibilidade
A principal ideia que devemos guardar é que replicação permite que o sistema tenha mais de um nó contendo os dados necessários para continuar funcionando.
Sem réplica:
Com réplica + failover:
Isso reduz a dependência de um único nó e também de um ponto único de falha.
Mas novamente, replicação não significa que o sistema automaticamente possui alta disponibilidade. Precisamos considerar o mecanismo de failover, detecção de falhas, promoção de réplicas, roteamento da aplicação e possíveis perdas ou atrasos de dados (replication lag).
Replicação e escalabilidade de leitura
Além de disponibilidade, replicação pode aumentar a capacidade de leitura
As escritas continuam concetradas no Primary, enquanto as leituras podem ser distribuídas entre as réplicas.
Isso permite aumentar a capacidade de leitura adicionando novas réplicas.
Porém, isso não resolve necessariamente o problema de escritas em excesso. Se o Primary estiver sobrecarregado por milhares de operações de escrita, adicionar Read Replicas não resolverá esse gargalo.
Essa distinção será importante para quando estudarmos particionamento e Sharding.
O tradeoff central da replicação
Podemos assumir a replicação desta maneira:
| Benefícios | Custos |
|---|---|
| Disponibilidade | Replication Lag |
| Escala de leitura | Complexidade |
| Failover | Consistência |
| Redundância | Sincronização |
Quanto mais réplicas temos, maior pode ser nossa capacidade de leitura e redundância, mas também aumentam os custos de infraestrutura e a complexidade de manter o sistema funcionando corretamente de acordo com a consistência e perca de dados nos casos de falha.
O que seria legal de guardar desse artigo
Replicação consiste em manter cópias dos mesmo dados em diferentes nós. Um modelo comum é o Primary/Replica ou também chamado de Leader/Follower, no qual o Primary recebe as escritas e as réplicas mantêm cópias desses dados. As réplicas podem ser utilizadas para aumentar a capacidade de leitura e também pode assumir o papel de Primary em caso de falhas através de um mecanismo de failover.
Na replicação síncrona, a escrita depende da confirmação de uma ou mais réplicas, oferecendo maior garantia de sincronização, mas potencialmente aumentando a latência.
Na replicação assíncrona, o Primary pode confirmar a escrita antes que as réplicas sejam atualizadas, proporcionando menor latência, mas permitindo Replication Lag e períodos de inconsistência entre os nós.
Portanto, replicação melhora disponibilidade e pode escalar leituras, mas introduz tradeoffs relacionados a consistência, latência, failover e complexidade.















Top comments (0)