Databases

Backend · Databases

Cassandra: Architecture & Use Cases

No master, no single point of failure — how Cassandra's ring, LSM-tree write path, and tunable consistency add up to a database built for write-heavy, always-on workloads.

9 min read
CassandraNoSQLDistributed Systems

Most databases people learn on have a shape: one primary that owns writes, a handful of replicas that trail behind it, and a single point where things go wrong if that primary disappears. Cassandra throws that shape out entirely. Every node is a peer, every node can take a read or a write, and there is no election, no failover window, and no node whose loss takes the cluster down. That design isn't free — you give up some of the convenience of a relational model — but for the workloads it targets, the trade is a good one.

A ring, not a hierarchy

Cassandra arranges every node in a cluster into a logical ring using consistent hashing. Each node owns a range of the hash space, and data is placed by hashing its partition key into that same space and walking clockwise to the first node responsible for it. There is no coordinator node that all traffic must pass through and no master that assigns work — any node can accept a request from a client, figure out which nodes in the ring actually own that data, and forward the request to them. That node is acting as a temporary coordinator for the one request, nothing more; the next request might pick a different coordinator entirely.

This is what lets Cassandra survive losing machines without anyone noticing an outage window. If a node goes down, its neighbors on the ring already hold replicas of its data, so reads and writes for that range keep succeeding. There's nothing to promote, nothing to fail over — the ring simply routes around the gap until the node comes back or is replaced.

Partitioning, replication, and vnodes

Where a row lands is entirely determined by its partition key. Cassandra hashes the partition key, and that hash — not the data's size, access frequency, or anything else — decides which node owns it. Everything sharing a partition key lives together on the same replicas, which is why schema design in Cassandra starts from "what will I query by?" rather than from normalized entity modeling.

Durability comes from the replication factor (RF): a keyspace configured with RF=3 stores every partition on three distinct nodes, chosen by walking forward around the ring from the partition's primary owner. Rather than assigning one large contiguous range per physical node, modern Cassandra gives each node a large number of small, randomly distributed ranges called virtual nodes (vnodes). Vnodes spread each node's data across many small slices of the ring instead of one block, which keeps load even as machines are added or removed and lets a newly-joined node absorb data from many existing peers in parallel rather than streaming from just one or two neighbors.

Tunable consistency

Because every partition has multiple replicas, Cassandra has to decide how many of them need to agree before a read or write counts as successful — and unlike most databases, it lets the client decide this on a per-request basis rather than baking one answer into the whole system.

  • ONE — only a single replica needs to acknowledge. Fastest, but a replica that hasn't caught up yet can serve stale data.
  • QUORUM — a majority of replicas (⌊RF/2⌋ + 1) must agree. With RF=3 that's 2 of 3. Reading at QUORUM after writing at QUORUM guarantees you see your own write, because the two sets of replicas are mathematically guaranteed to overlap.
  • ALL — every replica must acknowledge. Strongest guarantee, but availability drops to zero the moment a single replica is unreachable.

This is the essence of "tunable consistency": a dashboard query that can tolerate a few seconds of staleness reads at ONE for speed, while a financial balance check reads at QUORUM for correctness — in the same cluster, against the same tables, decided request by request.

sql
-- Per-request tunable consistency
CONSISTENCY QUORUM;

SELECT * FROM sensor_events
WHERE device_id = 'sensor-4471'
  AND event_time > '2026-08-01';

-- A write that only needs to be fast and durable,
-- not immediately visible everywhere
CONSISTENCY ONE;
INSERT INTO sensor_events (device_id, event_time, reading)
VALUES ('sensor-4471', toTimestamp(now()), 21.6);

The write path: why writes are cheap

Cassandra's write performance comes from never doing a read-before-write and never updating data in place. A write is appended to an on-disk commit log for durability, then inserted into an in-memory, sorted structure called a memtable. As far as the client is concerned, the write is done at that point — no seek, no lock contention on existing rows, no index maintenance mid-write.

When a memtable fills up, it's flushed to disk as an immutable file called an SSTable (sorted string table). Over time a node accumulates many SSTables, and a background process called compaction merges them, discarding overwritten and deleted values and folding duplicate keys into a single current value. This is a classic LSM-tree (log-structured merge-tree) design: writes are always sequential appends, never random-access rewrites, which is exactly the access pattern spinning disks and SSDs are best at. The cost of that speed is paid later, asynchronously, by compaction rather than up front by the write itself.

Tombstones and wide partitions

Two operational traps follow directly from this design. Deletes don't remove data immediately — they write a tombstone marker that has to be read past and is only physically removed once compaction runs and gc_grace_seconds passes. A workload that deletes heavily (e.g. a queue-like table) can silently accumulate enough tombstones to make simple reads scan thousands of dead rows. Separately, a partition key with low cardinality — say, one key per day for a high-volume sensor feed — concentrates unbounded data onto one partition and therefore one set of replicas, creating a hotspot that no amount of adding nodes elsewhere in the ring will relieve. Both are schema-design mistakes that only show up under production load, so partition key and delete patterns deserve real scrutiny before launch.

Where Cassandra shines

Cassandra is the right tool when the workload is write-heavy, latency-sensitive, and needs to survive infrastructure failure without downtime. Its sweet spots share a few traits:

  • Very high write throughput — the commit-log + memtable path lets a modest cluster absorb enormous sustained write volume, since writes never block on disk seeks or read-modify-write cycles.
  • Multi-region, active-active deployments — because there's no single master, nodes in different data centers or cloud regions can all accept writes simultaneously, with replication happening peer-to-peer instead of through one region.
  • No single point of failure — losing a rack, a data center, or several nodes at once is a normal, survivable event rather than an incident.
  • Time-series and event data — telemetry, IoT readings, clickstreams, and audit logs fit Cassandra's model naturally: a well-chosen partition key (device, user, or session plus a time bucket) groups related events together and appends new ones cheaply forever.

Where it's the wrong choice

Cassandra's strengths are mirror images of things it deliberately doesn't do well. There are no joins, so any "query across entities" that a relational database answers with a single statement instead requires denormalizing the data into multiple purpose-built tables ahead of time, or handling the join in the application layer. Ad-hoc, exploratory queries — "show me all orders where any of these five loosely related conditions hold" — fight the model, because every table is designed around one or two known access patterns, not arbitrary filtering.

Cassandra also has no cross-row or cross-partition transactions in the ACID sense. Lightweight transactions (using Paxos) exist for narrow compare-and-set cases on a single partition, but they are expensive and not a substitute for the multi-row, multi-table guarantees a relational database gives you for free — so workloads like ledger transfers or inventory reservations that require strict cross-row consistency belong elsewhere. Finally, secondary indexes on low-cardinality columns are a known anti-pattern: because the index itself is distributed across the cluster, a query against a low-cardinality secondary index tends to fan out to most or all nodes rather than narrowing to a few, giving you the latency profile of a full scan while looking like an indexed lookup.

Key takeaways

  • Cassandra has no master or coordinator — every node is a peer on a consistent-hashing ring, so losing a node never causes an outage window.
  • Partition key placement plus replication factor and vnodes determine both data locality and how evenly load spreads across the cluster.
  • Consistency level (ONE, QUORUM, ALL) is chosen per request, letting clients trade latency for correctness call by call rather than cluster-wide.
  • The commit-log → memtable → SSTable → compaction write path is an LSM-tree: writes are cheap sequential appends, and cleanup is deferred to background compaction.
  • It excels at high-throughput, multi-region, always-on time-series and event workloads — and struggles with joins, ad-hoc queries, and strong cross-row transactions.
  • Bad partition key choices and heavy delete patterns (hotspots and tombstones) are the most common ways Cassandra clusters get into trouble in production.
2026 — Built by Arpit Mishra