Cassandra & DynamoDB
0-day streakReview

Your progress

Level 1

0 XP100 XP to level 2
0day streak
0best streak
0topics started
0cards reviewed
    Review cards

    Progress is stored only in this browser. No account is required.

    Layer 4 · Full breakdown · 20 min · 5 figures

    Cassandra and DynamoDB

    What an interviewer expects you to know about Cassandra and DynamoDB: the Dynamo lineage and why DynamoDB is not leaderless, partition and clustering keys, tunable consistency, tombstones, LWT and transactions, partition limits, and when to pick each.

    Apache Cassandra and Amazon DynamoDB are the partitioned NoSQL stores you will name most often in a design interview. Both hash a partition key to spread data across machines, keep the rows of a partition sorted by a second key, and serve single-key reads in milliseconds at almost any scale. Cassandra is open source, leaderless and run by you; DynamoDB is a managed AWS service in which every partition has an elected leader. The bar is to model data around the queries, state the guarantees precisely and say where each one breaks.

    This page tracks Apache Cassandra 5.0 (5.0.9, August 2026, is the current release; 6.0 is in alpha) and the DynamoDB Developer Guide as of October 2026.

    Picture it first: a distributor’s shop ledgers

    A Pune distributor supplies 2,000 kirana shops and keeps one ledger per shop, entries in date order, so “shop 417’s last 20 orders” is the last page of one ledger. To answer “which shops bought Parle-G this week?” his clerks keep a second set, one ledger per product, and write every order twice.

    He can run the records himself. Each ledger is copied in three branches; any clerk takes an entry, phones the others and says “done” once two have it. A closed branch gets a slip to copy later, the later wall-clock time wins when copies disagree, and on Sundays the branches compare pages. Or he can hire a records company: a front desk finds the vault for shop 417, one head clerk writes each entry and says “done” once a deputy in another building has it, overgrown ledgers are split, and he pays per entry.

    Map it back: the ledger is a partition, the shop number the partition key, date order the clustering (sort) key, the product ledgers a denormalised table or GSI. Running it himself is Cassandra: three copies is replication factor 3, “two confirm” is QUORUM, the slip is hinted handoff, the wall clock is last-write-wins, the Sunday check is repair. The company is DynamoDB: the front desk is the request router, the head clerk the Paxos leader, the buildings availability zones.

    One name, two designs

    The 2007 Dynamo paper described Amazon’s shopping-cart store, where “add to cart” must never fail: consistent hashing with virtual nodes, sloppy quorums with hinted handoff, vector clocks merged on read, Merkle-tree anti-entropy and gossip. A merged cart could resurrect a deleted item; Amazon accepted that rather than lose an add.

    Cassandra (Lakshman and Malik, Facebook, 2009) combined Dynamo’s distribution with Bigtable’s data model to run Inbox Search: 50+ TB on 150 nodes. It dropped vector clocks, which need a read before each write; every cell carries a timestamp, and the highest wins.

    DynamoDB, launched in 2012, “shared most of the name of the previous Dynamo system but little of its architecture”, says its 2022 USENIX ATC paper. Each partition is a three-replica Multi-Paxos group spread over availability zones. The leader takes every write and strongly consistent read, and acknowledges a write once two of the three replicas have persisted its log record.

    Dynamo (2007 paper) Apache Cassandra Amazon DynamoDB
    Who runs it Each Amazon team You, or a vendor AWS, serverless
    Placement Consistent hashing, virtual nodes Token ring, 16 vnodes per node Key ranges in a metadata service
    Replication Leaderless, N replicas Leaderless, RF per data centre One Paxos leader per partition, three AZs
    A write succeeds when W nodes reply; stand-ins count The consistency level is met Two of three replicas have the log record
    Conflicts Vector clocks; the app merges Last write wins per cell None in a Region: the leader orders writes
    Data model Opaque value per key Partition key plus clustering columns Partition key plus sort key
    Storage engine Pluggable, mostly Berkeley DB LSM: commit log, memtable, SSTables Write-ahead log plus B-tree
    One paper, two descendants. Cassandra kept Dynamo’s leaderless replication; DynamoDB kept the partitioning and replaced the replication.

    In the interview

    Say it before you are asked: “DynamoDB is not leaderless. Each partition has a Paxos leader, so a strongly consistent read is just ConsistentRead: true. Cassandra, ScyllaDB and Riak are the leaderless ones, where freshness comes from quorum arithmetic.” Mixing the two up is the most common slip on this topic.

    Data model

    Cassandra: partitions of sorted rows

    A keyspace holds replication settings and tables. The primary key has two parts: the partition key, hashed to a token that picks the replicas, and clustering columns, which sort rows inside the partition. Rows of a partition sit together in clustering order, so “the 50 newest messages in this channel” is one sequential read.

    CREATE KEYSPACE chat WITH replication =
      {'class': 'NetworkTopologyStrategy', 'mumbai': 3, 'singapore': 3};
    
    CREATE TABLE chat.messages_by_channel (
      channel_id bigint,
      bucket     int,        -- hour number: unix_seconds / 3600
      message_id bigint,     -- time-sortable, Snowflake-style
      author_id  bigint,
      body       text,
      PRIMARY KEY ((channel_id, bucket), message_id)
    ) WITH CLUSTERING ORDER BY (message_id DESC);
    
    SELECT author_id, body FROM chat.messages_by_channel
     WHERE channel_id = 42 AND bucket = 498091 LIMIT 50;

    CQL looks like SQL but isn’t. A query must name the whole partition key, ranges apply only to clustering columns in order, and there are no joins. Anything else needs an index or ALLOW FILTERING, which scans. So modelling is query-first: one table per access pattern, each fact written to every table that needs it (data modelling and denormalisation).

    DynamoDB: items, item collections and indexes

    A table holds items of up to 400 KB, with no schema beyond the key: a partition key, optionally plus a sort key. Items sharing a partition key form an item collection, ordered by sort key. Query takes one partition key plus a sort-key condition (=, BETWEEN, begins_with…) and returns at most 1 MB per page, measured before filters; Scan reads everything.

    • A global secondary index (GSI) has its own keys, partitions and throughput. It is updated asynchronously, so its reads are always eventually consistent. Add one any time; the default quota is 20 per table.
    • A local secondary index (LSI) keeps the partition key with a different sort key and allows strong reads, but is created only with the table, at most 5, and caps each item collection at 10 GB.

    Single-table design stores several entity types under generic keys (PK = USER#42, SK = ORDER#2026-10-27#981), so one Query returns a user and their recent orders: a pre-computed join, paid for in readability and migrations.

    {
      "TableName": "app",
      "KeyConditionExpression": "PK = :pk AND begins_with(SK, :prefix)",
      "ExpressionAttributeValues": { ":pk": { "S": "USER#42" }, ":prefix": { "S": "ORDER#" } },
      "ScanIndexForward": false,
      "Limit": 20
    }
    The same idea in both stores. In Cassandra a partition is a run of rows sorted by clustering column; in DynamoDB an item collection is a run of items sorted by sort key, and a GSI re-keys a copy of them.Notice Each query is answered by reading one partition, and that a new access path means a new copy of the data (a second table or a GSI), not a new WHERE clause.

    Guarantees, precisely

    Cassandra: consistency is chosen per request

    A Cassandra write goes to every replica; the consistency level only sets how many acknowledgements the coordinator waits for. A read asks enough replicas to meet its level and keeps the newest timestamp. With replication factor (RF) 3 per data centre:

    Level Waits for Survives Typical use
    ONE, LOCAL_ONE 1 replica 2 replicas down Feeds, metrics, logs
    QUORUM A majority of all replicas, across data centres 1 down in a single DC Read-your-writes, one region
    LOCAL_QUORUM 2 of 3 in the local data centre A remote region down The multi-region default
    EACH_QUORUM 2 of 3 in every data centre 1 per DC, not a whole region Must be durable everywhere first

    If R + W > RF, read and write sets overlap: QUORUM plus QUORUM is 2 + 2 = 4 > 3, while ONE plus ONE is 2 and can miss a fresh write. Overlap is still not linearizability; quorums and leaderless replication lists the cases where a quorum read goes stale, and CAP and PACELC explains why the label belongs to the consistency level, not the product.

    Where a Cassandra write goes. Left: four nodes own two tokens each; the key’s replicas are the next three distinct nodes clockwise. Right: a QUORUM write while replica B is down.Notice The client gets OK from two acknowledgements, and that the coordinator’s hint helps B catch up but never counts towards QUORUM.

    How replicas converge

    • Hinted handoff: the coordinator replays missed writes to a replica that was down less than max_hint_window, 3 hours by default.
    • Read repair: when replicas disagree on a read above ONE, the newest value is written back before the answer.
    • Anti-entropy repair: nodetool repair compares Merkle trees per token range and streams only what differs. Operators must schedule it.

    Deletes and expired TTLs write tombstones, which compaction may purge after gc_grace_seconds, 864,000 s (10 days) by default. Repair every node within that window, or a replica that missed the delete hands the old value back as a zombie.

    Last write wins, LWT and batches

    Conflicts resolve per cell by timestamp, from the client or coordinator clock. Two writes to one cell at once: one silently vanishes. A server with a fast clock: its older writes beat newer ones. Keep NTP tight and prefer new rows to overwrites (clocks and conflict resolution).

    For check-then-set there are lightweight transactions: INSERT … IF NOT EXISTS or UPDATE … IF balance = 500 runs Paxos among the partition’s replicas and is linearizable for that partition. Paxos v1, still the default in cassandra.yaml, costs 4 round trips per write and 3 per read; v2 (4.1+, the default in 5.0’s cassandra_latest.yaml) costs 2 per write and 1–2 per read. Don’t mix LWT and plain writes on the same cells.

    A logged batch makes writes across partitions and tables all-or-nothing eventually, but isolated only within one partition. General ACID transactions (Accord) headline Cassandra 6.0, still in alpha (alpha2, August 2026), so don’t design around them yet. And the commit log syncs to disk only every 10 seconds by default; replication, not fsync, protects a fresh write.

    DynamoDB: a leader per partition

    • Writes go to the leader and are acknowledged once two of three replicas have the log record.
    • Reads are eventually consistent by default (any replica, half price); ConsistentRead: true goes to the leader. GSIs and streams offer only eventual reads.
    • Conditional writes evaluate on the leader, so “create if absent” or “update if version = 7” need no lock.
    • Transactions cover up to 100 items and 4 MB in one Region, are serializable against single-item reads and writes, and cost two units per item; a client token makes retries idempotent for 10 minutes (ACID vs BASE).
    • Global tables, MREC (default): every Region takes writes and replicates asynchronously, typically within a second, last writer wins per item; transactions are atomic only in their own Region.
    • Global tables, MRSC (generally available since 30 June 2025): exactly three Regions; a write reaches a second Region before it returns, so strong reads anywhere are current and a Region loss loses nothing acknowledged. Concurrent writes to one item fail with ReplicatedWriteConflictException, and you give up TTL, LSIs and transactions.
    • Recovery: point-in-time restore covers 35 days; Streams keep 24 hours of item changes, in order per item, for change data capture.

    “Strongly consistent” never applies to a GSI

    You add a GSI for “orders by status”, read it right after an update, and get the old status. GSI writes are asynchronous and ConsistentRead is not supported on them. If a read must see the write, read the base table by key, or use an LSI and accept its 10 GB cap.

    How it scales

    Cassandra: a ring of peers

    Murmur3 hashes the partition key to a token, and each node owns several ring positions: num_tokens is 16 since 4.0 (256 in 3.x). More tokens spread a joining node’s streaming over more peers but give each node more neighbours, so more failure pairs make some range unavailable; the docs suggest 4 for clusters heading past 30 nodes. NetworkTopologyStrategy sets RF per data centre and spreads replicas over racks (map racks to zones). Nodes gossip every second and join or leave only by operator action; a new node takes token ranges and streams their data, so capacity grows roughly linearly.

    The engine is an LSM tree: commit log plus memtable, flushed to immutable SSTables, each with a Bloom filter. Reads merge the memtable and every SSTable that might hold the partition, which is why Cassandra reads cost more than writes. Compaction merges files in the background:

    • STCS (size-tiered), the cassandra.yaml default: cheap writes, more files per read.
    • LCS (leveled): read-heavy or update-heavy tables, more write I/O.
    • TWCS (time window): TTL’d time series; an expired window drops as one file.
    • UCS (unified, 5.0): recommended for new tables.
    The Cassandra write path, a read that merges by timestamp, and compaction. Message m_1046 was edited (v2 at timestamp 105) and m_1045 was deleted (a tombstone at 110 still in the memtable).Notice The read touches the memtable and two files and lets the newest timestamp win cell by cell, while the Bloom filter saves a disk read on the oldest file.

    Cassandra 5.0 (September 2024) added storage-attached indexes (SAI), trie memtables and SSTables, UCS and a vector type. Most are opt-in: cassandra.yaml keeps 4.x-compatible defaults, while cassandra_latest.yaml switches them on.

    DynamoDB: routers, partitions and admission control

    The ATC paper describes request routers that authenticate each call and find its replication group in a metadata service; storage nodes hosting thousands of replicas, each a write-ahead log plus a B-tree; and autoadmin, which replaces bad replicas and splits partitions.

    A partition holds at most 10 GB and serves at most 3,000 read units and 1,000 write units per second (burst and adaptive capacity): a read unit is one strong read of 4 KB or two eventual ones, a write unit one 1 KB write. Partitions split for size and for heat, usually within minutes, but a single hot item or sequential keys cannot be split away. Burst capacity banks up to 300 seconds of unused throughput, and adaptive capacity shifts throughput to hot partitions, up to the partition maximum.

    Provisioned mode reserves units per second and suits steady load. On-demand bills per request: a new table sustains 4,000 writes and 12,000 reads per second and absorbs double its previous peak instantly, but can throttle if traffic more than doubles within 30 minutes.

    DynamoDB’s request path, after the 2022 USENIX ATC paper. Each partition is a three-replica Paxos group spread over three availability zones; a partition that grows past 10 GB or runs hot is split.Notice Writes and strong reads always reach the leader, while an eventually consistent read may land on any replica, which is why it costs half and may be stale.

    The arithmetic interviewers like: 30,000 one-kilobyte writes per second needs at least 30,000 ÷ 1,000 = 30 partitions’ worth of capacity, which DynamoDB will create if keys spread evenly. One key taking 1,500 writes per second throttles however big the table is.

    Limits and numbers

    DynamoDB figures are default quotas from the Developer Guide (October 2026); Cassandra defaults are from the 5.0 configuration reference.

    What Number Notes
    DynamoDB item 400 KB Put blobs in object storage, keep a pointer
    Query or Scan page 1 MB, before filters Filters don’t cut the read units you pay
    Per partition 3,000 RCU, 1,000 WCU; 10 GB Splits are automatic
    Capacity units RCU: 4 KB strong or 2 × eventual; WCU: 1 KB Transactions cost 2×
    Transactions 100 items, 4 MB, one Region
    Secondary indexes 20 GSIs (default), 5 LSIs LSI: 10 GB per item collection
    New on-demand table 4,000 writes/s, 12,000 reads/s Then up to 2× previous peak
    Latency and scale Low single-digit ms for 1 KB items; 89.2 million requests/s at Prime Day 2021 peak ATC 2022 paper
    Cassandra replication RF 3 per data centre QUORUM = 2 of 3
    num_tokens 16 since 4.0 256 in 3.x
    Hint window 3 hours Then only repair catches up
    gc_grace_seconds 864,000 s (10 days) Repair within it
    Tombstones per read Warn 1,000, fail 100,000
    Partition size 2 billion cells hard limit; aim under ~100 MB 4.x warned at 100 MiB in compaction
    LWT round trips v1: 4 write, 3 read; v2: 2 and 1–2 v2 since 4.1

    The 100 MB figure is a rule of thumb: at about 1 KB per row it is roughly 100,000 rows, where compaction, repair and reads of one partition start to load one node.

    When to pick it, and when not

    Cassandra DynamoDB ScyllaDB PostgreSQL
    Model Wide-column, CQL Items: partition and sort keys Cassandra’s CQL, plus a DynamoDB-compatible API Relational, SQL, joins
    Replication Leaderless, last write wins Paxos leader per partition Leaderless One primary, replicas
    Consistency Per request; LWT Eventual or strong reads; transactions Per request Serializable on the primary
    Multi-region writes Built in (LOCAL_QUORUM) Global tables: MREC or MRSC Built in Usually one writer region
    Operations Nodes, repair, compaction, JVM Keys and capacity mode only Like Cassandra; C++, shard per core, no GC Vacuum, failover, or managed
    Cost model Servers you size Per request or per provisioned unit Servers, often fewer Instances you size
    Pick it for Huge write-heavy data, many regions, any cloud AWS, spiky load, zero ops Cassandra workloads needing lower tail latency Relational data, transactions, ad-hoc queries
    Cassandra and DynamoDB against the usual alternatives. Rows depend on configuration; the last row is the honest reason to choose each.

    Pick Cassandra or DynamoDB when writes are heavy and keep coming (messages, events, readings, timelines), every read names a key, and the data outgrows one machine. DynamoDB if you are on AWS and would rather pay per request than run a cluster; Cassandra or ScyllaDB for many regions, other clouds or large steady volumes.

    Pick something else when you need joins, ad-hoc filters or multi-row invariants (PostgreSQL); the queries aren’t known yet; you need full-text search (feed an index by CDC); it is a cache or counter at memory speed (Redis); or it is a queue, because consumed-row deletes become tombstones (Kafka). For small data, one PostgreSQL primary is simpler; see databases for system design interviews.

    Common interview usage

    Design problem Role Key The follow-up to expect
    WhatsApp, Slack/Discord Message history (channel_id, bucket), message_id DESC A busy channel: hot and oversized partitions
    News feed Precomputed timeline per user user_id, post time; TTL Celebrities: fan-out on read instead
    Metrics, IoT Time-series points (sensor_id, day), timestamp; TWCS Late, out-of-order writes break TWCS windows
    Activity or audit log Append-only history (user_id, month), event time “By event type?” A second table or SAI
    Checkout and cart Cart, Dynamo’s original job PK = user_id, SK = product_id Two devices editing: per-item rows or conditional writes
    Sessions, idempotency keys Key-value with expiry Request ID; TTL attribute DynamoDB TTL deletes within days: filter expired items
    URL shortener Code → URL lookup Short code Unique custom alias: attribute_not_exists or IF NOT EXISTS

    Worked example: chat history and time buckets

    Partitioning messages by channel_id alone gives one partition per channel that grows forever. Discord partitioned by channel plus a static time bucket, and its 2023 post shows the pressure at scale: 177 Cassandra nodes holding trillions of messages, hot partitions whose latency spread to every query on those nodes because reads and writes used QUORUM, and compaction backlogs. Moving to 72 ScyllaDB nodes with request coalescing in front cut p99 for historical reads from 40–125 ms to 15 ms.

    Size the bucket. At 500 bytes per message, a busy channel at 20 messages per second writes 20 × 86,400 ≈ 1.7 million messages, 864 MB per day; a family group at 200 a day writes 100 KB.

    Partition size for one bucket of a busy channel and a quiet group under four bucket choices, at 500 bytes per message, on a log scale. The dashed line is the 100 MB rule of thumb.Notice No single window suits both: a busy channel needs hourly buckets to stay under 100 MB, while hourly buckets would scatter a quiet group’s 200 daily messages across 24 partitions.
    • No bucket: the busy channel reaches 864 MB × 365 ≈ 315 GB in a year, on three nodes.
    • One fixed window fails one side: ten days puts 8.6 GB in each busy bucket, one hour splits a quiet day across 24 tiny partitions.
    • A window per channel, stored on the channel row: an hour for busy channels (72,000 × 500 B = 36 MB), ten days for quiet ones (2,000 × 500 B = 1 MB).

    In DynamoDB the model is PK = CH#42#<bucket>, SK = message_id. A cricket-final channel at 5,000 one-kilobyte messages per second is five times one partition’s write limit, so the hot bucket must also be salted across at least 5 keys.

    Going deeper: failure modes

    Hot partitions

    Each key lives on one replica set: three Cassandra nodes, or one DynamoDB leader. A viral post or one giant merchant in a UPI-style ledger saturates it while the cluster idles, and adaptive capacity stops at the partition maximum. Fixes, each with a price: salt the key (post_42#0…#7) and merge on read; cache hot reads (hot keys); coalesce identical concurrent reads, as Discord did.

    Partitions that never stop growing

    A partition key with no time component (user_id for an activity log) grows forever on the same nodes, slowing compaction, repair and streaming. Bucket by time, and do the arithmetic for your worst key, not the average.

    Tombstone storms

    Cassandra as a queue (insert, read the oldest, delete) fills the partition head with tombstones that every read scans for at least 10 days. Past 1,000 in one read Cassandra warns; at 100,000 it aborts. Use a real queue; for expiring data, TTL whole partitions under TWCS so entire files drop.

    Read-before-write and LWT contention

    “Read, add one, write back” loses updates under last write wins: write new rows, use counters or a conditional write. LWT serialises through Paxos, so one hot key under LWT, such as a ticket sale’s seat map, queues and times out. Keep LWT for rare claims: usernames, seat holds, idempotency keys.

    Indexes that scatter or push back

    Cassandra indexes are local to each node, so a query without the partition key fans out to every token range. SAI is more efficient than the legacy index (still the 5.0 default for CREATE INDEX) but has the same shape; for a hot path, write a second table. In DynamoDB, a GSI short of write capacity throttles the base table’s writes, so a lagging “orders by status” index can stall checkout. And Scan charges for every item it reads, filter or not.

    Clock skew and zombies

    A client or node with a fast clock silently wins every conflict, and a timestamp in the future makes a row immune to updates. A replica that misses a delete and isn’t repaired within gc_grace_seconds resurrects the row. Both fail silently: alert on clock drift and repair age.

    Five questions before you write a table

    What are the queries? What is each partition key, and is any value hot? How big is one partition after a year? What consistency does each query need? What deletes or expires, and how? Answer them aloud with numbers and the schema is usually right.

    Cheat sheet

    Concept Remember it as
    Lineage Dynamo (leaderless) → Cassandra (plus Bigtable’s model); DynamoDB shares the name, not the design
    Keys Partition key picks machines; clustering or sort key orders the partition
    Modelling Query-first: one table or GSI per access pattern, no joins
    Cassandra consistency Per request; R + W > RF overlaps; LOCAL_QUORUM across regions
    Convergence Hints (3 h), read repair, Merkle-tree repair within 10 days
    Conflicts Cassandra: last write wins per cell; DynamoDB: the leader orders; MREC: last writer wins per item
    Check-then-set LWT (Paxos, 4 or 2 round trips); DynamoDB conditional writes
    DynamoDB Eventual reads half price; transactions 100 items, 2× cost; MRSC for zero-RPO multi-Region
    Limits 400 KB item, 1 MB page; 10 GB, 3,000 RCU, 1,000 WCU per partition
    Indexes GSI: async, own capacity, can throttle writes; LSI: at creation, 10 GB cap
    Partition size Bucket by time; under ~100 MB
    Traps Hot keys, unbounded partitions, queue-like deletes, scatter-gather indexes, clock skew

    How to say it in the interview

    “For message history I’d use Cassandra, or DynamoDB if we’re on AWS. The table is keyed by (channel_id, bucket) with message_id descending, so the latest 50 messages are one partition read. Buckets are an hour for busy channels and ten days for quiet ones, keeping partitions under about 100 MB. Replication factor 3 per region, reads and writes at LOCAL_QUORUM, so users see their own messages without a cross-region round trip. Search gets a change stream instead of indexes on the hot table, and the one check-then-set, claiming a username, uses a lightweight transaction.”

    Is DynamoDB leaderless like Dynamo? No. Each partition is a three-replica Multi-Paxos group; the leader takes writes and strong reads and acknowledges at two of three. Eventually consistent reads can hit any replica, which is why they cost half and can be stale.

    How do you stop two people claiming the same username or seat? Compare-and-set on one key: INSERT … IF NOT EXISTS in Cassandra, or PutItem with attribute_not_exists(PK) in DynamoDB. A quorum read then a write isn’t enough: both clients can read “free”.

    A channel’s partition is hot or huge. What now? For size, add a time bucket to the partition key. For heat, salt the key and merge on read, cache and coalesce in front, and check DynamoDB’s 1,000 writes per second per partition with arithmetic.

    Why are deletes dangerous in Cassandra? Each delete is a tombstone that reads must skip for at least 10 days. Queue-like deletes pile them up until reads warn or fail, and a replica that misses a delete and isn’t repaired in time brings the data back.

    Why not just PostgreSQL? Until one primary can’t take the writes, PostgreSQL is simpler and gives joins and transactions. Choose Cassandra or DynamoDB when the queries are known, writes outgrow one machine, and multi-region or managed scale-out matters more than ad-hoc queries.

    Where to go next

    References and further reading

    1. Dynamo: Amazon’s Highly Available Key-value Store (DeCandia et al., SOSP 2007)allthingsdistributed.comThe shopping-cart motivation and the techniques Cassandra inherited: consistent hashing, preference lists, sloppy quorums with hinted handoff, vector clocks, Merkle-tree anti-entropy and gossip.
    2. Cassandra: A Decentralized Structured Storage System (Lakshman and Malik, LADIS 2009)cs.cornell.eduDynamo’s distribution plus Bigtable’s column-family model, why vector clocks were dropped, and the Inbox Search deployment (50+ TB on 150 nodes).
    3. Amazon DynamoDB: A Scalable, Predictably Performant, and Fully Managed NoSQL Database Service (Elhemali et al., USENIX ATC 2022)usenix.orgMulti-Paxos replication groups across three AZs, leader-only writes and strong reads, request routers and metadata, WAL plus B-tree replicas, splits, bursting, adaptive capacity and the Prime Day 2021 peak.
    4. Apache Cassandra 5.0 documentation: Dynamo architecturecassandra.apache.orgToken ring and vnodes, NetworkTopologyStrategy, per-cell last-write-wins, consistency levels and W + R > RF, gossip, the phi accrual detector and Merkle-tree repair.
    5. Apache Cassandra 5.0 documentation: cassandra.yaml referencecassandra.apache.orgDefaults quoted here: num_tokens 16, 3-hour hint window, tombstone thresholds, Paxos v1 and v2 round trips, 10-second commit-log sync, timeouts, batch limits and the cassandra_latest.yaml variant.
    6. Apache Cassandra 5.0 documentation: Compaction overviewcassandra.apache.orgSTCS as the default, UCS recommended for new tables, LCS and TWCS use cases, tombstones, zombies and the 10-day gc_grace_seconds.
    7. Apache Cassandra documentation: Data modeling, refining the designcassandra.apache.orgThe 2-billion-cell partition limit, the partition-size formula and bucketing a large partition with an extra partition-key column.
    8. Amazon DynamoDB Developer Guide: Constraintsdocs.aws.amazon.com400 KB items, capacity-unit sizes, 2× cost of transactional reads and writes, the 100-item and 4 MB transaction limits, 1 MB Query and Scan pages and the 10 GB partition and LSI item-collection limit.
    9. Amazon DynamoDB Developer Guide: How global tables workdocs.aws.amazon.comMREC (asynchronous, last writer wins, typically within a second) versus MRSC (three Regions, synchronous to another Region, no TTL, LSIs or transactions).
    10. How Discord Stores Trillions of Messages (Discord engineering, March 2023)discord.comA real chat schema partitioned by channel and time bucket, hot partitions under quorum reads, compaction backlogs, and the move from 177 Cassandra nodes to 72 ScyllaDB nodes.