10 min read
System Design Index
Start Here
Tier 1 -- Building Blocks
Scale Reads
Scale Writes
Database Selection
Traffic Control
Consistency & Coordination
Estimation
Tier 2 -- Core Systems
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
System Design Index
Start Here
Tier 1 -- Building Blocks
Scale Reads
Scale Writes
Database Selection
Traffic Control
Consistency & Coordination
Estimation
Tier 2 -- Core Systems
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
Wide-Column Store (Cassandra, HBase) — AP, Massive Write Throughput
Tier 1 — Building Block
1. What Is It?
A wide-column store organizes data as rows identified by a row key, where each row can have a different set of columns, and columns are grouped into column families. Unlike relational databases where all rows in a table have the same schema, wide-column stores allow each row to have a unique set of columns — and individual columns within a row are independently versioned, compressed, and stored.
The defining characteristics are: extreme write (millions of writes/sec across a cluster), AP semantics (Available + Partition Tolerant from CAP), linear horizontal scalability, and no . The trade-off: no JOINs, no secondary indexes (or limited ones), no multi-row ACID transactions, and a data model that must be designed around query patterns rather than data relationships.
Cassandra is the most widely used wide-column store. HBase is Hadoop-integrated (built on HDFS), more commonly found in data engineering pipelines.
Your team is building a backend service that needs to handle millions of writes per second and must remain available even during network partitions. However, the data access patterns are well-defined upfront, and the team is comfortable designing the schema around specific queries. Which trade-off should the team be prepared to accept when choosing a wide-column store for this use case?
2. How It Works
Cassandra Data Model
Cassandra's data model hierarchy: Keyspace → Table → Partition → Row → Column.
Keyspace: social_network
Table: user_events
Partition Key: user_id ← determines which node(s) store this data
Clustering Key: event_timestamp ← determines order within the partition
Columns: event_type, metadata
All rows with the same user_id are stored on the same node (the partition), sorted by event_timestamp. This enables efficient range queries within a partition (SELECT ... WHERE user_id=42 AND event_timestamp > '2024-01-01') but not across partitions (no efficient SELECT WHERE event_type='click').
Write Path
- CommitLog: A Write-Ahead Log () — every write is recorded here first, so it can be replayed on crash recovery
- MemTable: In-memory sorted write buffer. When it fills up, it's flushed to disk as an SSTable. This is the pattern — converting random writes into sequential disk writes for higher (see & LSM Trees building block for details).
- SSTable: Sorted String Table — an immutable, sorted file on disk. Once written, never modified.
- W (write consistency level): How many replica ACKs the coordinator waits for before acknowledging to the client (configurable: ONE, , ALL)
Read Path
- R (read consistency level): How many replicas the coordinator reads from before returning (ONE = fast, may be stale; = balanced; ALL = strong but slow)
- Read repair: When a coordinator reads from multiple replicas and detects inconsistency, it asynchronously sends corrections to stale replicas
Consistency Levels and CAP Trade-Off
Replication Factor (RF) = 3
N = 3 replicas per partition
Strong consistency: W + R > N
QUORUM write (2 acks) + QUORUM read (2 acks) = 4 > 3 ✓ → Strong consistency
High availability: ONE write + ONE read → Fast, but may return stale data
| Write Level | Read Level | Consistency | Latency | Availability |
|---|---|---|---|---|
| ONE | ONE | Eventual | Lowest | Highest (any node can serve) |
| QUORUM | QUORUM | Strong (W+R > N) | Medium | Medium |
| ALL | ALL | Strong (all replicas) | Highest | Lowest (any replica down = failure) |
| LOCAL_QUORUM | LOCAL_QUORUM | Strong within datacenter | Low (local DC only) | High (tolerates remote DC failure) |
A social media platform uses Cassandra with a replication factor of 3 to store user activity logs. The team needs strong consistency guarantees — every read must reflect the most recent write. Which combination of write and read consistency levels achieves this?
3. Variants & Comparisons
| Cassandra | HBase | |
|---|---|---|
| Lineage | Amazon Dynamo (distribution) + Google Bigtable (data model) | Based on Google Bigtable; runs on Hadoop/HDFS |
| Storage | Custom LSM-based SSTable files on local disk | HDFS (Hadoop Distributed File System) |
| Availability | Masterless (any node can handle any request) | Master-slave (HMaster + RegionServers) |
| SPOF | None (fully peer-to-peer) | HMaster is a potential SPOF (mitigated by backup master) |
| CAP | AP (tunable consistency) | CP (strong consistency, ZooKeeper coordination) |
| Write throughput | Extremely high (masterless, all nodes accept writes) | Very high (limited by HDFS write path) |
| Best for | Low-latency, high-throughput write OLTP | Batch analytics on Hadoop, tight HBase/Spark/Hadoop integration |
| Users | Netflix, Discord, Uber, Apple, Instagram | Facebook Messenger (original), Pinterest, Twitter |
Cassandra vs. DynamoDB
| Cassandra | DynamoDB | |
|---|---|---|
| Deployment | Self-hosted or DataStax Astra (managed) | AWS fully managed |
| Pricing | Infrastructure costs; no per-request cost | Pay per request or provisioned capacity |
| Flexibility | Open source; run anywhere | AWS lock-in |
| Operations | High ops burden (tuning, compaction, GC) | Zero ops |
| Global tables | Multi-datacenter native | DynamoDB Global Tables |
| Choose when | Multi-cloud, hybrid cloud, control over tuning | AWS-native, zero-ops required |
Your team is building a multi-cloud backend service that requires extremely high write throughput, the ability to tune consistency levels per request, and no dependency on a single cloud provider. Which wide-column database is the better architectural fit, and why?
4. When to Use It (and When NOT To)
Use Cassandra When:
- Write > 100K/sec: Cassandra scales writes linearly — add nodes, get proportional
- Append-mostly workloads: Event logs, time-series, activity streams, IoT sensor data — new data added, rarely updated
- Global multi-datacenter: Cassandra's
LOCAL_QUORUMconsistency enables multi-datacenter deployments with strong local consistency - Time-series data with time-range queries: Model as
(device_id, timestamp)→ values; partition by device, cluster by timestamp; range queries within a partition are efficient - No JOINs needed: Your access patterns are all partition-key lookups, no relational queries
Decision triggers:
- "If writes > 100K/sec sustained → Cassandra or sharded SQL"
- "If data is time-series (metrics, events, logs) → Cassandra with (entity_id, timestamp) data model"
- "If you need zero-downtime global multi-datacenter writes → Cassandra with LOCAL_QUORUM"
Do NOT Use Cassandra When:
- Ad-hoc queries:
SELECT WHERE arbitrary_column = Xrequires ALLOW FILTERING (full cluster scan) — catastrophically slow - Relational data with JOINs: No JOIN support; must denormalize aggressively
- Multi-row ACID transactions: Cassandra's lightweight transactions (LWT using Paxos) exist but are expensive and limited. For real ACID transactions, use PostgreSQL.
- Low cardinality partition key:
SELECT ... WHERE country='US'— US gets 40% of all rows on one partition. Cassandra partitions must be large enough to distribute load evenly but not one giant "hot" partition (max practical partition size ~100MB).
Anti-patterns:
- Giant partitions: A partition with 100M rows is slow to read, slow to compact, and causes GC pressure. Bucket your data: instead of
(user_id, event_timestamp)producing huge partitions for power users, use(user_id, year_month, event_timestamp)to cap partition size per month. - Too many secondary indexes: Cassandra secondary indexes are local (per node, not global). A query on a requires reading from ALL nodes — full cluster scatter-gather. Use materialized views or denormalized tables instead.
- Reads without partition key: Any query that doesn't filter by the full partition key becomes a full cluster scan. Design your tables around your query patterns first.
- Expecting SQL-like flexibility: Cassandra requires schema design upfront around specific access patterns. Changing your access pattern often requires creating a new table (denormalized copy of the data).
Your team stores IoT sensor events in Cassandra using a partition key of device_id and a clustering column of event_timestamp. After several months, you notice that a handful of high-traffic devices have accumulated tens of millions of rows per partition, causing slow reads and garbage collection pressure. Which schema change best addresses this problem?
5. Real-World Usage
Netflix (Cassandra for viewing history): Netflix stores viewing history for ~260M subscribers in Cassandra. Every play, pause, resume, and completion event is a Cassandra write. The data model: partition by (profile_id), cluster by (video_id, event_timestamp). At peak, Netflix processes ~1 million writes/sec across their Cassandra clusters globally. They store trillions of rows. Netflix chose Cassandra for its multi-datacenter (their 3-region AWS architecture) and write — they cannot afford to lose a viewing history write.
Discord (Cassandra for message storage, then ScyllaDB): Discord stored billions of messages in Cassandra with the schema (channel_id, message_id DESC) — partition by channel, cluster by message ID (, descending for "newest first" queries). Discord served ~120 billion messages/year from Cassandra at peak. When read degraded due to pressure and GC pauses on the JVM, Discord migrated to ScyllaDB (a C++ reimplementation of Cassandra) — keeping the same CQL API but achieving better and more predictable .
Apple (Cassandra at extreme scale): Apple runs one of the largest Cassandra deployments in the world — reportedly ~75,000+ Cassandra nodes, storing data for iCloud, iMessage, Siri, and other services. Apple's scale illustrates Cassandra's linear scalability: adding nodes proportionally increases both and storage capacity.
Discord originally stored billions of messages in Cassandra using the schema (channel_id, message_id DESC). Over time, they experienced degraded read latency caused by compaction pressure and JVM garbage collection pauses. They eventually migrated to ScyllaDB. What was the primary advantage of this migration?
6. Interview Cheat Sheet
Key sentences to demonstrate depth:
- "Cassandra is the right choice when write exceeds what a single SQL node can handle, the data model is append-mostly (events, time-series), and you need multi-datacenter . It trades JOINs, ad-hoc queries, and ACID for linear write scalability."
- "The most important Cassandra design decision is the partition key — it determines data distribution. Bad partition key = hot partitions. The partition key must be high-cardinality, evenly distributes load, and must be in every WHERE clause you care about."
- "Cassandra's consistency is tunable: W + R > N guarantees . + on RF=3 (2+2>3) is the most common production choice — with tolerance for one node failure."
- "Cassandra has no joins — you must denormalize. One query pattern = one table. If you need to look up the same data by both
user_idandemail, you have two tables: one partitioned by user_id, one by email." - "Giant partitions are a Cassandra anti-pattern — partitions larger than ~100MB cause slow and GC pauses. Bucket time-series data by time period (e.g.,
(user_id, year_month, timestamp)) to keep partition sizes bounded."
Common follow-up questions:
| Question | Concise Answer |
|---|---|
| "What is eventual consistency in Cassandra?" | With LOCAL_ONE consistency, a read may return data that's slightly stale (hasn't been replicated to all nodes yet). The data is eventually consistent — all replicas will converge. Strong consistency holds only when the read and write consistency levels together satisfy W + R > N (e.g. QUORUM writes + QUORUM reads on RF=3) — a QUORUM read alone does not guarantee it. |
| "What is a tombstone in Cassandra?" | A delete marker written to the LSM log. Until compaction, tombstones accumulate and are scanned on every read. Heavy deletes cause "tombstone buildup" — queries that scan millions of tombstones to find a few live rows. Severe performance impact. |
| "How does Cassandra handle node failure?" | Consistent hashing: when a node fails, its key ranges are served by adjacent nodes (replicas). With RF=3, the system tolerates one node failure. With LOCAL_QUORUM, the system tolerates a minority of nodes failing while still serving reads and writes. |
| "What is LWT (Lightweight Transaction) in Cassandra?" | Paxos-based compare-and-swap: IF NOT EXISTS or IF condition on writes. Used for conditional writes (e.g., "create user only if username doesn't exist"). Expensive (~4× latency of a normal write) and limited to single-partition — not real ACID. |
| "Cassandra vs. DynamoDB?" | Same philosophy (AP, wide-column), different deployment model. DynamoDB is fully managed (zero ops), AWS-only, pay-per-request. Cassandra is self-hosted (or DataStax Astra), any cloud, higher ops burden but more control. |
Connections to other building blocks:
- LSM Trees / : Cassandra's write path is a classic LSM implementation — CommitLog () + MemTable + SSTable . All write performance properties of LSM apply.
- : Cassandra distributes partitions using on the partition key. The token ring is a direct application of consistent hashing with VNodes.
- CAP Theorem: Cassandra is the canonical AP database example. With tunable consistency, it can behave as CP (ALL consistency) but at the cost of .
- : Cassandra's token ring is automatic horizontal . Each node owns a token range; data is sharded across all nodes without any application-layer routing.
- Message Queues: Cassandra is sometimes used as a queue backing store (but with limitations — Cassandra's tombstone problem makes it poorly suited for high-delete-rate queue patterns). is better for queuing.
Glossary History
Click dotted jargon to save explanations here.
Glossary History
Click dotted jargon to save explanations here.