Chapter 11: NoSQL Database Taxonomy
Document, KV, Column-family, Graph — When to Use Each
11.1 Why NoSQL Exists
The Relational Database Wall
By the mid-2000s, web-scale companies hit fundamental limits with traditional RDBMS:
| Limitation | Symptom at Scale | Root Cause |
|---|---|---|
| Rigid Schema | ALTER TABLE locks on billions of rows; schema migrations take weeks | ACID guarantees require fixed structure; changes must be atomic |
| Join Performance | Multi-way joins across sharded tables require cross-network operations | Normalization assumes co-located data; sharding breaks this assumption |
| Write Scalability | Single-master bottleneck; vertical scaling only (add RAM/CPU) | Strong consistency requires coordination; 2PC/Paxos slow down writes |
| Impedance Mismatch | Object-Relational Mapping (ORM) complexity; N+1 query problems | Application objects don't map cleanly to normalized tables |
| Cost | Enterprise licenses scale with CPU cores; hardware gets expensive | Commercial databases charge per-core; commodity hardware not optimized |
The CAP Theorem Trade-off
All nodes see same data] A[Availability
System always responds] P[Partition Tolerance
Works during network splits] CAP --> C CAP --> A CAP --> P C -.->|CP Systems| CP[Traditional RDBMS
MongoDB strong
HBase
Redis Cluster] A -.->|AP Systems| AP[Cassandra
DynamoDB
Riak
CouchDB] P -.->|CA Impossible| CA[Network partitions
always happen in
distributed systems] style CA fill:#f66,stroke:#f00
Reality: Network partitions are inevitable in distributed systems (fiber cuts, switch failures, datacenter splits). So the real choice is CP vs AP.
| Choice | Behavior During Partition | Example Systems | Use When |
|---|---|---|---|
| CP (Consistency + Partition Tolerance) | Minority partition nodes return errors or block reads/writes until partition heals | MongoDB (strong consistency), HBase, etcd, Redis Cluster | Financial transactions, inventory, strong correctness requirements |
| AP (Availability + Partition Tolerance) | All nodes accept reads/writes; conflicts resolved later (last-write-wins, vector clocks, CRDTs) | Cassandra, DynamoDB, Riak, CouchDB | Shopping carts, social feeds, analytics, high uptime > perfect consistency |
Polyglot Persistence
Modern architectures use multiple database types within the same application, each optimized for specific access patterns:
Key-Value] App -->|Product Catalog| Mongo[MongoDB
Document] App -->|Order History| Postgres[PostgreSQL
Relational] App -->|Activity Feed| Cassandra[Cassandra
Column-Family] App -->|Recommendations| Neo4j[Neo4j
Graph] App -->|Search| ES[Elasticsearch
Document + Inverted Index] style Redis fill:#e74c3c style Mongo fill:#47a248 style Postgres fill:#336791 style Cassandra fill:#1287b1 style Neo4j fill:#008cc1 style ES fill:#005571
11.2 Key-Value Stores
Conceptual Model
The simplest NoSQL data model: a distributed hash map. Every item has a unique key, and the value is an opaque blob (or typed data structure in advanced stores).
Value: {name: 'Alice', age: 30}"] KV2["Key: session:abc123
Value: {userId: 1001, expires: 1620000000}"] KV3["Key: counter:page_views
Value: 452891"] end Client[Client] -->|GET user:1001| KV1 Client -->|SET session:abc123| KV2 Client -->|INCR counter:page_views| KV3
| Characteristic | Implication |
|---|---|
| No Schema | Values can be anything (JSON, binary, string); no validation at storage layer |
| No Joins | Related data accessed via multiple GET operations; application-side joins |
| No Secondary Indexes | Can only query by primary key; filtering requires scanning all keys or external indexing |
| Horizontal Scaling | Partition by key hash; consistent hashing enables adding/removing nodes |
| Performance | O(1) reads/writes; microsecond latency for in-memory stores |
Redis
The Swiss Army Knife of KV stores. Single-threaded (no lock contention), in-memory with optional persistence, rich data structures beyond simple key-value.
Architecture
epoll/kqueue] Commands[Command Processor] DataStructures[Data Structures
Strings, Hashes, Lists,
Sets, Sorted Sets, Streams] Persistence[Persistence Layer] end subgraph "Persistence Options" RDB[RDB Snapshots
Fork + Copy-on-Write
Periodic full dump] AOF[AOF Log
Append-only file
fsync every write/second/never] end subgraph "Scaling" Sentinel[Redis Sentinel
Auto-failover + Monitoring] Cluster[Redis Cluster
16384 hash slots
Automatic sharding] end Client[Client] --> EventLoop EventLoop --> Commands Commands --> DataStructures DataStructures --> Persistence Persistence --> RDB Persistence --> AOF DataStructures -.-> Sentinel DataStructures -.-> Cluster
| Feature | Description | Use Case |
|---|---|---|
| Strings | Binary-safe strings up to 512MB; GET/SET/INCR/DECR | Caching, counters, rate limiting |
| Hashes | Field-value maps; HGET/HSET/HGETALL | User profiles (key=user:1001, fields=name/email/age) |
| Lists | Linked lists; LPUSH/RPUSH/LPOP/RPOP/LRANGE | Job queues, activity logs, real-time feeds |
| Sets | Unique unordered strings; SADD/SREM/SINTER/SUNION | Tags, unique visitors, online users |
| Sorted Sets | Sets with score; ZADD/ZRANGE/ZRANGEBYSCORE | Leaderboards, priority queues, time-series indexes |
| Streams | Append-only log with consumer groups (like Kafka Lite) | Event sourcing, messaging, activity tracking |
| Bitmaps | Bit-level operations on strings; SETBIT/GETBIT/BITCOUNT | Feature flags, user activity tracking (daily logins) |
| HyperLogLog | Probabilistic cardinality estimation (0.81% error) | Unique visitor counts with O(1) space |
Persistence Strategies
| Method | Mechanism | Durability | Performance Impact | Recovery |
|---|---|---|---|---|
| RDB (Snapshotting) | Fork child process, writes copy-on-write snapshot to disk periodically (e.g., every 5 min) | Can lose up to snapshot interval of data | Low (background process); brief pause during fork on large datasets | Fast (load snapshot file) |
| AOF (Append-Only File) | Log every write command to file; replay on restart | Better (fsync every second or every write) | Higher (disk I/O on writes); AOF rewrite compacts file | Slower (replay all commands) |
| RDB + AOF | Hybrid: RDB for full snapshots + AOF for recent changes | Best (RDB base + AOF delta) | Medium (both mechanisms active) | Fast RDB load + short AOF replay |
| None | Pure in-memory cache (no persistence) | None (data lost on restart) | Zero (no disk I/O) | N/A (start empty) |
Redis Cluster Partitioning
Key Routing:
slot = CRC16(key) % 16384
# Client contacts any node; if wrong slot, server returns MOVED redirect
# Smart clients cache slot-to-node mapping for direct routing
Answer: (1) All operations are in-memory (no disk I/O blocking), (2) No lock contention (single thread = no mutex overhead), (3) Event loop with non-blocking I/O (epoll/kqueue) handles thousands of concurrent connections, (4) Simple data structures optimized for cache locality. Bottleneck is usually network, not CPU. Redis 6+ added I/O threading for socket reads/writes, but command execution remains single-threaded.
Memcached
Pure LRU cache. Simpler than Redis (no persistence, fewer data structures), multi-threaded (better for massive read-heavy workloads).
| Feature | Memcached | Redis |
|---|---|---|
| Threading | Multi-threaded (per-core) | Single-threaded (I/O threads in 6+) |
| Data Structures | Strings only | Strings, hashes, lists, sets, sorted sets, streams, etc. |
| Persistence | None | RDB snapshots + AOF log |
| Replication | None (client-side sharding) | Master-replica + Sentinel/Cluster |
| Eviction | Strict LRU | Multiple policies (LRU, LFU, TTL, volatile/allkeys) |
| Use Case | Pure cache layer (sessions, page fragments) | Cache + data structures + pub/sub + messaging |
DynamoDB
AWS managed key-value + document store. Fully managed (no servers), single-digit millisecond latency, unlimited scale, pay-per-request or provisioned capacity.
Architecture
Hash key range A-F] P2[Partition 2
Hash key range G-M] P3[Partition 3
Hash key range N-Z] end subgraph "Replication (3 AZs)" R1[Replica AZ-1] R2[Replica AZ-2] R3[Replica AZ-3] end Storage[Storage Layer
SSD-backed] end Client --> Router Router -->|Consistent hash| P1 Router --> P2 Router --> P3 P1 --> R1 P1 --> R2 P1 --> R3 R1 --> Storage R2 --> Storage R3 --> Storage
Data Model
Each item (row) must have a partition key (hash key). Optionally, a sort key (range key) for ordering items within a partition.
// Table: Users
{
"userId": "user123", // Partition key (PK)
"name": "Alice",
"email": "alice@example.com",
"createdAt": 1620000000
}
// Table: OrderItems (composite key)
{
"orderId": "order456", // Partition key (PK)
"itemId": "item789", // Sort key (SK)
"quantity": 2,
"price": 29.99
}
// Query: Get all items for order456, sorted by itemId
GET orderId = "order456"
Secondary Indexes
| Index Type | Scope | Key Requirements | Consistency | Use Case |
|---|---|---|---|---|
| Local Secondary Index (LSI) | Same partition key, different sort key | Must define at table creation | Strong or eventual | Query same partition by different attribute (e.g., orderId + timestamp instead of itemId) |
| Global Secondary Index (GSI) | Different partition key and/or sort key | Can add/remove after table creation | Eventual only | Query by non-primary key (e.g., email lookup in Users table) |
Consistency Models
| Mode | Behavior | Latency | Cost |
|---|---|---|---|
| Eventual Consistency | Read from any replica; may see stale data (< 1 second lag) | Lower | 0.5x RCU (read capacity units) |
| Strong Consistency | Read from leader replica; always latest data | Higher | 1x RCU |
Adaptive Capacity
DynamoDB automatically redistributes capacity to hot partitions. If one partition gets 10x traffic, DynamoDB boosts its throughput temporarily (borrowing from unused capacity elsewhere).
userId#<0-9> suffix) or use DynamoDB Accelerator (DAX) for caching.
etcd
Distributed KV store for configuration and coordination. Built on Raft consensus algorithm; used by Kubernetes for cluster state.
| Feature | Description | Use Case |
|---|---|---|
| Raft Consensus | Leader election + log replication; strong consistency; quorum writes (majority) | Ensures all nodes agree on state even during failures |
| Watch API | Clients subscribe to key changes; get notified in real-time | Service discovery (watch /services/api-server for IP changes) |
| TTL Keys | Automatic expiration (leases) | Leader election (holder renews lease; if dies, lease expires and new leader elected) |
| Transactions | Compare-and-swap (CAS) operations; multi-key ACID txns | Distributed locks, atomic configuration updates |
| Prefix Range Queries | List all keys with prefix (e.g., /config/db/*) | Hierarchical configuration |
etcd: Strong consistency (Raft), designed for critical metadata (Kubernetes state, service discovery). Slower writes (quorum required) but guaranteed linearizability.
Redis: Eventual consistency (async replication), designed for caching and high-throughput data structures. Faster but can lose data or see stale reads during failover.
When to Use Key-Value Stores
| Scenario | Why KV Fits | Recommended Store |
|---|---|---|
| Session Management | Fast reads/writes by session ID; TTL for expiration | Redis (persistence for sticky sessions), Memcached (pure cache) |
| Caching | High read throughput; LRU eviction; tolerate data loss | Memcached (simple), Redis (richer features) |
| Rate Limiting | Atomic counters (INCR); sliding window with sorted sets | Redis |
| Real-time Analytics Counters | High-write throughput; eventual consistency OK | DynamoDB (managed scale), Redis (sorted sets for leaderboards) |
| Configuration Store | Strong consistency; watch for changes; small dataset | etcd |
| Feature Flags | Fast lookups; infrequent updates; broadcast changes | Redis (pub/sub for updates), etcd (watch API) |
| Shopping Cart | User-keyed data; occasional writes; merge conflicts tolerable | DynamoDB (managed, AP), Redis (fast, CP) |
11.3 Document Databases
Conceptual Model
Store documents (JSON, BSON, XML) as first-class entities. Unlike KV stores, documents have internal structure that the database can index and query.
| Characteristic | Implication |
|---|---|
| Flexible Schema | Documents in same collection can have different fields; schema-on-read |
| Nested Structures | Embed related data (denormalization); reduces joins |
| Rich Queries | Query by any field; secondary indexes; aggregation pipelines |
| Horizontal Scaling | Shard by document ID or chosen shard key |
MongoDB
The dominant document database. BSON format (binary JSON), rich query language, aggregation framework, sharding and replication built-in.
Architecture
All writes] Secondary1[Secondary 1
Async replication] Secondary2[Secondary 2
Async replication] Primary -->|Oplog replication| Secondary1 Primary -->|Oplog replication| Secondary2 Secondary1 -.->|Heartbeat| Primary Secondary2 -.->|Heartbeat| Primary end subgraph "Sharded Cluster (optional)" Mongos[mongos
Query Router] ConfigServers[Config Servers
Cluster metadata] Shard1[Shard 1
Replica Set
Chunk A-M] Shard2[Shard 2
Replica Set
Chunk N-Z] Mongos --> ConfigServers Mongos --> Shard1 Mongos --> Shard2 end Client -->|Single Replica Set| Primary Client -->|Read preference:
primary/secondary| Secondary1 Client -.->|Sharded Setup| Mongos
Data Model
// Collection: users
{
"_id": ObjectId("507f1f77bcf86cd799439011"), // Auto-generated 12-byte ID
"name": "Alice",
"email": "alice@example.com",
"age": 30,
"address": {
"street": "123 Main St",
"city": "NYC",
"zip": "10001"
},
"interests": ["hiking", "photography"],
"createdAt": ISODate("2023-01-15T10:30:00Z")
}
// Collection: orders (reference to user)
{
"_id": ObjectId("507f1f77bcf86cd799439012"),
"userId": ObjectId("507f1f77bcf86cd799439011"), // Reference
"items": [
{ "productId": "prod123", "quantity": 2, "price": 29.99 },
{ "productId": "prod456", "quantity": 1, "price": 49.99 }
],
"total": 109.97,
"status": "shipped"
}
Embedding vs Referencing
| Pattern | When to Use | Pros | Cons |
|---|---|---|---|
| Embedding (denormalize) |
1:few relationships; data accessed together; bounded array size | Single read to get all data; atomic updates | Document size limit (16MB); duplication if data shared across docs |
| Referencing (normalize) |
1:many or many:many; data accessed independently; unbounded growth | No duplication; flexible access patterns | Multiple queries (application-side join); no ACID across documents |
Example Decision:
- Embed user's address (1:1, always accessed together)
- Reference user's orders (1:many, unbounded, orders queried separately)
Indexing
// Single-field index
db.users.createIndex({ email: 1 }) // 1 = ascending, -1 = descending
// Compound index
db.orders.createIndex({ userId: 1, createdAt: -1 })
// Multikey index (array fields)
db.users.createIndex({ interests: 1 }) // Indexes each array element
// Text index (full-text search)
db.products.createIndex({ description: "text" })
// Geospatial index
db.stores.createIndex({ location: "2dsphere" })
// Unique index
db.users.createIndex({ email: 1 }, { unique: true })
Aggregation Pipeline
Multi-stage data transformation (like Unix pipes):
db.orders.aggregate([
// Stage 1: Filter
{ $match: { status: "shipped", createdAt: { $gte: ISODate("2023-01-01") } } },
// Stage 2: Join with users collection
{ $lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}},
// Stage 3: Unwind array
{ $unwind: "$user" },
// Stage 4: Group and aggregate
{ $group: {
_id: "$user.city",
totalRevenue: { $sum: "$total" },
orderCount: { $sum: 1 }
}},
// Stage 5: Sort
{ $sort: { totalRevenue: -1 } },
// Stage 6: Limit
{ $limit: 10 }
]);
Sharding Strategy
shard = hash(shardKey) % numShards"] Range["Range Sharding
Chunk A-M → Shard1
Chunk N-Z → Shard2"] Zone["Zone Sharding
USA data → Shard1
EU data → Shard2"] end Mongos --> Hash Mongos --> Range Mongos --> Zone Hash --> Shard1[Shard 1] Hash --> Shard2[Shard 2] Range --> Shard1 Range --> Shard2 Zone --> Shard1 Zone --> Shard2
| Shard Key Type | Distribution | Range Queries | Use Case |
|---|---|---|---|
| Hashed | Uniform (random distribution) | Requires scatter-gather (query all shards) | High write throughput; no hot spots; don't need range queries |
| Range | Skewed if key not evenly distributed | Efficient (target specific shard) | Time-series data (shard by date); ordered data access |
| Zone | Manual control (geo, tenant, etc.) | Depends on key | Data locality (GDPR), multi-tenancy |
Elasticsearch
Document store + full-text search engine. Built on Apache Lucene; inverted index for fast text search; also used for log analytics (ELK stack).
Architecture
Cluster coordination] subgraph "Data Nodes" Node1[Node 1] Node2[Node 2] Node3[Node 3] end subgraph "Index: products (3 primary shards, 1 replica)" P1[Primary Shard 1] P2[Primary Shard 2] P3[Primary Shard 3] R1[Replica Shard 1] R2[Replica Shard 2] R3[Replica Shard 3] end Master -.->|Manages| Node1 Master -.->|Manages| Node2 Master -.->|Manages| Node3 Node1 --> P1 Node1 --> R2 Node2 --> P2 Node2 --> R3 Node3 --> P3 Node3 --> R1 end Client -->|Index document| Node1 Client -->|Search query| Node2
Inverted Index
Core data structure for full-text search:
// Documents
Doc1: "The quick brown fox jumps"
Doc2: "Quick brown dogs"
Doc3: "The lazy fox sleeps"
// Inverted Index (after tokenization + stemming)
Term → Document IDs
"quick" → [Doc1, Doc2]
"brown" → [Doc1, Doc2]
"fox" → [Doc1, Doc3]
"jump" → [Doc1]
"dog" → [Doc2]
"lazy" → [Doc3]
"sleep" → [Doc3]
// Query: "quick fox" → Match Doc1 (contains both terms)
Search Query DSL
POST /products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "description": "laptop" } } // Full-text search
],
"filter": [
{ "range": { "price": { "gte": 500, "lte": 1500 } } },
{ "term": { "brand": "Apple" } }
]
}
},
"aggs": {
"price_ranges": {
"histogram": {
"field": "price",
"interval": 100
}
}
},
"sort": [
{ "_score": "desc" }, // Relevance score
{ "price": "asc" }
]
}
Use Cases
| Use Case | Why Elasticsearch |
|---|---|
| Full-Text Search | Inverted index; relevance scoring (TF-IDF, BM25); fuzzy matching; autocomplete |
| Log Analytics | ELK stack (Elasticsearch + Logstash + Kibana); ingest logs, index, visualize dashboards |
| Real-Time Analytics | Aggregations (histograms, percentiles, cardinality); near-real-time indexing (1 sec refresh) |
| Geospatial Search | Geo-point/geo-shape types; radius search, bounding box, polygon queries |
| Application Search | E-commerce product search, content recommendations, typeahead suggestions |
Answer: MongoDB has text indexes, but Elasticsearch is purpose-built for search: (1) Advanced text analysis (stemming, synonyms, language-specific), (2) Relevance scoring (BM25), (3) Faceted search (aggregations), (4) Performance (inverted index optimized for reads), (5) Real-time analytics. Use MongoDB for general document storage + basic search; use Elasticsearch when search is a primary feature.
Firestore
Google's managed document database. Real-time sync, offline support, automatic scaling, tight integration with Firebase ecosystem.
| Feature | Description |
|---|---|
| Real-Time Listeners | Clients subscribe to queries; get updates pushed instantly when data changes |
| Offline Support | Client-side cache; writes queued locally and synced when online |
| Automatic Scaling | No sharding config; scales to millions of concurrent connections |
| Security Rules | Declarative access control at document/collection level |
| Multi-region Replication | Synchronous replication across regions for high availability |
When to Use Document Databases
| Scenario | Why Document DB Fits | Recommended Store |
|---|---|---|
| Content Management | Flexible schema (articles, pages, posts have varying fields); rich queries | MongoDB, Firestore |
| User Profiles | Nested data (preferences, settings); embed related entities (addresses, payment methods) | MongoDB, Firestore |
| Product Catalogs | Varying attributes per category (laptop specs ≠ shirt specs); full-text search | Elasticsearch (search), MongoDB (storage) |
| Mobile/Web Apps | Real-time sync, offline support, rapid prototyping (schema evolution) | Firestore |
| Log Storage | Unstructured/semi-structured logs; full-text search; aggregations | Elasticsearch |
| Event Sourcing | Append-only events (documents); flexible schema for event types | MongoDB, Firestore |
11.4 Wide-Column Stores
Conceptual Model
Data organized into rows and column families. Each row can have arbitrary columns; optimized for high write throughput and time-series data.
Column Family: profile
name: 'Alice'
email: 'alice@example.com'
Column Family: activity
login_2024-01-01: '10:30'
login_2024-01-02: '09:15'"] Row2["Row Key: user456
Column Family: profile
name: 'Bob'
Column Family: activity
login_2024-01-01: '14:20'"] end Client[Client] -->|GET user123:profile:name| Row1 Client -->|GET user123:activity:login_*| Row1
| Characteristic | Implication |
|---|---|
| Sparse Columns | Rows can have millions of columns; only store non-null values (efficient for sparse data) |
| Column-Oriented Storage | Columns stored together on disk; efficient for analytical queries (read specific columns) |
| No Joins | Denormalize data; model relationships via row keys and column naming |
| Tunable Consistency | Trade consistency for availability/latency (quorum reads/writes) |
| Optimized for Writes | Log-structured merge trees (LSM); sequential writes; background compaction |
Cassandra
Masterless, AP-focused wide-column store. Inspired by Amazon DynamoDB paper + Google Bigtable; tunable consistency, linear scalability, no single point of failure.
Architecture
Token Range: 0-25] Node2[Node 2
Token Range: 26-50] Node3[Node 3
Token Range: 51-75] Node4[Node 4
Token Range: 76-100] Node1 -->|Gossip Protocol| Node2 Node2 -->|Gossip Protocol| Node3 Node3 -->|Gossip Protocol| Node4 Node4 -->|Gossip Protocol| Node1 end subgraph "Data Replication (RF=3)" Primary[Primary Replica
Node 1] Replica1[Replica 2
Node 2] Replica2[Replica 3
Node 3] Primary -.->|Async replication| Replica1 Primary -.->|Async replication| Replica2 end Client -->|Write/Read| Node1 Client -->|Write/Read| Node2 Client -->|Write/Read| Node3
Gossip Protocol
Nodes exchange cluster state information every second (peer-to-peer). No central coordinator; eventually all nodes learn about cluster changes (new nodes, failures).
// Node 1 gossips to Node 2:
{
"Node1": { "status": "UP", "load": 45%, "version": 123 },
"Node3": { "status": "UP", "load": 60%, "version": 122 },
"Node4": { "status": "DOWN", "last_seen": 1620000000 }
}
// Node 2 merges with its own state and gossips to Node 3...
// Within seconds, all nodes agree on cluster state
Tunable Consistency
Specify consistency level per query (trade-off latency vs consistency):
| Level | Read | Write | Latency | Consistency |
|---|---|---|---|---|
| ONE | Return first response | 1 node ACK | Lowest | Eventual (may see stale data) |
| QUORUM | Majority of replicas | Majority ACK | Medium | Strong (R + W > RF) |
| ALL | All replicas respond | All replicas ACK | Highest | Strongest (but fails if any node down) |
| LOCAL_QUORUM | Majority in local DC | Majority in local DC | Low (no cross-DC) | Strong within DC |
Example: For strong consistency, use QUORUM for both reads and writes (with RF=3, require 2 nodes to agree). This ensures read always sees latest write.
Data Model
// CQL (Cassandra Query Language, SQL-like)
CREATE TABLE user_activity (
user_id UUID,
activity_date DATE,
activity_time TIMESTAMP,
action TEXT,
PRIMARY KEY ((user_id), activity_date, activity_time)
);
// Partition Key: user_id (determines which node stores data)
// Clustering Columns: activity_date, activity_time (order within partition)
// Query: Get all activities for user on 2024-01-15
SELECT * FROM user_activity
WHERE user_id = 123e4567-e89b-12d3-a456-426614174000
AND activity_date = '2024-01-15';
LSM Tree Storage
Sorted in-memory buffer] end subgraph "Disk (SSTables)" SSTable1[SSTable 1
Immutable sorted file
Recent] SSTable2[SSTable 2
Older] SSTable3[SSTable 3
Oldest] end Write --> Memtable Write -.->|Also write| CommitLog[Commit Log
Append-only WAL] Memtable -->|Full? Flush to disk| SSTable1 SSTable1 -.->|Compaction| SSTable2 SSTable2 -.->|Compaction| SSTable3 Read[Read Request] --> Memtable Read --> SSTable1 Read --> SSTable2 Read --> SSTable3
Write Path:
- Write to commit log (append-only, fast sequential I/O)
- Write to memtable (in-memory sorted structure)
- Acknowledge write immediately (no disk read)
- When memtable full, flush to SSTable (immutable on-disk file)
Read Path:
- Check memtable (recent writes)
- Check SSTables (use bloom filters to skip files that definitely don't have key)
- Merge results from multiple SSTables (tombstones mark deletions)
Compaction: Background process merges SSTables, removes deleted data (tombstones), and reduces read amplification (fewer files to check).
When to Use Cassandra
| Use Case | Why Cassandra |
|---|---|
| Time-Series Data | High write throughput; efficient range queries (clustering columns); time-based partitioning |
| IoT / Sensor Data | Millions of writes/sec; scale horizontally; eventual consistency tolerable |
| Activity Feeds | User-partitioned data; high write volume; read your own writes |
| Messaging / Notifications | Append-only workload; time-ordered data; no single point of failure |
| Multi-Datacenter | Built-in multi-DC replication; LOCAL_QUORUM for low latency |
HBase
Hadoop's wide-column store. Built on HDFS; strong consistency (CP); tight integration with Hadoop ecosystem (MapReduce, Spark).
Architecture
Region assignment, DDL] subgraph "Region Servers" RS1[Region Server 1] RS2[Region Server 2] RS3[Region Server 3] end subgraph "Regions (Row Ranges)" R1[Region 1
Rows A-M] R2[Region 2
Rows N-Z] end ZooKeeper[ZooKeeper
Coordination, leader election] end subgraph "Storage" HDFS[HDFS
Distributed file system
3x replication] end Client --> ZooKeeper Client --> RS1 Client --> RS2 Master -.->|Assigns| RS1 Master -.->|Assigns| RS2 Master -.->|Assigns| RS3 RS1 --> R1 RS2 --> R2 R1 --> HDFS R2 --> HDFS Master -.-> ZooKeeper RS1 -.-> ZooKeeper RS2 -.-> ZooKeeper
| Component | Role |
|---|---|
| HMaster | Schema changes, region assignment, load balancing, failover coordination |
| Region Server | Serves reads/writes for assigned regions; manages memstore and HFiles |
| Region | Contiguous row range for a table; splits automatically when too large (10GB default) |
| ZooKeeper | Cluster coordination; stores region-to-server mapping; HMaster election |
| HDFS | Durable storage; 3x replication; stores HFiles (immutable SSTables) |
Cassandra: AP (eventual consistency by default), no single point of failure, optimized for always-on writes, multi-DC out-of-box.
HBase: CP (strong consistency), HMaster is SPOF (mitigated by ZooKeeper), optimized for read-heavy + Hadoop integration, better for sequential scans.
ScyllaDB
Cassandra-compatible, rewritten in C++. Shard-per-core architecture; 10x throughput of Cassandra; drop-in replacement (uses CQL).
per core
Garbage collection pauses] end subgraph "ScyllaDB (C++)" Core1[Core 1
Independent shard] Core2[Core 2
Independent shard] Core3[Core 3
Independent shard] Core4[Core 4
Independent shard] Core1 -.->|No shared state| Core2 Core2 -.->|No shared state| Core3 Core3 -.->|No shared state| Core4 end style ScyllaDB fill:#2d5,stroke:#3f6,stroke-width:2px
Key Optimizations:
- Shard-per-Core: Each CPU core owns a shard (partition of data); no locks, no context switching
- User-Space I/O: Bypass kernel for disk/network I/O (DPDK, io_uring)
- No GC Pauses: Manual memory management (C++); predictable latency
- Automatic Tuning: Self-tunes cache sizes, compaction schedules, etc.
11.5 Graph Databases
Property Graph Model
Store nodes (entities) and relationships (edges) as first-class citizens. Each can have properties (key-value pairs).
name: Alice
age: 30] Bob[Node: Person
name: Bob
age: 25] Carol[Node: Person
name: Carol
age: 28] Product[Node: Product
name: Laptop
price: 999] Alice -->|FRIEND_OF
since: 2020| Bob Bob -->|FRIEND_OF
since: 2021| Carol Alice -->|FRIEND_OF
since: 2019| Carol Alice -->|PURCHASED
date: 2024-01-15| Product Bob -->|VIEWED
date: 2024-01-20| Product style Alice fill:#3498db style Bob fill:#3498db style Carol fill:#3498db style Product fill:#e74c3c
| Component | Description | Example |
|---|---|---|
| Node | Entity with labels and properties | (:Person {name: "Alice", age: 30}) |
| Relationship | Directed edge with type and properties | -[:FRIEND_OF {since: 2020}]-> |
| Property | Key-value pair on node or relationship | name: "Alice", since: 2020 |
| Label | Node type (like a table in RDBMS) | Person, Product |
Neo4j
The leading graph database. Native graph storage (index-free adjacency); Cypher query language; ACID transactions.
Index-Free Adjacency
Each node physically contains pointers to its relationships (like a linked list). Traversing relationships is O(1) (follow pointer), not O(log n) (index lookup).
user_id, friend_id] Index[B-Tree Index on friend_id] UserTable -->|Lookup in index| Index Index -->|Find matching rows| FriendTable end subgraph "Neo4j (Index-Free Adjacency)" Node1[Node: Alice] Node2[Node: Bob] Node3[Node: Carol] Node1 -.->|Direct pointer| Rel1[Relationship: FRIEND_OF] Rel1 -.->|Direct pointer| Node2 Node1 -.->|Direct pointer| Rel2[Relationship: FRIEND_OF] Rel2 -.->|Direct pointer| Node3 end style Neo4j fill:#2d5,stroke:#3f6,stroke-width:2px
Cypher Query Language
ASCII-art syntax for pattern matching:
// Find Alice's friends
MATCH (alice:Person {name: "Alice"})-[:FRIEND_OF]->(friend)
RETURN friend.name
// Find friends-of-friends (2 hops)
MATCH (alice:Person {name: "Alice"})-[:FRIEND_OF*2]-(foaf)
RETURN DISTINCT foaf.name
// Shortest path between Alice and Carol
MATCH path = shortestPath(
(alice:Person {name: "Alice"})-[:FRIEND_OF*]-(carol:Person {name: "Carol"})
)
RETURN path
// Recommend products (friends who purchased)
MATCH (alice:Person {name: "Alice"})-[:FRIEND_OF]-(friend)
-[:PURCHASED]->(product)
WHERE NOT (alice)-[:PURCHASED]->(product)
RETURN product.name, count(friend) AS friendCount
ORDER BY friendCount DESC
LIMIT 5
// Create new data
CREATE (alice:Person {name: "Alice", age: 30})
CREATE (bob:Person {name: "Bob", age: 25})
CREATE (alice)-[:FRIEND_OF {since: 2020}]->(bob)
Use Cases
| Use Case | Why Graph DB | Query Pattern |
|---|---|---|
| Social Networks | Multi-hop traversals (friends-of-friends); relationship-centric queries | "Find mutual friends", "Suggest connections", "Influencer detection" |
| Fraud Detection | Detect suspicious patterns (e.g., multiple accounts with same phone number, address, IP) | "Find accounts linked by shared properties", "Detect rings of collusion" |
| Recommendation Engines | Collaborative filtering via graph traversal (users who bought X also bought Y) | "Recommend products based on social graph + purchase history" |
| Knowledge Graphs | Store entities and relationships (e.g., Google Knowledge Graph, Wikipedia) | "Answer complex questions by traversing relationships" |
| Network/IT Operations | Model infrastructure dependencies (servers, apps, services) | "Impact analysis: which services affected if server X goes down?" |
| Supply Chain | Track product flow through suppliers, manufacturers, distributors | "Trace origin of defective batch", "Optimize logistics" |
Answer: (1) Simple CRUD with no relationships (overkill), (2) Analytics on large datasets (graph DBs slow for full table scans; use data warehouse), (3) Highly variable schema with no relationships (use document DB), (4) Write-heavy workloads (graph writes update indexes on relationships; less optimized than KV/column stores).
Amazon Neptune
AWS managed graph database. Supports both property graph (Gremlin) and RDF (SPARQL); multi-AZ replication, automated backups.
| Feature | Description |
|---|---|
| Dual Model | Property graph (Gremlin/TinkerPop) + RDF/SPARQL on same data |
| Storage | Up to 128TB; 6-way replication across 3 AZs |
| Read Replicas | Up to 15 read replicas; millisecond replica lag |
| ML Integration | Neptune ML for graph neural networks (link prediction, node classification) |
When to Use Graph Databases
Rule of thumb: If your queries involve 3+ joins or recursive traversals in a relational database, consider a graph database.
e.g., 2-hop friends| Neo4j[Neo4j/Neptune] Q1 -->|Variable depth
e.g., shortest path| Neo4j Q1 -->|Analytical queries
e.g., centrality, clustering| GraphAnalytics[Graph Analytics
GraphX, Spark] style Graph fill:#2d5,stroke:#3f6,stroke-width:2px
11.6 Time-Series Databases
Characteristics
Optimized for append-only data with timestamps. Common in monitoring, IoT, financial data.
| Feature | Implication |
|---|---|
| Immutable Data | No updates/deletes; only inserts and time-range queries |
| Time-Based Indexing | Primary index on timestamp; efficient range scans |
| Compression | Delta encoding, run-length encoding; 10-100x compression |
| Downsampling | Aggregate old data (1-sec → 1-min → 1-hour); save storage |
| Retention Policies | Automatically delete data older than N days |
InfluxDB
Purpose-built time-series database. InfluxQL (SQL-like) + Flux (functional query language); clustering in Enterprise edition.
Data Model
// Measurement (like table)
// Tags: indexed, low-cardinality dimensions
// Fields: values, not indexed
// Timestamp: nanosecond precision
cpu_usage,host=server1,region=us-east value=45.2 1620000000000000000
cpu_usage,host=server2,region=us-west value=62.8 1620000001000000000
memory_usage,host=server1,region=us-east value=8192 1620000000000000000
// Query: Average CPU usage per region in last hour
SELECT MEAN(value) FROM cpu_usage
WHERE time > now() - 1h
GROUP BY region, time(5m)
Storage Engine
Append-only] Cache[In-Memory Cache] subgraph "TSM Files (Time-Structured Merge Tree)" TSM1[TSM File 1
Compressed blocks
Time range: Hour 1] TSM2[TSM File 2
Time range: Hour 2] TSM3[TSM File 3
Time range: Hour 3] end end Write --> WAL Write --> Cache Cache -->|Flush to disk| TSM1 TSM1 -.->|Compaction| TSM2 TSM2 -.->|Compaction| TSM3 Query[Query] --> Cache Query --> TSM1 Query --> TSM2
Compression: Delta encoding (store differences), run-length encoding (repeated values), dictionary encoding (strings).
TimescaleDB
PostgreSQL extension for time-series. Full SQL support; combines relational + time-series capabilities; automatic partitioning.
Hypertables
Automatic partitioning into "chunks" (time ranges):
-- Create hypertable
CREATE TABLE metrics (
time TIMESTAMPTZ NOT NULL,
device_id INT,
temperature DOUBLE PRECISION,
humidity DOUBLE PRECISION
);
SELECT create_hypertable('metrics', 'time');
-- Behind the scenes: TimescaleDB creates chunks
-- _hyper_1_1_chunk (2024-01-01 to 2024-01-08)
-- _hyper_1_2_chunk (2024-01-08 to 2024-01-15)
-- ...
-- Query transparently spans chunks
SELECT AVG(temperature) FROM metrics
WHERE time > NOW() - INTERVAL '7 days'
AND device_id = 42;
Features
| Feature | Benefit |
|---|---|
| Full SQL | JOINs, window functions, CTEs — leverage PostgreSQL ecosystem |
| Continuous Aggregates | Materialized views that auto-update incrementally (real-time rollups) |
| Compression | Columnar compression on old chunks (10-20x reduction) |
| Retention Policies | Automatically drop old chunks (e.g., > 90 days) |
| Multi-Node | Distributed hypertables across nodes (Enterprise) |
Prometheus
Monitoring system + time-series DB. Pull model (scrapes metrics); PromQL query language; integrates with Grafana for dashboards.
Architecture
:9090/metrics] App2[App Server 2
:9090/metrics] DB[Database
:9100/metrics] end Prometheus[Prometheus Server
Scrapes + Stores + Queries] Grafana[Grafana
Dashboards] AlertManager[Alert Manager
Notifications] Prometheus -->|Scrape every 15s| App1 Prometheus -->|Scrape every 15s| App2 Prometheus -->|Scrape every 15s| DB Grafana -->|PromQL queries| Prometheus Prometheus -->|Fire alerts| AlertManager AlertManager -->|Email/Slack/PagerDuty| Admin[Admin]
Metric Types
| Type | Description | Example |
|---|---|---|
| Counter | Monotonically increasing (resets on restart) | Total HTTP requests, bytes sent |
| Gauge | Value can go up/down | CPU usage, memory usage, queue depth |
| Histogram | Distribution of values in buckets | Request latencies (p50, p95, p99) |
| Summary | Like histogram but calculates quantiles client-side | Response times |
# PromQL Examples
# CPU usage over 80% in last 5 minutes
avg(cpu_usage) > 80
# Request rate (requests/sec)
rate(http_requests_total[5m])
# 95th percentile latency
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# Disk space running out (predicts when disk full)
predict_linear(disk_free_bytes[1h], 4*3600) < 0
When to Use Time-Series Databases
| Scenario | Why Time-Series DB | Recommended DB |
|---|---|---|
| Application Monitoring | High write throughput; range queries; downsampling; alerting | Prometheus + Grafana |
| IoT Sensor Data | Millions of devices; append-only; compression; retention policies | InfluxDB, TimescaleDB |
| Financial Market Data | Tick data (price/volume); high precision timestamps; fast ingestion | TimescaleDB (SQL), InfluxDB |
| Log Aggregation | Time-ordered logs; full-text search; aggregations | Elasticsearch (ELK stack) |
| Business Metrics | Dashboards, KPIs, real-time analytics; SQL for ad-hoc queries | TimescaleDB |
11.7 NewSQL
The Best of Both Worlds
NewSQL databases aim to provide NoSQL scalability + RDBMS ACID guarantees. They achieve this through modern distributed systems techniques (Raft/Paxos, distributed transactions, snapshot isolation).
CockroachDB
Distributed SQL inspired by Spanner. PostgreSQL-compatible; multi-region; automatic rebalancing; survivable zone/region failures.
Architecture
Keys: A-M
Raft Group] R2[Range 2
Keys: N-Z
Raft Group] end subgraph "Nodes (3 regions)" Node1[Node 1
us-east] Node2[Node 2
us-central] Node3[Node 3
us-west] end subgraph "Raft Consensus" Leader1[Leader
Node 1] Follower1[Follower
Node 2] Follower2[Follower
Node 3] end end Client -->|SQL query| Node1 Node1 -->|Route to range| R1 R1 --> Leader1 Leader1 -->|Replicate| Follower1 Leader1 -->|Replicate| Follower2 Leader1 -.->|Commit when majority ack| Storage[Persistent Storage]
Key Features
| Feature | How It Works | Benefit |
|---|---|---|
| Range Partitioning | Data split into sorted ranges (~64MB); each range is a Raft group (3-5 replicas) | Automatic rebalancing; add nodes → ranges split/move automatically |
| Raft Consensus | Each range uses Raft for leader election + log replication (quorum writes) | Strong consistency; tolerates minority failures (2 out of 3 nodes can fail) |
| Distributed Transactions | Serializable isolation (strongest); two-phase commit across ranges | ACID guarantees even across nodes/regions |
| Geo-Partitioning | Pin data to specific regions (e.g., EU data in EU for GDPR) | Data locality; compliance; low latency |
| Automatic Failover | If leader fails, Raft elects new leader in < 5 seconds | High availability; no manual intervention |
-- Standard PostgreSQL-compatible SQL
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email STRING UNIQUE,
name STRING,
region STRING
);
-- Geo-partition: Keep EU users in EU
ALTER TABLE users PARTITION BY LIST (region) (
PARTITION eu VALUES IN ('eu'),
PARTITION us VALUES IN ('us')
);
ALTER PARTITION eu CONFIGURE ZONE USING constraints='[+region=eu-west]';
ALTER PARTITION us CONFIGURE ZONE USING constraints='[+region=us-east]';
-- Transaction (serializable across nodes)
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 'alice';
UPDATE accounts SET balance = balance + 100 WHERE id = 'bob';
COMMIT;
TiDB
MySQL-compatible NewSQL. Separates compute (TiDB servers) from storage (TiKV); Raft-based replication; HTAP (hybrid transactional/analytical).
SQL parser, optimizer] TiDB2[TiDB Server 2
SQL parser, optimizer] end subgraph "Storage Layer (TiKV)" TiKV1[TiKV Node 1
Raft replica] TiKV2[TiKV Node 2
Raft replica] TiKV3[TiKV Node 3
Raft replica] end PD[Placement Driver
Cluster metadata
Load balancing] TiFlash[TiFlash
Columnar storage
Analytical queries] end Client -->|MySQL protocol| TiDB1 Client --> TiDB2 TiDB1 --> PD TiDB1 --> TiKV1 TiDB1 --> TiKV2 TiKV1 -.->|Raft replication| TiKV2 TiKV1 -.->|Raft replication| TiKV3 TiKV1 -.->|Async replication| TiFlash
Google Spanner
The original NewSQL. Global scale (used by Gmail, Google Ads); TrueTime API for external consistency; serializable isolation.
TrueTime
Spanner's secret sauce: TrueTime API provides a time interval with bounded uncertainty (typically < 7ms).
// TrueTime API
earliest, latest = TT.now() // e.g., [t-3ms, t+3ms]
// Spanner uses this to order transactions globally
// Wait out the uncertainty before committing (commit-wait)
// Ensures transaction T1 committed before T2 starts → T1's timestamp < T2's timestamp
| Aspect | Implementation |
|---|---|
| Clock Sync | GPS + atomic clocks in every datacenter; sync error < 7ms |
| Commit Wait | Transaction waits max(uncertainty) before committing (ensures external consistency) |
| Snapshot Reads | Read from past timestamp (no locks); stale reads with bounded staleness |
Answer: TrueTime requires specialized hardware (atomic clocks, GPS) in every datacenter, which is expensive and complex. CockroachDB and others use hybrid logical clocks (HLC) instead — software-based, no special hardware, but slightly higher latency for global transactions.
YugabyteDB
Distributed SQL with PostgreSQL compatibility. Built on Raft + RocksDB; multi-API (SQL, Cassandra CQL, Redis).
| Feature | Description |
|---|---|
| Dual API | YSQL (PostgreSQL) for transactions; YCQL (Cassandra) for high-throughput writes |
| Raft Consensus | Like CockroachDB; each shard is a Raft group |
| Read Replicas | Async replicas in distant regions for low-latency reads |
| Tablespaces | Pin tables to specific regions (geo-partitioning) |
When to Use NewSQL
| Scenario | Why NewSQL | Recommended DB |
|---|---|---|
| Global Applications | Multi-region deployments; low latency everywhere; strong consistency | Spanner, CockroachDB, YugabyteDB |
| Financial Services | ACID guarantees at scale; regulatory compliance; no data loss | CockroachDB, Spanner |
| E-commerce | Transactions (inventory, orders); scale during peaks; relational model | TiDB, CockroachDB |
| SaaS Platforms | Multi-tenant; horizontal scaling; SQL familiarity; compliance (GDPR) | CockroachDB, YugabyteDB |
| RDBMS Migration | Outgrown single-node MySQL/Postgres; need scale but keep SQL | TiDB (MySQL), YugabyteDB (PostgreSQL), CockroachDB (PostgreSQL) |
11.8 Selection Decision Framework
Use this flowchart to narrow down database type based on access patterns and requirements:
Simple values| KV[Key-Value Store
Redis, DynamoDB, Memcached] Q1 -->|Nested documents
Flexible schema| Q2{Search Requirements} Q2 -->|Full-text search
Relevance ranking| ES[Elasticsearch] Q2 -->|Rich queries
No search focus| DOC[Document Store
MongoDB, Firestore] Q1 -->|Relationships
Graph structure| Q3{Query Type} Q3 -->|Multi-hop traversals
Pattern matching| GRAPH[Graph Database
Neo4j, Neptune] Q3 -->|Analytical
Clustering, pagerank| ANALYTICS[Graph Analytics
Neo4j + GDS, GraphX] Q1 -->|Tabular with
structured schema| Q4{Consistency Need} Q4 -->|Strong ACID
Global scale| NEWSQL[NewSQL
CockroachDB, Spanner] Q4 -->|Eventual OK
High write throughput| Q5{Access Pattern} Q5 -->|Time-series
Append-only| TS[Time-Series DB
InfluxDB, Prometheus] Q5 -->|Wide rows
Sparse columns| WIDE[Wide-Column
Cassandra, HBase] Q5 -->|Traditional SQL
Single region| RDBMS[Traditional RDBMS
PostgreSQL, MySQL] style KV fill:#e74c3c style DOC fill:#47a248 style ES fill:#005571 style GRAPH fill:#008cc1 style NEWSQL fill:#2d5,stroke:#3f6,stroke-width:2px style TS fill:#9b59b6 style WIDE fill:#1287b1 style RDBMS fill:#336791
Key Decision Factors
| Factor | Questions to Ask | Impact |
|---|---|---|
| Data Model | Key-value pairs? Nested documents? Graph relationships? Tabular? | Determines database category (KV, document, graph, relational) |
| Access Patterns | Read-heavy or write-heavy? Point lookups or range scans? Joins needed? | KV for simple lookups; RDBMS for complex queries; column for high writes |
| Consistency | Strong ACID required? Eventual consistency acceptable? | CP systems (RDBMS, NewSQL) vs AP systems (Cassandra, DynamoDB) |
| Scale | Dataset size? Query throughput (QPS)? Geographic distribution? | Single-node RDBMS OK? Need horizontal scaling (NoSQL, NewSQL)? |
| Query Complexity | Simple CRUD? Multi-table joins? Full-text search? Graph traversal? | Simpler queries → NoSQL; complex → SQL or specialized (search, graph) |
| Operational Complexity | Team expertise? Managed service available? Monitoring/backup needs? | Managed services (RDS, DynamoDB, Atlas) vs self-hosted |
| Cost | Budget constraints? Pay-per-request or provisioned? Storage costs? | DynamoDB on-demand costly at scale; Cassandra requires ops expertise |
Common Scenarios
| Application Type | Primary Database | Supporting Databases | Rationale |
|---|---|---|---|
| Social Network | Neo4j (graph) | Redis (cache), Cassandra (feeds), Elasticsearch (search) | Relationships are core feature; graph for friends/follows; Cassandra for activity feeds |
| E-commerce | PostgreSQL or CockroachDB | Redis (sessions, cart), Elasticsearch (product search), DynamoDB (inventory counters) | Transactions critical (orders, inventory); relational model fits; scale with NewSQL |
| SaaS App | MongoDB or PostgreSQL | Redis (cache), Elasticsearch (logs), TimescaleDB (metrics) | Flexible schema for multi-tenant data; MongoDB for rapid iteration; Postgres for stability |
| IoT Platform | Cassandra or TimescaleDB | InfluxDB (metrics), PostgreSQL (metadata) | High write throughput from sensors; time-series for sensor data; Cassandra for scale |
| Real-Time Analytics | ClickHouse or Druid | Kafka (streaming), Redis (state), Elasticsearch (dashboards) | OLAP workloads; columnar storage for fast aggregations; streaming ingestion |
| Content Management | MongoDB or Firestore | Elasticsearch (search), Redis (cache), S3 (media) | Flexible schema for varied content types; search for discovery; MongoDB for storage |
| Mobile App | Firestore | None (Firestore handles most needs) | Real-time sync, offline support, managed scaling; ideal for mobile/web apps |
- Clarify requirements: Data model, scale, consistency, access patterns
- Identify constraints: Latency SLAs, budget, team expertise, compliance
- Propose primary database: Based on core workload (transactions → SQL, writes → column, etc.)
- Add supporting databases: Cache layer (Redis), search (Elasticsearch), etc.
- Justify trade-offs: Why this choice over alternatives (CAP, cost, complexity)
11.9 Master Comparison Matrix
Comprehensive comparison of all NoSQL and NewSQL databases covered:
| Database | Type | Data Model | Consistency | Partition Strategy | Query Language | Scalability | Managed Service | Ideal Use Case |
|---|---|---|---|---|---|---|---|---|
| Redis | Key-Value | Strings, hashes, lists, sets, sorted sets, streams | CP (cluster), eventual (replication) | Consistent hashing (16384 slots) | Redis commands | Horizontal (cluster), vertical (single node) | AWS ElastiCache, Azure Cache, GCP Memorystore | Caching, sessions, real-time analytics, queues |
| Memcached | Key-Value | Strings only | None (pure cache) | Client-side consistent hashing | Text protocol (GET/SET) | Horizontal (client-side sharding) | AWS ElastiCache, GCP Memorystore | Pure cache layer, page fragments, sessions |
| DynamoDB | Key-Value + Document | Items (JSON-like) with partition/sort keys | Eventual or strong (per-request) | Hash partitioning (auto-sharding) | PartiQL, SDK query API | Unlimited (auto-scaling) | AWS DynamoDB (fully managed) | Serverless apps, shopping carts, session store, game state |
| etcd | Key-Value | Key-value with hierarchical keys | CP (Raft consensus) | Single Raft cluster (not horizontally scaled) | gRPC API (Get/Put/Watch) | Vertical (small datasets, < 8GB) | None (self-hosted) | Service discovery, configuration, distributed locks (Kubernetes) |
| MongoDB | Document | BSON documents (JSON-like) | CP (strong with majority reads/writes) | Hash or range sharding (configurable) | MongoDB Query Language (MQL) | Horizontal (sharding + replica sets) | MongoDB Atlas, AWS DocumentDB | Content management, user profiles, catalogs, mobile apps |
| Elasticsearch | Document + Search | JSON documents with inverted index | Eventual (async replication) | Hash sharding (automatic) | Query DSL (JSON), SQL (v7+) | Horizontal (shards + replicas) | Elastic Cloud, AWS OpenSearch | Full-text search, log analytics, real-time analytics (ELK) |
| Firestore | Document | Documents in collections (hierarchical) | Strong (multi-region sync) | Auto-sharding (managed by Google) | SDK queries (where/orderBy/limit) | Unlimited (auto-scaling) | Google Firestore (fully managed) | Mobile/web apps, real-time sync, offline support |
| CouchDB | Document | JSON documents with MVCC | AP (eventual consistency, conflict resolution) | Master-master replication | HTTP REST API, MapReduce views | Horizontal (multi-master) | IBM Cloudant | Offline-first apps, multi-master sync, mobile backends |
| Cassandra | Wide-Column | Column families (sparse columns) | Tunable (ONE, QUORUM, ALL) | Consistent hashing (token ring) | CQL (SQL-like) | Linear horizontal scaling (masterless) | DataStax Astra, AWS Keyspaces, Azure Cosmos DB (Cassandra API) | Time-series, IoT, activity feeds, high write throughput |
| HBase | Wide-Column | Column families (sparse columns) | CP (strong consistency) | Range-based regions on HDFS | Java API, Thrift, REST | Horizontal (regions across RegionServers) | AWS EMR, GCP Bigtable | Hadoop ecosystem, large-scale batch processing, Bigtable workloads |
| ScyllaDB | Wide-Column | Column families (Cassandra-compatible) | Tunable (same as Cassandra) | Consistent hashing (token ring) | CQL (Cassandra-compatible) | Linear horizontal scaling (10x faster than Cassandra) | ScyllaDB Cloud | Same as Cassandra but higher performance (low-latency, high-throughput) |
| Neo4j | Graph | Property graph (nodes + relationships) | CP (ACID within single instance), eventual (cluster) | Sharding via Fabric (Enterprise) | Cypher | Vertical (single node), horizontal (Fabric sharding in Enterprise) | Neo4j Aura | Social networks, fraud detection, recommendation engines, knowledge graphs |
| Amazon Neptune | Graph | Property graph + RDF | CP (strong consistency) | Auto-sharding (managed by AWS) | Gremlin (property), SPARQL (RDF) | Vertical (up to 15 replicas), managed scaling | AWS Neptune (fully managed) | Same as Neo4j but managed; integrates with AWS services |
| JanusGraph | Graph | Property graph | Depends on storage backend (Cassandra/HBase/BerkeleyDB) | Storage backend handles partitioning | Gremlin | Horizontal (via storage backend) | None (self-hosted) | Large-scale graphs (billions of edges), needs custom backend |
| InfluxDB | Time-Series | Measurements with tags (indexed) + fields (values) | AP (eventual in cluster), single-node (CP) | Time-based sharding (shards per time range) | InfluxQL, Flux | Horizontal (Enterprise/Cloud), vertical (OSS) | InfluxDB Cloud | Metrics, IoT sensor data, DevOps monitoring |
| TimescaleDB | Time-Series (PostgreSQL extension) | Relational tables (hypertables with time partitioning) | CP (ACID via PostgreSQL) | Time-based chunks, optional multi-node (Enterprise) | SQL (full PostgreSQL) | Vertical (single node), horizontal (multi-node in Enterprise) | Timescale Cloud, AWS RDS (via extension) | Time-series with SQL, financial data, business metrics, IoT |
| Prometheus | Time-Series | Metrics with labels (key-value tags) | Single-node (no replication by design) | Single-node (federate for scale) | PromQL | Vertical (federation for scale) | Grafana Cloud, AWS Managed Prometheus | Application/infrastructure monitoring, alerting (Prometheus + Grafana) |
| CockroachDB | NewSQL | Relational tables (PostgreSQL-compatible) | CP (serializable isolation, Raft consensus) | Range-based sharding (auto-balancing) | SQL (PostgreSQL dialect) | Linear horizontal scaling (add nodes → auto-rebalance) | CockroachDB Cloud | Global apps, financial services, multi-region ACID transactions |
| TiDB | NewSQL | Relational tables (MySQL-compatible) | CP (snapshot isolation, Raft via TiKV) | Range-based sharding (auto-balancing) | SQL (MySQL dialect) | Linear horizontal scaling (compute/storage separation) | TiDB Cloud | MySQL migration at scale, HTAP (transactional + analytical) |
| Google Spanner | NewSQL | Relational tables (SQL) | CP (external consistency via TrueTime, Paxos) | Range-based sharding (auto-balancing) | SQL (Google SQL dialect) | Unlimited horizontal scaling (global distribution) | Google Cloud Spanner (fully managed) | Mission-critical global apps (AdWords, Gmail), financial services |
| YugabyteDB | NewSQL | Relational tables (PostgreSQL-compatible) + Cassandra API | CP (serializable via Raft) | Range-based + hash sharding (auto-balancing) | SQL (PostgreSQL), CQL (Cassandra) | Linear horizontal scaling (multi-API) | Yugabyte Cloud | Multi-region, multi-cloud, PostgreSQL/Cassandra workloads at scale |
CAP Theorem Classification
| CP (Consistency + Partition Tolerance) | AP (Availability + Partition Tolerance) | Tunable |
|---|---|---|
|
|
|
- "High write throughput" → Cassandra, ScyllaDB, InfluxDB
- "Strong consistency + scale" → CockroachDB, Spanner, YugabyteDB
- "Full-text search" → Elasticsearch
- "Graph traversal" → Neo4j, Neptune
- "Real-time sync + offline" → Firestore
- "Simple key lookups + cache" → Redis, Memcached
- "Time-series + SQL" → TimescaleDB
- "Monitoring metrics" → Prometheus, InfluxDB
- "Multi-region, always on" → Cassandra, DynamoDB, CockroachDB