NoSQL Databases: Architecture, Data Models, and Practical Use
Understand why NoSQL databases emerged and how their architectures differ from relational systems. This tutorial explores document, key-value, wide-column, and graph databases; data modeling; partitioning; sharding; replication; consistency; CAP; transactions; caching; CQRS; microservices; and polyglot persistence. It concludes with practical architecture decisions for ownership, data flow, scaling, performance, and failure scenarios.
Lesson 3: The Distributed Systems Foundations of NoSQL
Many of the most important NoSQL concepts are actually distributed-systems concepts. Before going deeper into individual databases, this lesson builds an understanding of nodes, replication, partitioning, fault tolerance, availability, and network failures. These concepts explain why distributed databases behave differently from a database running on a single machine and why architectural trade-offs become unavoidable at scale.
Why Distributed Databases Exist
A distributed database stores and processes data across multiple machines, called nodes, instead of depending on a single database server. This approach becomes important when an application needs more capacity, higher availability, or geographic distribution than one machine can reasonably provide.
For example, imagine an online learning platform with millions of students. One database server may eventually become a bottleneck because it has limits on CPU, memory, storage, and network throughput. A distributed database can use several machines so that the workload and data are spread across the cluster.
Technologies such as MongoDB, Cassandra, DynamoDB, and Couchbase are designed with distributed operation as an important part of their architecture. Relational databases can also participate in distributed architectures, but many NoSQL systems were designed around these requirements from the beginning.
Nodes and Clusters
A node is an individual machine or database instance participating in a distributed database. Multiple nodes form a cluster, and the database software coordinates these nodes to provide storage and access to data.
Consider a MongoDB deployment with three nodes. Instead of thinking of the system as three independent databases, the application normally interacts with the cluster as a logical database. The database infrastructure determines which node should process a request and how data should be replicated.
This abstraction is useful for application developers, but architects need to understand what happens underneath. Requests travel over a network, nodes can fail, data may exist in multiple locations, and communication between nodes is not guaranteed to be instantaneous or reliable.
Replication
Replication means keeping multiple copies of data on different nodes. Its main purposes are improved availability and fault tolerance, and sometimes improved read performance.
For example, suppose a customer record exists on three database nodes:
Node A: Customer 101
Node B: Customer 101
Node C: Customer 101
If Node A fails, another node can potentially continue serving the data. The system therefore does not depend on a single physical machine.
MongoDB uses replica sets, while Cassandra uses a different replication architecture in which data is distributed and replicated across nodes. DynamoDB also automatically maintains replicated infrastructure across availability zones.
Replication introduces an important problem: keeping copies synchronized. If one node receives an update, the other nodes need to learn about it. This can introduce replication delay and creates important consistency decisions.
Partitioning and Sharding
Replication creates multiple copies of the same data, but it does not solve the problem of storing more data than one machine can handle. Partitioning divides data into separate pieces so that different nodes store different portions of the dataset.
For example, suppose an application has 100 million customers. Instead of storing every customer on one machine, the database might distribute customers across several nodes:
Node A -> Customers 1-25M
Node B -> Customers 25M-50M
Node C -> Customers 50M-75M
Node D -> Customers 75M-100M
This is commonly called sharding in database systems. The database needs a mechanism, usually a partition or shard key, to determine where a particular piece of data belongs.
A poor partition key can create a hot partition, where a disproportionate amount of traffic reaches one node. Therefore, choosing partition keys becomes an important architectural responsibility when working with distributed NoSQL systems.
Combining Partitioning and Replication
Large distributed databases commonly use both partitioning and replication. Partitioning determines which nodes own the data, while replication determines how many copies of that data exist.
For example:
Partition 1 -> Node A, Node B
Partition 2 -> Node B, Node C
Partition 3 -> Node C, Node D
The application might have hundreds of millions of records distributed across many partitions, while each partition has multiple replicas.
This architecture provides both scalability and resilience. However, it also increases system complexity because the database must coordinate distributed operations and maintain replicas while nodes are joining, leaving, or failing.
Fault Tolerance
A distributed system is designed with the assumption that failures will happen. A node can crash, a disk can fail, a server can lose network connectivity, or an entire availability zone can become unavailable.
Fault tolerance means that the system can continue operating despite some of these failures. Replication is one of the main mechanisms used to achieve this.
Imagine an e-commerce application where one database node suddenly stops responding. If the data exists only on that node, the application may become unavailable. If the data has replicas on other nodes, the system may continue operating.
However, fault tolerance is not free. More replicas require more storage, network traffic, and coordination. An architect therefore has to balance resilience against cost and complexity.
Availability
Availability describes the ability of a system to continue responding to requests when failures occur. A highly available database is designed so that individual failures do not necessarily make the entire system unavailable.
For example, suppose a database cluster has three replicas and one node fails. The remaining nodes may continue serving requests. This is significantly more resilient than having one database server with no redundancy.
However, availability is not simply a property of the database product. Application architecture also matters. If the application depends on a single database endpoint, network connection, or service instance, another component can still become a single point of failure.
Network Partitions
One of the most important concepts in distributed systems is the network partition. A network partition occurs when nodes are running but cannot communicate correctly with one another.
For example:
Node A ───── Node B
X
Node C
Node A and Node B can communicate, but the connection to Node C has failed. Node C may still be operational and may even receive requests from some clients.
This creates a difficult question: what should happen if Node A receives an update while Node C cannot communicate with it? Should Node A continue accepting requests? Should it reject requests to protect consistency? What happens when communication is restored?
These questions lead directly to the CAP theorem.
CAP Theorem
The CAP theorem states that a distributed system cannot guarantee both Consistency and Availability during a network Partition.
Consistency means that the system provides a defined view of the data so that clients do not observe conflicting states according to the system's consistency guarantee. Availability means that requests continue receiving responses. Partition tolerance means that the system continues operating despite communication failures between nodes.
The important point is that network partitions are unavoidable in distributed systems. Therefore, during a partition, an architecture must make trade-offs between consistency and availability.
A system that prioritizes consistency may reject requests when it cannot guarantee that the data is correct. A system that prioritizes availability may continue accepting requests and deal with synchronization or conflicts later.
A Concrete Example
Imagine a global ticket-booking system with database nodes in Toronto and London. A network failure temporarily separates the two locations.
A customer in Toronto attempts to purchase the last available seat while another customer in London does the same. If both locations continue accepting the transaction independently, the system could potentially sell the same seat twice.
The system could instead prioritize consistency and temporarily reject one or both operations until the nodes can communicate. This reduces availability but protects the correctness of the data.
For something less critical, such as a social-media like counter, temporary differences may be acceptable. The system can continue accepting likes and reconcile the data later. This prioritizes availability and can provide better user experience during failures.
Why Distributed Databases Force Trade-Offs
The central architectural lesson is that distribution creates trade-offs. Adding more machines gives us scalability and fault tolerance, but it also introduces network communication, replication delays, partitions, coordination, and more complicated failure scenarios.
A single-server database can often perform an operation locally and immediately. A distributed database may need to communicate with several machines before it can safely complete the same operation. Network communication is slower and less reliable than communication inside one machine.
This is why an architect should never evaluate a distributed NoSQL database only by asking, "How many requests per second can it handle?" The more important questions are: What happens when a node fails? What happens during a network partition? How is data partitioned? How many replicas exist? What consistency guarantee does the application need?
Architectural Perspective
NoSQL databases became strongly associated with distributed architectures because many modern applications need to operate across multiple machines and sometimes multiple regions. Their architectures commonly combine partitioning, replication, fault tolerance, and configurable consistency to achieve large-scale operation.
The key lesson is that scalability and availability come with complexity. As a technical lead or architect, you need to understand not only the normal path when everything works, but also what happens when nodes fail, replicas become inconsistent, or the network separates parts of the system.
The key idea is that a distributed database is not simply a larger database. It is a distributed system, and therefore its architecture must explicitly deal with partitioning, replication, failures, network communication, consistency, and availability.