SysPadLessons › database lessons › DynamoDB

How DynamoDB works

Fully managed NoSQL key-value and document database. Delivers single-digit millisecond latency at any scale. On-demand mode scales automatically; provisioned mode offers predictable cost.

DynamoDB has no joins and no relational schema you can point to, on purpose. That one set of constraints is exactly why, during Amazon Prime Day 2024, it peaked at 146 million requests per second while holding single-digit-millisecond latency. Here's the single idea that makes that possible.

What you will learn

Finding one item among billions

Imagine a phone book with a billion names and you need one entry in about a millisecond. Flipping through is hopeless. DynamoDB never flips, it computes the page.

Every item you store has a partition key. DynamoDB runs it through a hash function, and the result points at exactly one storage location. No scan, a direct jump.

Partitions: where your data actually lives

That “one location” is a partition, a slice of your table on fast SSDs. A table is split across many partitions as it grows in size or throughput.

Each write is durably persisted across multiple Availability Zones (typically three) before it's acknowledged. Lose a whole data centre and your data is still there, you never configure this.

What actually triggers DynamoDB to split a partition?

Two things: storage (when a partition fills up it splits to make room) and throughput (if you provision more capacity than one partition's ceiling can serve, it splits to spread the load). Splits are managed for you, which is why capacity is divided per partition, the setup for the next section. (You may see an old “10 GB per partition” figure quoted; AWS no longer documents a fixed per-partition size.)

The hot-partition trap

Here's the counter-intuitive part: you can be throttled while most of your capacity sits idle. Each partition has its own ceiling, about 3,000 read units and 1,000 write units per second.

If your key sends most traffic to one partition (every ID starting with the same prefix, one celebrity user, a single “today” bucket), that partition hits its ceiling and starts throttling, no matter how much table-wide capacity you bought.

Bites people running gaming leaderboards, IoT fleets reporting on the same timestamp, and multi-tenant apps where one big customer dominates.

Eventually vs. strongly consistent reads

DynamoDB's default read is eventually consistent: cheap, fast, can come from any of the three copies, but might be a beat behind a very recent write.

A strongly consistent read always reflects the latest write, because it goes to the leader copy.

What you actually pay for

DynamoDB bills in capacity units. One WCU = one write of an item up to 1 KB/second. One RCU = one strongly-consistent read up to 4 KB/second (or two eventually-consistent reads). Bigger items round up into more units.

Two modes: on-demand auto-scales and you pay per request; provisioned means you set the capacity (cheaper at steady, predictable load, and it can auto-scale too).

Why does a 5 KB read cost 2 RCUs, not 1.25?

RCUs are charged in whole 4 KB blocks, rounded up. A 5 KB item spans two blocks (4 KB + 1 KB), so a strongly-consistent read costs 2 RCUs; an eventually-consistent read of the same item costs 1 RCU (half rate). Keeping items small directly cuts cost.

The mindset shift: design for queries, not data

In SQL you model your data, then query it any way later. DynamoDB flips this: you list your access patterns first, then design the table so each one is a direct key lookup. No joins means no after-the-fact slicing. (DynamoDB does offer PartiQL, a SQL-like syntax, but under the hood it's still key-based access, not relational SQL with joins.)

Need to look something up by an attribute that isn't your partition key? You add a Global Secondary Index (GSI), effectively a second copy of the table keyed differently, kept in sync for you.

This is why DynamoDB tables often look strange to SQL eyes, one table, overloaded keys , yet serve every query in a single fast hop.

GSI vs. LSI, what’s the difference?

A Local Secondary Index (LSI) shares the table's partition key but adds a different sort key, and must be created with the table. A Global Secondary Index (GSI) can use a completely different partition key, can be added anytime, and has its own capacity. GSIs are eventually consistent with the base table, and strongly-consistent reads aren't available on a GSI at all.

Flashcards

You write a profile update. A read one second later returns the old value. Which consistency model, and is it a bug or a feature?
Eventual consistency, and it's a deliberate feature: lower latency, higher availability, reads from any replica. The replicas converge within milliseconds.
10,000 writes/sec all go to user IDs starting with “A”. Capacity is provisioned high, yet you're throttled. Why?
A hot partition. Those keys hash to one partition, which hits its ~1,000-WCU/sec ceiling. Table-wide capacity doesn't help, the limit is per partition.
You write a 5 KB item once per second. How many WCUs does that consume?
5 WCUs, one WCU covers 1 KB of writes, rounded up.
A 5 KB item, read once per second, eventually consistent. How many RCUs?
1 RCU. The item rounds to two 4 KB blocks (2 RCUs strong), and eventually-consistent reads are half-rate, so 1 RCU.
New app, traffic unpredictable and spiky. On-demand or provisioned capacity?
On-demand, it auto-scales instantly and you pay per request, so you neither over-provision nor get throttled by a guess.
You need to query by an attribute that isn't the partition key. What do you create?
A Global Secondary Index (GSI), a differently-keyed view of the table, kept in sync for you (eventually consistent with the base table).

Sources

Open the SysPad canvas · Official DynamoDB documentation

Other database lessons