Apache Cassandra

Apache Cassandra is the canonical wide-column / Dynamo-style distributed database. Originally developed at Facebook for Inbox Search, open-sourced in 2008, and now the storage layer behind Netflix, Apple, Discord, Instagram, and Uber. Cassandra is built for write-heavy, multi-region workloads where availability and linear scalability trump strong consistency.

Cassandra combines Amazon Dynamo's distribution design (consistent hashing, replication to neighbouring nodes, gossip, tunable consistency) with Google Bigtable's storage model (a log-structured merge tree of immutable SSTables). The result is a database that accepts writes on any node in any region and keeps serving when nodes or whole data centres fail, in exchange for a query model that must be designed around partition keys up front.

Ring architecture

A write at QUORUM with replication factor 3 Client driver, token-aware load balancing Coordinator any node; hashes partition key Replica 1 owns token range Replica 2 next node on ring Replica 3 next node (other rack) With RF=3 and QUORUM, the coordinator replies after 2 of 3 replicas acknowledge; the third catches up via hints or repair.

Each node owns ranges of the token space (with virtual nodes, many small ranges). The partition key is hashed with Murmur3 to a token, and the replication strategy places copies on the next nodes around the ring, spread across racks, and in each data centre with NetworkTopologyStrategy. Any node can coordinate any request. Nodes learn cluster membership and state through gossip, and missed writes are repaired by hinted handoff, read repair, and scheduled anti-entropy repair.

Key Features:

Data Model:

A Cassandra table is keyed by a partition key (which determines which node owns the data) plus optional clustering columns (which determine sort order within the partition). The right partition-key choice is the single most important design decision — bad keys produce hot partitions or cross-partition scans, both of which are pathological in Cassandra.

Use Cases:

Cassandra vs. Other NoSQL:

Write path and storage

LSM-tree write path on a single replica Commit log sequential append for durability Memtable sorted in memory per table Flush memtable written as SSTable SSTables immutable files + bloom filters Compaction merge, drop tombstones Writes never read before writing, which is why they are cheap; reads may consult several SSTables and merge.

A write is acknowledged once it is in the commit log and memtable, so write latency is low and nearly constant. Updates and deletes are just newer cells (deletes are tombstones), resolved at read time by timestamp. Bloom filters let reads skip SSTables that cannot contain the partition, and compaction strategies (size-tiered, leveled, time-window) trade write amplification against read performance; time-window compaction suits time-series tables with TTLs.

Worked example: query-first table design

In Cassandra you design one table per query. For "latest readings for a sensor on a given day", partition by sensor and day so partitions stay bounded, and cluster by time descending:

CREATE KEYSPACE iot WITH replication =
  {'class': 'NetworkTopologyStrategy', 'dc1': 3, 'dc2': 3};

CREATE TABLE iot.readings_by_sensor_day (
    sensor_id  text,
    day        date,
    ts         timestamp,
    temp_c     double,
    humidity   double,
    PRIMARY KEY ((sensor_id, day), ts)
) WITH CLUSTERING ORDER BY (ts DESC)
  AND default_time_to_live = 7776000          -- 90 days
  AND compaction = {'class': 'TimeWindowCompactionStrategy',
                    'compaction_window_unit': 'DAYS', 'compaction_window_size': 1};

INSERT INTO iot.readings_by_sensor_day (sensor_id, day, ts, temp_c, humidity)
VALUES ('s-17', '2025-06-01', '2025-06-01 12:00:00', 21.4, 0.48);

-- Efficient: one partition, already sorted
SELECT ts, temp_c FROM iot.readings_by_sensor_day
WHERE sensor_id = 's-17' AND day = '2025-06-01' LIMIT 10;

-- Rejected without ALLOW FILTERING: no partition key, would scan the cluster
-- SELECT * FROM iot.readings_by_sensor_day WHERE temp_c > 30;

If another query needs "all sensors above a threshold", create a second table keyed for that access pattern and write to both, often with a logged batch. Denormalization is the normal cost of Cassandra's predictable performance.

Choosing consistency levels

LevelReplicas that must answer (RF=3)Use when
ONE1Lowest latency; stale reads acceptable (metrics, logs)
LOCAL_QUORUM2 in the local DCDefault for most apps; consistent within a region
QUORUM2 of all replicas (across DCs: majority of total)Cross-region consistency, higher latency
ALL3Rarely; any node down fails the request

Reads and writes are strongly consistent when the replicas read plus the replicas written exceed the replication factor, for example LOCAL_QUORUM for both with RF=3 in one data centre. Lightweight transactions (IF NOT EXISTS) use Paxos for compare-and-set at a significant latency cost.

Pitfalls