Courses › System Design › Key Technologies
Cassandra
Wide-column modeling, partition and clustering keys, tunable consistency.
Apache Cassandra is a distributed wide-column database designed for massive write throughput, linear horizontal scaling and high availability with no single point of failure. It's the classic answer for chat messages, activity feeds, IoT and time-series data — anywhere writes are huge and access patterns are known in advance.
Architecture
- Masterless — every node is equal. Any node can accept reads and writes and coordinate the request.
- Consistent hashing — data is distributed around a token ring using the partition key (see Consistent Hashing), with virtual nodes for balance.
- Replication — each partition is stored on
RFnodes (replication factor, commonly 3), across racks or datacenters. - Gossip — nodes share cluster membership and health via a gossip protocol.
- LSM-tree storage — writes go to a commit log and an in-memory memtable, flushed to immutable SSTables and compacted in the background. Writes are sequential and very fast.
Data modeling: query-first
Cassandra has no joins and limited secondary indexing, so you design one table per query. The primary key has two parts:
CREATE TABLE messages (
conversation_id uuid,
message_id timeuuid,
sender_id uuid,
body text,
PRIMARY KEY ((conversation_id), message_id)
) WITH CLUSTERING ORDER BY (message_id DESC);- Partition key (
conversation_id) — decides which nodes store the data. All rows with the same partition key live together. - Clustering key (
message_id) — sorts rows *within* a partition. Here, newest messages first, so "load the latest 50 messages" is a single sequential read.
[!WARNING] Unbounded partitions A partition that grows forever (every message ever in a busy group chat) becomes slow and hard to compact. Bucket it: PRIMARY KEY ((conversation_id, month), message_id). Aim to keep partitions well under ~100 MB.
Denormalization is normal: if you also need "messages by sender," that's a second table written alongside the first.
Tunable consistency
Each read and write chooses a consistency level:
If reads + writes > replication factor (e.g. QUORUM + QUORUM with RF=3), every read overlaps with the latest write, giving strong consistency for that data. Lower levels favor availability and latency.
Conflicts are resolved with last-write-wins by timestamp. Lightweight transactions (IF NOT EXISTS) provide compare-and-set using Paxos, but they're expensive — use them sparingly.
When to use Cassandra
- Very high write volume: messages, events, sensor readings, logs
- Time-ordered data read by key and time range
- Multi-region, always-on availability requirements
- Access patterns that are known and stable
When not to
- You need ad-hoc queries, joins or aggregations
- You need multi-row transactions (payments, inventory)
- Your scale fits comfortably in Postgres — Cassandra's operational complexity isn't free
[!INTERVIEW] What to say "Messages are write-heavy and always read by conversation in time order, so I'll use Cassandra with conversation_id (bucketed by month) as the partition key and a timeuuid clustering key descending. Writes at LOCAL_QUORUM, reads at LOCAL_QUORUM."