Seu banco de dados foi atualizado, mas o cache não. Agora seus usuários veem dados antigos. Bem-vindo ao problema do Dual Write.
⏱️ Tempo: 4 minutos | 📊 Dificuldade: Médio
❓ O Que É Dual Write?
Dual Write = escrever em dois lugares ao mesmo tempo.
Exemplo: quando você atualiza um usuário no banco de dados, você também escreve no cache Redis. Parece lógico, certo? Errado.
Pseudocódigo (PERIGOSO):
usuario.nome = "João"
db.update(usuario) // Escreve no banco
cache.set(usuario) // Escreve no cache
❌ E se a linha 2 falhar? Cache tem dado novo, DB tem dado velho!
🐛 Por Que Dual Write É Ruim?
1️⃣ Inconsistência de Dados
Se uma das escritas falha, você fica com dados inconsistentes:
| Cenário | DB | Cache | Problema |
|---|---|---|---|
| Escreve DB ✓ | Novo | Velho | ❌ Cache erro |
| Escreve Cache ✓ | Velho | Novo | ❌ DB erro |
| Ambas falham | Velho | Velho | ✓ OK (mas erro) |
2️⃣ Race Conditions
Duas requisições simultâneas = ordem imprevisível:
Requisição A: Escreve saldo = 100
Requisição B: Escreve saldo = 50
Se A escreve no DB primeiro mas B escreve no cache primeiro:
DB = 50, Cache = 100 (inconsistente!)
3️⃣ Impossível de Corrigir
Não há "rollback" automático. Se o DB foi atualizado e o cache falhou, você nunca vai saber.
✅ A Solução Correta: Event Sourcing / Change Data Capture
Não escreva em dois lugares. Escreva em UM e deixe o resto sincronizar.
Abordagem 1: Event Sourcing
1. Escrever apenas no banco de dados
2. DB gera um "evento" (usuário.atualizado)
3. Sistema de filas (RabbitMQ, Kafka) consome o evento
4. Cache é atualizado de forma assíncrona
✓ Se cache falhar, fila retenta automaticamente
✓ Dados sempre consistentes no DB
✓ Cache é apenas um reflexo (pode ser deletado e recriado)
Pseudocódigo (CORRETO):
usuario.nome = "João"
// Escreve APENAS no DB
db.update(usuario) // ✓ Sucesso ou ❌ Erro
// DB gera evento automaticamente
evento = {tipo: "usuario.atualizado", id: 123}
kafka.publish(evento) // Coloca na fila
// BACKGROUND (consumer):
while (true) {
evento = kafka.consume()
usuario = db.get(evento.id)
cache.set(usuario) // Atualiza cache
}
🆚 Dual Write vs Forma Correta
| Aspecto | Dual Write ❌ | Event Sourcing ✓ |
|---|---|---|
| Consistência | Arriscada | Garantida |
| Rollback | Impossível | Automático (fila) |
| Auditoria | Manual | Integrada (eventos) |
| Escalabilidade | Frágil | Robusta |
⚡ A ÚNICA Exceção: Transação ACID
Se ambas as operações são no MESMO banco de dados (ex: tabela principal + tabela auditoria), você usa transação ACID. Isso não é "dual write", é uma transação única:
BEGIN TRANSACTION
UPDATE usuarios SET nome='João'
INSERT INTO auditoria (evento) VALUES ('atualizado')
COMMIT // Tudo ou nada
✓ Seguro porque é transação ACID no mesmo DB
✅ Checklist: É Dual Write Perigoso?
Escrevo em 2+ bancos de dados diferentes?
Escrevo em DB e Cache/Search/Queue?
Não há transação ACID envolvendo ambos?
A ordem das escritas pode variar?
Se marcou sim em qualquer um: Você está usando Dual Write perigoso. Use Event Sourcing.
🎯 Conclusão
Dual Write é a próxima bomba-relógio do seu código. Parece funcionar até o momento em que não funciona mais.
Regra simples:
✓ Escreva em UM lugar (banco de dados)
✓ Deixe eventos sincronizarem o resto
✓ Cache/Search/Queue são cópias (can be recreated)