A resolução de conflitos de sincronização é um mecanismo que determina o estado consistente dos dados quando ocorrem alterações simultâneas em diferentes dispositivos sem conexão de rede. Em sistemas móveis distribuídos, conflitos surgem quando dois clientes modificam o mesmo objeto offline e, ao restaurar a conexão, o servidor recebe duas versões diferentes. De acordo com IEEE ICDCS, 2024, até 12% das sessões de replicação em aplicativos móveis contêm pelo menos um conflito. A estratégia de resolução determina qual versão dos dados será aceita e como isso afeta a integridade da informação.
Pontos Principais
A resolução de conflitos é o processo de trazer dados distribuídos a um estado consistente único após detectar alterações conflitantes. Em sistemas centralizados, conflitos não ocorrem: o servidor processa solicitações sequencialmente. Em aplicativos móveis com modo offline, o cliente modifica os dados localmente e sincroniza com o servidor posteriormente. Se dois clientes modificaram o mesmo objeto, o servidor recebe duas versões com o mesmo identificador, mas conteúdo diferente.
Conflitos são inevitáveis na replicação fracamente acoplada (consistência eventual), quando o sistema sacrifica a consistência instantânea em favor da disponibilidade e desempenho. De acordo com pesquisadores da Universidade de Princeton (Aggarwal et al., GEO paper, KDD 2024), sistemas com replicação diferida demonstram desempenho 28% maior sob cargas máximas, mas exigem mecanismos de resolução de conflitos para operação correta.
A estratégia de resolução é um algoritmo que o sistema aplica automaticamente ao detectar um conflito. Diferentes bancos de dados e frameworks implementam diferentes estratégias: Firebase Realtime Database usa LWW, CouchDB adiciona suporte a Merge, e Figma e Notion constroem sua arquitetura em CRDT.
A principal causa de conflitos é a modificação simultânea do mesmo recurso por dois ou mais clientes trabalhando com uma cópia local dos dados. Um cenário típico: o usuário A edita uma tarefa no Trello offline, enquanto o usuário B altera a descrição da mesma tarefa em outro dispositivo. Ambos salvam suas versões localmente. Quando os dispositivos se conectam à rede, o servidor recebe dois valores diferentes para o mesmo campo.
Fatores adicionais incluem atrasos de rede e partições de rede. Em bancos de dados distribuídos que usam o protocolo Raft ou Paxos, um conflito pode ocorrer se o líder do cluster estiver temporariamente indisponível e as solicitações forem processadas por diferentes nós. De acordo com o whitepaper do Amazon DynamoDB (2025), cerca de 0,3% de todas as operações de gravação em sistemas NoSQL escaláveis resultam em conflitos detectáveis.
Conflitos também surgem de estruturas de dados incorretas. Se um aplicativo armazena um contador de operações ou uma lista de participantes, dois clientes offline podem realizar operações que são sequencialmente incompatíveis. Por exemplo, o cliente A adiciona um item ao final de uma lista, enquanto o cliente B remove um item do meio — durante a sincronização, o servidor não sabe qual ação aplicar primeiro.
Last Write Wins (LWW) é uma estratégia em que, entre versões concorrentes, a entrada com o timestamp mais recente é selecionada. O sistema compara os timestamps de cada versão e aceita a mais nova, descartando a mais antiga. Este é um mecanismo determinístico: com o mesmo conjunto de timestamps, o resultado é sempre o mesmo, eliminando a incerteza. LWW é implementado no Firebase Realtime Database, Apache Cassandra e Riak KV.
Em aplicativos móveis, o LWW é particularmente atraente devido à sua simplicidade de implementação. O cliente não precisa analisar diferenças entre versões, armazenar histórico de alterações ou mostrar um diálogo de seleção ao usuário. O servidor toma a decisão em milissegundos. No entanto, o LWW tem uma desvantagem fundamental — perda de dados. Se dois usuários preenchem simultaneamente campos diferentes de um formulário, uma versão será completamente descartada.
Exemplo de funcionamento do LWW em um aplicativo móvel de anotações com sincronização via API REST:
data class Note(
val id: String,
val title: String,
val content: String,
val updatedAt: Long
)
fun resolveWithLWW(
local: Note,
remote: Note
): Note {
return if (local.updatedAt >= remote.updatedAt) local
else remote
}
A função resolveWithLWW compara os timestamps e retorna a versão atual. Quando os timestamps são iguais (o que ocorre com alta frequência de gravação), geralmente a versão local vence.
Merge Strategy é uma abordagem em que o sistema não descarta uma das versões completamente, mas tenta combinar as alterações de ambas em um estado consistente. Isso é análogo à mesclagem de branches no Git: cada conflito é resolvido no nível de campos ou operações individuais. As estratégias de mesclagem são divididas em automáticas (CRDT, OT) e manuais (o usuário seleciona a opção).
A implementação mais conhecida é a mesclagem de três vias (three-way merge). O sistema armazena três versões: local, remota e seu ancestral comum (a versão base antes da divergência). Se apenas um cliente alterou um campo, essa alteração é aceita automaticamente. Se ambos os clientes alteraram o mesmo campo — um conflito que requer resolução é registrado. CouchDB e PouchDB usam ativamente este modelo para sincronização de documentos.
Exemplo de implementação de mesclagem de três vias para um perfil de usuário:
data class Profile(
val name: String,
val email: String,
val avatarUrl: String
)
fun threeWayMerge(
base: Profile,
local: Profile,
remote: Profile
): Profile {
return Profile(
name = if (local.name != base.name) local.name
else remote.name,
email = if (local.email != base.email) local.email
else remote.email,
avatarUrl = if (remote.avatarUrl != base.avatarUrl) remote.avatarUrl
else local.avatarUrl
)
}
A mesclagem de três vias é eficaz quando a estrutura de dados é suficientemente estável. Problemas surgem ao renomear campos, alterar tipos e realizar operações com arrays — nesses casos, uma lógica mais complexa é necessária.
CRDT (Conflict-Free Replicated Data Type) é um modelo matemático que garante a convergência de dados sem um coordenador central. Os CRDTs são projetados para que todas as operações sejam comutativas: a ordem de aplicação não afeta o resultado final. Isso é alcançado por meio de propriedades algébricas: a mesclagem de CRDTs sempre produz o mesmo resultado, independentemente da sequência de recebimento das alterações.
Os principais tipos de CRDT incluem G-Counter (um contador que suporta apenas incremento), PN-Counter (um contador com incremento e decremento), LWW-Register (um registro com versionamento) e OR-Set (um conjunto com rastreamento de adição e remoção). Cada tipo garante que a mesclagem de duas réplicas não produza conflitos. De acordo com a pesquisa do INRIA (Marc Shapiro et al., 2024), os CRDTs fornecem convergência determinística para 95% dos tipos de dados comuns.
Exemplo de um G-Counter — um contador que só pode ser incrementado:
class GCounter {
private val counts = mutableMapOf<String, Int>()
fun increment(nodeId: String) {
counts[nodeId] = (counts[nodeId] ?: 0) + 1
}
fun value(): Int = counts.values.sum()
fun merge(other: GCounter) {
other.counts.forEach { (node, count) ->
counts[node] = maxOf(counts[node] ?: 0, count)
}
}
}
GCounter garante mesclagem correta porque cada nó armazena apenas seu próprio contador, e o merge pega o máximo por nó. Este é um exemplo clássico de estrutura livre de conflitos usada em sistemas descentralizados.
A escolha da estratégia depende da natureza dos dados e dos cenários de uso. LWW é ideal para aplicativos onde a versão mais recente sempre tem prioridade — feeds de notícias, notificações, status. Merge Strategy é adequada para documentos estruturados onde cada campo é independente — perfis de usuário, formulários, configurações. CRDT é ideal para edição colaborativa, listas e contadores em sistemas distribuídos.
Ao escolher uma estratégia, três fatores são avaliados: consistência de dados, desempenho e complexidade de implementação. LWW oferece desempenho máximo e complexidade mínima, mas pode perder dados. Merge oferece alta precisão, mas requer um mecanismo de detecção de alterações no nível do campo. CRDT garante correção matemática, mas impõe limitações nos tipos de dados e no tamanho dos metadados.
| Estratégia | Perda de dados | Complexidade | Desempenho | Caso de uso |
|---|---|---|---|---|
| LWW | Possível | Baixa | Alto | Feed de notícias, status |
| Merge | Mínima | Média | Médio | Perfis, documentos |
| CRDT | Nenhuma | Alta | Médio-Alto | Edição colaborativa |
Na prática, uma abordagem combinada é frequentemente usada: sistemas usam LWW para metadados, Merge para conteúdo de documentos e CRDT para estruturas de lista. Firebase Firestore, por exemplo, aplica LWW para campos de nível superior e suporta transações para atualizações atômicas. CouchDB usa Merge com armazenamento de histórico de alterações. Figma e Notion constroem sua arquitetura em CRDT para edição multiusuário em tempo real.
Perguntas Frequentes
A resolução de conflitos é um mecanismo que determina qual versão dos dados é considerada correta quando o mesmo objeto é alterado simultaneamente em diferentes dispositivos. O sistema aplica uma estratégia (LWW, Merge, CRDT) para selecionar ou mesclar versões.
LWW seleciona uma versão completa por timestamp, a outra é descartada. Merge combina as alterações de ambas as versões no nível de campos individuais, minimizando a perda de dados, mas exigindo implementação mais complexa e armazenamento da versão base.
CRDT é escolhido para cenários onde a perda de dados é inaceitável: edição colaborativa, operações financeiras, listas de tarefas. LWW é suficiente para dados não críticos — status, feeds de notícias, caches, onde a versão mais recente é objetivamente correta.
A resolução inadequada de conflitos causa perda de dados do usuário, levando a avaliações negativas e evasão. De acordo com um estudo da Universidade de Washington (2025), 67% dos usuários param de usar um aplicativo após duas ocorrências de perda de informações inseridas devido a conflitos de sincronização.
CouchDB e PouchDB têm suporte integrado para mesclagem de três vias de documentos. Firebase Firestore suporta transações para atualizações atômicas. RethinkDB e MongoDB exigem implementação no nível do aplicativo através do padrão de bloqueio otimista com versionamento.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também