Cassandra

A wide-column database that spreads data over a ring of equal nodes. How the write path and tunable consistency work, why you model tables around queries, and when to pick it.

On this page
  1. 01What it is and why it exists
  2. 02How it works, at the level you must explain
  3. 03When to use it, trade-offs, numbers
  4. Common mistakes
  5. Check yourself

Cassandra is an open-source database built for very high write volume and for staying up when machines fail. It has no leader node. That one choice explains most of how it behaves.

Crux: Cassandra gives you always-on writes at scale by being leaderless and append-only. You pay with query limits, and consistency that you tune yourself.

What it is and why it exists

Cassandra is a wide-column store. A table has a partition key and optional clustering columns. Rows with the same partition key sit together, sorted by the clustering columns. You query with CQL, which looks like SQL but has no joins and restricts what you can filter on.

It exists for workloads like time-series events, messages, activity feeds and sensor data: lots of writes, reads by key and range, and a need to survive a node or a data centre failing.

How it works, at the level you must explain

The ring and replication

Nodes sit on a hash ring. The partition key is hashed to a position, and the node that owns that position stores the row. Copies go to the next nodes around the ring. The number of copies is the replication factor (RF), commonly 3. Any node can take a request and acts as the coordinator, forwarding it to the replicas. There is no leader, so there is no single failure that stops writes.

ABCDEF key hash(key) picks a pointRF = 3: the next threenodes clockwise hold copies quorum = 2 of 3any node can coordinateno leader to lose replicas in warm: they hold the key
A key hashes to a spot on the ring. With RF 3, the next three nodes hold copies.

Write path: why writes are fast

A replica does three things on a write.

  • 1. Append to the commit log on disk, for durability. This is sequential and fast.
  • 2. Write to the memtable, an in-memory sorted structure.
  • 3. Later, flush the memtable to an immutable file on disk called an SSTable.

Nothing is updated in place. Background compaction merges SSTables and drops old versions. A read may have to check the memtable and several SSTables, helped by bloom filters that say "this file definitely does not have the key". That is why reads cost more than writes in Cassandra. Deletes write a marker called a tombstone, which lingers until compaction, and many tombstones slow reads down.

Tunable consistency

For each request you pick a consistency level: how many replicas must answer.

  • ONE: fastest, may read stale data.
  • QUORUM: a majority (with RF 3, two replicas).
  • ALL: every replica, so one down node fails the request.

The rule to remember: if reads + writes > RF, a read overlaps the latest write. With RF 3, quorum writes and quorum reads give that. Replicas that miss a write catch up through hinted handoff, read repair and background repair. The result is eventual consistency unless you pay for quorum, and it is still not a transaction system.

Modelling: tables follow queries

You design one table per query. Data is duplicated across tables on purpose, because there are no joins.

  • Choose a partition key that spreads load and keeps one query inside one partition.
  • Use clustering columns for the sort order within it.
  • Keep partitions bounded. A partition that grows without limit, such as all events for one device forever, gets slow. Add a time bucket (device and day) to cap it.
  • Writes to a partition are cheap. Updating a column in many tables is your job in the application.

A modelling walk-through

Take a fleet of delivery bikes sending a location every few seconds. The query is "the last hour of locations for bike 17". The table follows that query.

CREATE TABLE bike_locations (
  bike_id   text,
  day       date,
  ts        timestamp,
  lat       double,
  lon       double,
  PRIMARY KEY ((bike_id, day), ts)
) WITH CLUSTERING ORDER BY (ts DESC);
  • The partition key is (bike_id, day), in double brackets. One bike for one day is one partition, so the data cannot grow without limit and one query hits one partition.
  • ts is the clustering column, newest first, so "latest N" is a short sequential read.
  • A different question ("which bikes were near this point?") is a different table with a different key, loaded by the application or a stream job.

Keep an eye on partition size. A common rule of thumb is to stay far below a few hundred megabytes and a few hundred thousand rows per partition. That is a guide to verify, not a limit.

Routing, gossip and failure detection

  • Any node can be the coordinator. A smart driver knows the ring and sends each request straight to a replica (token-aware routing), saving a hop.
  • Each node owns many small slices of the ring (virtual nodes), so adding a machine takes a little from many nodes, and load stays even.
  • Nodes exchange state by gossip: every second or so each node tells a few random peers what it knows. The cluster learns who is up with no central registry. Failure detection is probabilistic (the phi accrual idea): a node is suspected when its heartbeats are late relative to its usual rhythm.
  • While a replica is down, other nodes keep hints for it and replay them when it returns. Long outages need a full repair.

Conflicts and what you do not get

Each write carries a timestamp, and when copies disagree the latest timestamp wins. Clocks matter, and two writers on one cell can lose an update. Writes are atomic per row (within a partition), with no multi-row or cross-partition transaction. There are lightweight transactions (compare-and-set through consensus) for rare "insert if not exists" needs, and they are slower.

Secondary indexes and views

A secondary index on a non-key column is stored per node, so a query without the partition key must ask many nodes. It suits columns with moderate cardinality and a partition key in the query. Materialized views automate a second table for another query, but I would check the current status in the documentation before relying on them. In most designs, you write the extra table yourself.

When to use it, trade-offs, numbers

  • What: a leaderless, wide-column, append-only database.
  • Use when: very high write throughput, time-ordered data, multi-region availability, and queries you know in advance.
  • Know: the ring, RF and quorum maths, commit log, memtable, SSTable, compaction, tombstones, and partition key design.
  • Careful: it is poor at ad hoc queries, joins, strong transactions and frequent deletes. It is also work to operate (repair, compaction tuning, capacity planning).

Cassandra or something else?

  • DynamoDB: a similar data model, run for you. Pick it on AWS when you want less operations. Cassandra gives more control and no lock-in.
  • PostgreSQL: pick it unless the write volume or availability need truly rules it out.
  • A log such as Kafka: pick it when the data is a stream to be consumed in order, not queried by key.

Numbers: RF 3 with quorum is the standard shape to quote. I am leaving out throughput claims per node, since they vary greatly with hardware and row size.

Common mistakes

  • Choosing it for "scale" when a single Postgres would do.
  • Modelling like a relational schema and expecting to filter on any column.
  • A partition key with low cardinality, or a partition that grows forever.
  • Quorum on writes but ONE on reads, then expecting fresh reads.
  • Heavy deletes or queue-like use, which produce tombstones.
  • Designing for a flexible query set. Cassandra wants the queries first.
  • Using secondary indexes as the main access path.
  • Updating one cell from many writers and relying on the clock to order them.

Check yourself

  • Why does having no leader help availability?
  • Walk through a Cassandra write. Why is it fast?
  • With RF 3, what read and write consistency levels guarantee you read the latest write?
  • What is a tombstone and why can it hurt?
  • How would you stop a partition growing without limit?
  • Give one reason to choose DynamoDB over Cassandra and one for the reverse.
  • Write the primary key for "latest 50 messages in a chat room" and explain each part.
  • How do nodes find out another node is down, with no central registry?
  • Which kinds of query would you refuse to support in Cassandra?