Redis handles 1 million operations per second on a single node. No joins, no schemas, no transactions. Just one rule: give me a key, I'll give you the value. Here's why that simplicity is the point.

What's actually happening here?

A key-value store is the most minimal database possible. Every piece of data has exactly two parts: a key (the name you use to find it) and a value (the data itself). You store by key, you retrieve by key. That's the entire interface. You cannot filter by value, you cannot sort, you cannot join two keys together. In exchange for giving up all of that, you get something no relational database can match: O(1) lookup regardless of how many records exist. Whether you have 100 records or 100 billion, the time to find any single record is identical.

The problem this solves

Every distributed system has a class of data that follows a simple pattern: "I know the exact ID — just give me the object." User sessions, rate limit counters, cached query results, configuration flags, shopping cart contents, live presence indicators. For all of these, you never need to query by value or run aggregations. You always know the key. A relational database answering these lookups is using a Ferrari to deliver newspapers — technically it works, but you're paying for capabilities you don't need and adding latency you don't have to.

How it really works (step by step)

What happens inside Redis on a GET request:

  1. Client sends GET session:user_4821 — a 29-byte command over a TCP connection from the app server.

  2. Redis parses the command — reads the operation type and the key string.

  3. Hash function runs on the key — maps the key string to a slot number (0–16383 in Redis Cluster).

  4. Hash table lookup — Redis's in-memory hash table resolves the slot to a memory address in O(1). No disk, no index traversal, no query planner.

  5. Value returned directly — the value at that memory address is serialised back to the client.

  6. Total time: ~0.1ms — round trip over a local network. Compare to 5–50ms for a Postgres query.

Redis data structures beyond simple string values:

  • String — the basic type. Stores JSON blobs, integers, binary data up to 512MB. Used for cached objects and counters (INCR page_views:homepage).

  • Hash — a mini key-value store within a key. Store a user object's fields without serialising the whole thing: HSET user:4821 name "Arjun" city "Mumbai".

  • List — an ordered list of strings. Used for message queues, activity feeds, recent items. LPUSH adds to the head, RPOP removes from the tail.

  • Sorted Set — strings each assigned a floating-point score, kept in order. The data structure behind every leaderboard and priority queue. ZADD leaderboard 9850 "user:4821" then ZRANGE leaderboard 0 9 REV returns the top 10.

  • Bitmap — treats a string as an array of bits. Tracking which of 100 million users has logged in today costs exactly 100 million bits = 12.5MB. SETBIT active_users:2024-01-15 4821 1 marks user 4821 as active.

The part most tutorials skip

Redis is single-threaded for command execution — and that's why it's fast. A multi-threaded database spends significant CPU time on locking, context switching, and synchronisation between threads competing for the same data. Redis avoids all of that by running every command on a single thread. The event loop accepts connections asynchronously, but each command executes sequentially. No locks, no contention, no deadlocks. The bottleneck shifts entirely to network I/O, not CPU. This architecture lets Redis handle 100,000+ commands per second per CPU core — and since commands execute sequentially, complex operations like EVAL (Lua scripts) are inherently atomic without any additional synchronisation primitives.

Real company doing this right now

Uber's real-time driver location system stores the location of every active driver in Redis with a 15-second TTL. Each driver's app pings its location every 5 seconds, updating a key like driver_location:driver_id. The key format pairs with Redis's native geospatial commands: GEOADD drivers_geo 72.88 19.07 "driver_4821". When a rider books a trip, Uber queries GEORADIUS drivers_geo 72.87 19.06 2 km to find all drivers within 2km in a single command — no database query, no application-level filtering, no geospatial index build. The entire operation completes in under 1ms. At peak in Mumbai, Uber maintains hundreds of thousands of active driver keys simultaneously, all in memory, all expiring automatically.

What breaks at scale?

Memory is finite and Redis keeps everything in RAM. Unlike a database that can spill to disk transparently, a Redis instance that runs out of memory starts evicting keys — silently dropping data according to its eviction policy. The most dangerous scenario: an LRU-based eviction policy starts dropping old session keys under memory pressure, suddenly logging users out at peak traffic with no error in your logs — just disappeared sessions. The fix is monitoring Redis memory usage as a primary metric, setting eviction policies deliberately (allkeys-lru for cache workloads, noeviction for session stores where data loss is unacceptable), and alerting before you hit 80% memory utilisation.

The "aha" moment

Every Redis data structure is a purpose-built tool for a specific access pattern. A Sorted Set is not just a list with scores — it's a data structure that answers "give me the top N items by score" in O(log N) time, the exact operation a leaderboard needs millions of times per second. Choosing the right Redis type is the difference between 0.1ms and building custom sorting logic in your application.

Your practical takeaway

  • Use Redis Sorted Sets for any ranking or leaderboard featureZADD, ZRANGE, and ZRANK give you O(log N) insertion and O(log N + K) range queries out of the box. Building this in Postgres with ORDER BY and LIMIT under concurrent writes will cause lock contention you cannot solve without this structure.

  • Set a TTL on every key that represents transient state — sessions, rate limit windows, cached responses, OTP codes. Keys without TTLs accumulate forever, silently consuming memory until your Redis instance falls over at 3am during peak traffic.

  • Never store large objects (>1MB) in Redis — Redis is designed for small, frequently-accessed objects. Large values create memory fragmentation, slow serialisation, and network congestion on your Redis connection. Store large blobs in S3 and cache only the metadata or a reference key in Redis.

Lesson 09 · Stage 2 — Storage Architecture · System Design Made Easy