Skip to main content

Key-Value Stores

Level 2: Level 2: Data Storage & Modelingeasy25 minkey-valueredissessions

Encode everything you query on into a namespaced key, guard against hot keys, TTL cache data, and never treat a non-persistent cache as a source of truth.

The simplest database, and the discipline it forces

A key-value store is the simplest possible database: a distributed hash map. You GET(key), you PUT(key, value), you DELETE(key). There is no query language over the value, no WHERE clause, no join. Because the access path is a hash lookup, point reads and writes are O(1) and the fastest thing in your architecture: Redis serves reads in tens of microseconds in-process and sub-millisecond p99 over the network, and a single node handles 100k+ ops/sec easily. This is why KV stores are the default for caches, session stores, feature flags, rate-limit counters, and as a building block inside bigger systems.

The defining constraint is value opacity. To the store, the value is a blob of bytes. You cannot ask "give me all sessions where lastActive < X" because the store cannot see inside the value. Whatever you want to query on must be encoded into the key. This forces the key-design discipline that is the whole skill of this family.

Key design

Namespace with a prefix and a delimiter so different data types never collide: session:{sessionId}, user:123:profile, ratelimit:{userId}:{minuteBucket}. Composite keys co-locate related lookups. The danger is hot keys: a single key that takes a wildly disproportionate share of traffic (a global counter, a celebrity's profile) becomes a hotspot on whichever shard owns it. You fight this by sharding the key (counter:{shard} summed across N shards) or by fronting the hot key with a client-side or local cache.

Check yourself
Your team stores login sessions in a Redis instance configured as a pure cache: no persistence, 'allkeys-lru' eviction. The node restarts. What do users experience?

Interview nuance: Interviewers probe "cache or source of truth?" Memcached and a Redis instance with no persistence are caches: if the box dies, the data is gone, and that is fine because you can recompute it from the real database. If you use a KV store as a durable source of truth (DynamoDB, or Redis with AOF/RDB persistence and replication), you must reason about durability, replication, and backups just like any primary database. The common wrong turn is treating a cache-configured Redis as a system of record, then losing data on a restart.

TTL, eviction, and the rich data structures

Every session and counter should carry an expiry (SET key val EX 3600) so stale data self-cleans. When memory fills, Redis evicts by policy: allkeys-lru for a pure cache, volatile-lru to only evict keys that have a TTL, noeviction to fail writes instead of dropping data (what you want for a source of truth).

Redis is more than KV. It ships data structures that make it a Swiss-army server: sorted sets (leaderboards, sliding-window rate limits, priority queues), lists (simple queues), hashes (store a session as fields you can update individually), streams (append-only log with consumer groups), pub/sub, HyperLogLog (cardinality estimation), and vector similarity. Reaching for these instead of raw string blobs is often the difference between a clean design and a clumsy one.

Choose the engine to the job: Memcached for a dumb, multi-threaded, memory-only cache; Redis for a single-threaded rich-data-structure store that can also persist; DynamoDB for a managed, durable, auto-sharded KV/document store with predictable single-digit-ms latency at any scale.

Recap: KV stores give O(1) opaque-blob lookups, so encode everything you query on into a namespaced key, guard against hot keys, always TTL cache data, and never treat a non-persistent cache as your source of truth.

Check yourself

You are about to design a session store and rate limiter on Redis. Sort each piece of data by what losing it on a restart would mean.

Live login sessions with no copy anywhere else
Per-minute rate-limit counters
Cached results of an expensive database query
The only copy of a user's shopping cart

Apply

Your turn

The task this lesson builds to.

Design the data layout for user sessions and rate-limit counters in a key-value store, including key schema and TTLs.

Think about

  1. How do you design keys and namespaces to avoid hot keys?
  2. When is a KV store a cache vs a source of truth?
  3. What does value-blob opacity mean for your model?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design the key-value layer for Twitch's live-stream viewer-count and chat rate-limiting during a top event peaking at 5 million concurrent viewers on a single channel, where a naive global counter would melt one shard. Explain the key schema, the hot-key mitigation, and the consistency you accept.

Think about

  1. What makes a single channel's viewer count the archetypal hot key?
  2. Does the displayed count actually need to be exact, and what does relaxing that buy?
  3. Where can rate-limit enforcement move so a channel-wide limit is not a global lock?