Chapter 10 · Key-Value Databases and Data-Structure Stores
Keys as the API: Lookup Semantics, Namespaces, Prefixes, and Atomic Single-Key Operations
Design AtlasMart key schemas as an API contract, then observe tenant collisions, routing distribution, single-key atomic boundaries, and the hot-key/migration costs created by unstable key construction.
Learning outcomes
AtlasMart wants sub-millisecond lookups for sessions, carts, idempotency records, counters, and small pieces of feature state. The temptation is to think “a key-value database is just a dictionary over the network.” The useful mental model is stricter: the key is part of the public data-access contract. It determines identity, routing, tenant isolation, atomicity boundaries, hot-key risk, migration difficulty, and often which multi-key operations are even possible.
Define key, value, namespace, prefix, key schema, lookup, atomic operation, partition/routing key, collision, hot key, and migration boundary before relying on them.
Design stable tenant-aware AtlasMart key names that express identity without embedding change-prone infrastructure details.
Trace one key through client construction, routing, a single-key mutation, acknowledgement, and a subsequent read.
Demonstrate a cross-tenant collision and a single hot key, then repair both with explicit namespace and workload-aware decomposition.
Explain why O(1)-like lookup is an API expectation rather than a universal end-to-end latency guarantee.
The mandatory labs use Python 3.13+ standard library only in one deterministic process with a logical clock; there is no database server, client driver, container, cloud account, network fault injection, or paid feature. Optional implementation references were rechecked against Redis Open Source 8.10.0 (GA July 2026; Redis 8+ is offered under the user's choice of AGPLv3, RSALv2, or SSPLv1) and Valkey 9.1.1 (released 21 July 2026; predominantly BSD-3-Clause). Product commands/defaults are examples only; later Stage 03 product courses teach product-specific operations in depth.
Chapter 07 showed that a partitioning function maps logical keys onto partitions; Chapter 06 showed that replicas and quorum choices then determine acknowledgement and read behavior. A key-value API hides much of that machinery, but key design still feeds it.
1. A key is identity plus routing input—not a decorative label
A key is the identifier supplied to retrieve or
mutate one logical value. A namespace is an
application-defined partition of key names, commonly encoded
with prefixes such as t:atlas-eu:session:.... Many
key-value systems expose a point-lookup API whose expected work
is approximately independent of the number of logical records
for a well-distributed key, but end-to-end latency still
includes hashing/routing, networking, queueing, replication,
persistence, deserialization, and hot-key contention.
A robust key schema usually contains stable business identity
and a clear kind marker while avoiding volatile implementation
facts. t:atlas-eu:cart:cart-731 can survive a node
replacement. node-4:disk-2:cart-731 bakes current
topology into business identity and turns routine resharding
into a data-model migration.
| Key design | Benefit | Failure if omitted |
|---|---|---|
| Tenant namespace | Collision and authorization boundary | Two tenants can address the same logical key. |
| Entity/type prefix | Human diagnostics, policy grouping, migrations | Ambiguous keys and accidental reuse. |
| Stable immutable ID | Identity survives rename/topology changes | Key rewrites and secondary-reference repair. |
| Bounded key length | Memory/network predictability | Metadata dominates small values. |
| Distribution-aware component | Avoids one partition/key receiving all load | Hot shard or single-key serialization bottleneck. |
2. Trace one AtlasMart request end to end
Suppose checkout updates t:atlas-eu:cart:731. The
client constructs the key; a client/router hashes or otherwise
maps it to partition P3; a coordinator/owner applies the
single-key mutation atomically relative to other operations on
that same key; configured replicas acknowledge; the client
receives success. A later point read constructs the identical
logical key and routes to an allowed replica/coordinator. The
key-value abstraction does not, by itself, promise
linearizability, durable quorum, or multi-key isolation—those
remain product/topology/consistency choices from earlier
chapters.
“Atomic” means the operation has no visible intermediate state inside the documented boundary. An atomic increment can avoid a read-modify-write race on one counter. It does not make a separate inventory key and payment key one transaction.
3. Wrong approach: omit the tenant boundary
AtlasMart's European and US tenants both have
user-42. If a session key is only
session:user-42, the second writer overwrites the
first. This is not a rare hash collision; it is a deterministic
model collision created by an incomplete identity.
Authorization cannot reliably repair an identifier that aliases
two owners.
The repair is explicit ownership in the key schema plus authorization that derives/validates the tenant rather than trusting arbitrary user-supplied prefixes. Namespaces help diagnostics, but they are not security by themselves.
4. Wrong approach: assume more nodes fix one hot key
A million requests to exactly one key still map to one ownership/serialization boundary in many designs. Adding shards increases aggregate capacity but does not automatically parallelize one indivisible key. Possible repairs—if the invariant permits—include sharded counters, per-user/per-object keys, write combining, caching, local aggregation, or business decomposition. Every repair adds read fan-in, merge, staleness, or coordination cost.
5. AtlasMart lab: collisions, routing, and hot-key concentration
The deterministic lab hashes keys into eight toy partitions. It first shows a tenant collision, then a corrected key namespace, then 4,000 independent carts, a 1,000-request single hot key, and a 32-shard counter design. The partition counts are evidence about this hash function and dataset—not a benchmark or prediction of any vendor.
import hashlib
from collections import Counter
PARTITIONS = 8
def route(key):
token = int.from_bytes(hashlib.sha256(key.encode()).digest()[:8], 'big')
return token % PARTITIONS
def good_session_key(tenant, user_id, session_id):
return f"t:{tenant}:session:user:{user_id}:{session_id}"
print("BAD namespace example")
bad = {}
bad["session:user-42"] = {"tenant": "atlas-eu", "cart": ["sku-1"]}
bad["session:user-42"] = {"tenant": "atlas-us", "cart": ["sku-9"]}
print("same key reused by two tenants ->", bad["session:user-42"])
print("\nGOOD tenant-scoped keys")
good = {
good_session_key("atlas-eu", "user-42", "s-001"): {"cart": ["sku-1"]},
good_session_key("atlas-us", "user-42", "s-002"): {"cart": ["sku-9"]},
}
for key, value in good.items():
print(key, "partition", route(key), "value", value)
print("\nENTITY-key distribution")
counts = Counter(route(f"t:atlas-eu:cart:{i:05d}") for i in range(4000))
for p in range(PARTITIONS):
print(f"partition {p}: {counts[p]} keys")
print("\nHOT-KEY request concentration")
requests = ["t:atlas-eu:flashsale:counter"] * 1000
hot = Counter(route(k) for k in requests)
print("one logical key -> partition requests", dict(hot))
print("\nSHARDED counter keys reduce one-key concentration")
requests = [f"t:atlas-eu:flashsale:counter:{i % 32:02d}" for i in range(1000)]
spread = Counter(route(k) for k in requests)
print("32 logical shards -> partition requests", dict(sorted(spread.items())))
print("requires read-side fan-in/reconciliation; distribution is not free")
BAD namespace example
same key reused by two tenants -> {'tenant': 'atlas-us', 'cart': ['sku-9']}
GOOD tenant-scoped keys
t:atlas-eu:session:user:user-42:s-001 partition 4 value {'cart': ['sku-1']}
t:atlas-us:session:user:user-42:s-002 partition 5 value {'cart': ['sku-9']}
ENTITY-key distribution
partition 0: 494 keys
partition 1: 499 keys
partition 2: 506 keys
partition 3: 503 keys
partition 4: 477 keys
partition 5: 540 keys
partition 6: 510 keys
partition 7: 471 keys
HOT-KEY request concentration
one logical key -> partition requests {4: 1000}
SHARDED counter keys reduce one-key concentration
32 logical shards -> partition requests {0: 31, 1: 124, 2: 125, 3: 188, 4: 187, 5: 220, 6: 62, 7: 63}
requires read-side fan-in/reconciliation; distribution is not free
What the evidence proves—and does not prove
The tenant example proves that key identity must include all ownership dimensions. The routing counts prove that independent keys can spread under this toy hash. The hot-key case proves that repeated operations on one logical key remain concentrated. It does not prove uniform real-world hashing, constant network latency, or safe sharded counters under arbitrary invariants.
Check your understanding
- Why is a key schema part of the data model?
- Why is “GET is O(1)” insufficient as a latency claim?
- Can a namespace prefix enforce tenant security by itself?
- Why might sharding one counter be unsafe?
- What should survive a node replacement?
Review the answers
1. It defines identity, ownership, routing input, collision boundaries, atomic scope, diagnostics, and migration behavior.
2. Routing, network, queueing, replication, persistence, serialization, value size, and hot-key contention still contribute to end-to-end latency.
3. No. It helps identity and organization, but authorization must independently validate which tenant/key a caller may access.
4. The read must merge shards, and invariants that require one exact serialized value may be weakened or made more expensive.
5. The logical business key; infrastructure topology should normally be routing metadata rather than embedded identity.
6. Production judgment
| Production dimension | Questions to record before using the pattern |
|---|---|
| Correctness / atomicity | What is the atomic boundary: one key, one structure, one shard, one transaction, or a broader invariant? Which races remain possible around reads, retries, expiration, failover, and multiple keys? |
| Consistency / topology | Which node owns or coordinates the key, how are replicas acknowledged, what stale reads are allowed, and what changes during partition/failover? |
| Durability / recovery | Is the state disposable, reconstructable, or authoritative? What persistence, replication, backup, restore, and reconciliation evidence supports that claim? |
| Latency / hot keys | Measure p50/p95/p99, queueing, value size, key distribution, per-key operation rate, serialization cost, fan-in/fan-out, and hot-key concentration. |
| TTL / memory | Differentiate logical expiration from physical reclamation and memory-pressure eviction. Define refresh rules, jitter, capacity headroom, and acceptable disappearance. |
| Security / tenancy | Namespace tenant data, authorize keys/operations, protect secrets, prevent cross-tenant scans/collisions, limit abusive large values/structures, and audit privileged coordination actions. |
| Operations / testing | Test ambiguous retries, duplicate requests, eviction, restart, replica lag, failover, clock shifts where relevant, hot keys, schema evolution, restore, and cache rebuild. |
| Version / license / cost | Pin product/client versions when used; verify license/edition/feature status; price memory, replicas, persistence I/O, network egress, backup retention, and operational skill. |
Bridge to Lesson 2: Once the key defines the addressable boundary, the next question is what lives behind it: opaque bytes, a document, or server-side data structures with richer atomic operations.
Authoritative references
- Amazon Dynamo paper — primary key-value/distributed design reference
- Redis — Keys and values — current example of keys, naming conventions, and expiration
- Redis Open Source 8.10 release notes — dated implementation snapshot
- Redis licenses — current edition/license status
- Valkey releases — alternative current key-value implementation release history