Marcio Cunha

Data Synchronization in Distributed Databases with CRDT-Based Conflict Resolution

Learn how CRDTs solve synchronization conflicts in distributed systems without locks or central coordination, enabling offline operation and automatic data convergence.

Marcio Cunha•5 min
Also available in:PortuguêsEspañol
Summary
  • CRDTs allow multiple servers to update data simultaneously without locking the system or requiring queries to a central coordinator
  • Mathematical convergence ensures that all database copies reach the exact same state after receiving all changes
  • State-based models send the entire document on each sync, whereas operation-based models transmit only the executed actions
  • Conflicts from simultaneous deletions and edits no longer require manual intervention when semantic-oriented structures are adopted
  • Offline systems benefit enormously from this approach because they automatically reconcile data the moment connectivity is restored

The Fundamental Challenge of Consistency in Distributed Networks

Imagine you and a colleague edit the same spreadsheet on separate computers while completely offline. When both reconnect, the changes must merge without erasing anyone's work. In software engineering, synchronizing databases scattered across the globe runs into unyielding physical laws: messages take time to travel across networks, and connection drops happen constantly. Traditionally, systems tried to solve this by locking records so only one person could edit at a time. In practice, this creates severe bottlenecks, slows down applications, and prevents mobile devices from operating independently when disconnected.

To bypass this obstacle, modern architects adopt eventual consistency, a strategy where data does not need to look identical at the exact same millisecond, as long as it converges to the same value eventually. However, deciding which modification should prevail when two people alter the same record simultaneously remains a thorny problem. This is precisely where CRDTs, or Conflict-Free Replicated Data Types, come in. Simply put, they are clever mathematical structures built to accept changes anywhere, at any time, ensuring all copies align themselves autonomously in the end without losing valid data.

How State-Based and Operation-Based CRDTs Work

There are two major families of CRDTs, and understanding the difference helps design more efficient systems. The first is state-based, often called CvRDT. In practice, this means each server sends its entire document or a substantial portion of it to the others whenever a sync occurs. When the neighbor receives the packet, it applies a mathematical join operation, merging the data so that the arrival order of messages does not alter the final result. It is like combining two buckets of water: it does not matter which bucket was poured first, the final volume and mixture in the main container will always be the same.

The second family is operation-based, known as CmRDT. In this model, the system does not transmit the entire database, but rather the exact command that was executed, such as adding item X or incrementing a counter by one. For this to work without chaos, the infrastructure must guarantee that all messages reach all nodes, even if out of order, or that operations follow commutative rules where the order of factors does not change the product. While state-based models consume more bandwidth by sending larger packets, operation-based models demand stricter network guarantees to prevent dropping crucial commands along the way.

Practical Structures for Counters, Sets, and Maps

In everyday engineering, building applications requires concrete tools. CRDTs offer foundational structures that solve very specific data modeling problems. A classic example is the PN-Counter, ideal for managing likes on social networks or page views. It combines two internal counters: one that only sums increments and another that accumulates decrements. Because each node in the network records its own actions in isolation, simply summing all partial scores during synchronization yields the exact total without the risk of overwriting peer work.

Another indispensable component is the OR-Set, or Observed-Removed Set. In user directories or task lists, removing an item can cause conflicts if someone else edited it at the exact same moment. The OR-Set solves this by attaching unique, invisible identifiers to each inclusion. When an element is deleted, the system simply marks that specific identifier as obsolete. If a new item with the same name is created later, it carries a brand-new identifier, preventing the deletion mechanism from accidentally wiping out a new addition made by another user at a distant edge of the network.

Implementing a Distributed Counter in Code

To visualize the logic behind these structures, we can examine a simplified Python implementation of a partition-tolerant counter. The code below demonstrates how each node maintains its own dictionary of local increments and performs a merge with the state of other nodes.

class PNCounter:    def __init__(self, node_id, total_nodes):        self.node_id = node_id        self.increments = {str(i): 0 for i in range(total_nodes)}        self.decrements = {str(i): 0 for i in range(total_nodes)}    def increment(self, value=1):        self.increments[str(self.node_id)] += value    def decrement(self, value=1):        self.decrements[str(self.node_id)] += value    def merge(self, remote_counter):        for k in self.increments:            self.increments[k] = max(self.increments[k], remote_counter.increments[k])            self.decrements[k] = max(self.decrements[k], remote_counter.decrements[k])    @property    def value(self):        total_inc = sum(self.increments.values())        total_dec = sum(self.decrements.values())        return total_inc - total_dec

In this practical example, each machine has a unique numeric identifier. When the merge method runs, it compares the local and remote dictionaries, taking the highest value recorded by each node, ensuring that no past update is discarded during the data reconciliation process.

Trade-offs and Operational Care in Architecture

Despite eliminating the need for complex locks, CRDTs are not a magic bullet applicable to every engineering scenario. The main cost associated with this technology is memory and disk space consumption. Since the system must track detailed metadata to resolve conflicts deterministically, the volume of stored data tends to grow over time. In mobile applications with severe battery and storage constraints, accumulating operation history may require compaction strategies or controlled purging of old data that has already reached total convergence across nodes.

Another critical point concerns the complexity of business modeling. Not every domain logic fits naturally into commutative and associative mathematical structures. Strict financial operations, which require real-time balances with complex validations and immediate checks against overdraft limits, still rely on traditional relational databases and pessimistic concurrency control. CRDTs shine brightly in collaborative scenarios, real-time document editing, shopping carts, and decentralized systems where edge autonomy outweighs the need for strict linear consistency. To complement this implementation in production environments, see our related technical analyses on Resilience Strategies in Distributed Databases with CRDT-Based Conflict Resolution and Distributed Transaction Processing in Multi-Master Databases with CRDT-Based Conflict Resolution.

Final Considerations on the Future of Synchronization

The evolution of distributed systems goes hand in hand with the need for increasingly resilient applications capable of functioning seamlessly even when network infrastructure fails. CRDTs have radically transformed how we view data synchronization, proving that reliable convergence is possible without resorting to costly and slow centralized coordination. By understanding the trade-offs between metadata overhead and operational flexibility, engineers can design modern architectures that are truly fault-tolerant. The future points toward an even greater adoption of these structures in everyday tools, cementing distributed computing as an accessible and robust standard.