Cassandra
A fleet of devices sends readings continuously. The dashboard usually asks for one device's recent history, but the growing write volume and regional availability requirements are putting pressure on a single database server. Most requests have a predictable shape; they do not need arbitrary joins across the fleet.
Cassandra distributes partitions across a cluster and stores replicas on several nodes. Avinash Lakshman and Prashant Malik built it at Facebook for Inbox Search, releasing it as open source in 2008. It combined ideas from distributed systems such as Dynamo with a table model organized around the queries an application needed to serve.
That query-first approach matters more than CQL's resemblance to SQL. For the device dashboard, choose a device and day as the partition key, then order readings by observation time. A day bucket prevents one device's entire lifetime from accumulating in one partition.
Open cqlsh against a local Cassandra instance. The following keyspace assumes its data center is named datacenter1; substitute the cluster's actual data-center name. Replication factor 1 is for this single-node example:
CREATE KEYSPACE profile_telemetry
WITH replication = {
'class': 'NetworkTopologyStrategy',
'datacenter1': 1
};
USE profile_telemetry;
CREATE TABLE readings (
device_id TEXT,
day DATE,
observed_at TIMESTAMP,
reading_id TIMEUUID,
temperature DOUBLE,
PRIMARY KEY ((device_id, day), observed_at, reading_id)
) WITH CLUSTERING ORDER BY (observed_at DESC, reading_id DESC)
AND default_time_to_live = 604800;The inner parentheses identify the partition key. Observation time and reading ID are clustering columns, determining order inside that partition. The extra ID permits readings with identical timestamps. Bucket size still needs to match the workload: a very busy device might need smaller buckets.
Insert a reading and fetch the most recent observations in a time range:
INSERT INTO readings
(device_id, day, observed_at, reading_id, temperature)
VALUES
('sensor-42', '2026-11-01', '2026-11-01T10:00:00Z', now(), 22.4);
SELECT observed_at, reading_id, temperature
FROM readings
WHERE device_id = 'sensor-42'
AND day = '2026-11-01'
AND observed_at >= '2026-11-01T09:00:00Z'
LIMIT 50;This query names one partition and follows its clustering order. A fleet-wide temperature search would need a different access path or derived table. Adding ALLOW FILTERING is not a substitute for understanding how much data such a query must inspect.
For real ingestion retries, reuse a stable reading ID; now() here generates a new one on each insert. Repeating the full primary key updates the existing logical row, while a new ID creates another reading.
Writes enter a commit log and an in-memory table before being flushed into immutable SSTables. Compaction later merges those files. The table's seven-day TTL counts from the write, not from observed_at; backfilled readings therefore need a deliberate expiry policy. Expired data also leaves deletion information that compaction must eventually clear, which can affect storage and read costs.
Replication and consistency are separate choices. In a data center with three replicas, LOCAL_QUORUM requires responses from two local replicas. Waiting for more replicas changes both the guarantees and which failures a request can tolerate. A single-node demo cannot demonstrate that availability behavior.
Telemetry history, messaging records, and other high-volume feeds can fit this model when their reads follow known keys. The design work goes into partition sizes, duplication for different queries, and operating replication and repair.
Replication and partitioning connects those choices to the distributed-system behavior behind them.