arrow_backBACK TO REDIS — THE IN-MEMORY DATA-STRUCTURE STORE, END TO END
Lesson 11Redis — The In-Memory Data-Structure Store, End to End5 min read

Advanced Patterns

October 30, 2026

TL;DR

These patterns fall out of the data structures — when a problem maps to a Redis structure, the solution is a few commands. LEADERBOARDS (sorted sets): ZADD scores, ZREVRANGE for top-N, ZRANK for a player's rank — all O(log n); real-time rankings that would be a painful query in a relational DB. RATE LIMITING: INCR a per-window key + EXPIRE, a sliding-window sorted set, or a Lua token bucket — atomic, fast, per-user. COUNTING UNIQUES AT SCALE (HyperLogLog): PFADD/PFCOUNT estimate unique counts in ~12 KB regardless of cardinality (0.8% error) — millions of uniques without storing every id. BITMAPS & GEO: bitmaps track daily-active-users as bits (SETBIT/BITCOUNT), tiny and fast; GEOADD/GEOSEARCH answer 'shops within 2km'. The theme: these aren't bolt-ons — a leaderboard IS a sorted set, a unique-count IS a HyperLogLog — so the solution is O(1)/O(log n) commands, not a batch job.

By now the pattern of Redis should be clear: its real power is that common, otherwise-awkward problems map directly onto its data structures, turning subsystems into a few commands. This lesson collects the best of those patterns — leaderboards, rate limiting, unique-counting at scale, bitmaps and geospatial — each one a small amount of Redis doing what would be a real engineering effort elsewhere.

The patterns

Advanced patterns. Leaderboards (sorted sets): ZADD scores, ZREVRANGE for top-N, ZRANK for a player's rank — all O(log n); real-time rankings that would be a painful query in a relational DB. Rate limiting: INCR a per-window key plus EXPIRE, or a sliding-window sorted set, or a Lua token bucket; atomic, fast, per-user — the classic Redis job. Counting at scale (HyperLogLog): PFADD / PFCOUNT estimate unique counts (visitors) in ~12 KB regardless of cardinality, 0.8% error; millions of uniques without storing every id. Bitmaps and geo: bitmaps track daily active users as bits (SETBIT/BITCOUNT), tiny and fast; GEOADD/GEOSEARCH for shops within 2km with geospatial sorted sets. The theme: these aren't bolt-ons — they fall out of the core data structures; a leaderboard IS a sorted set, a unique-count IS a HyperLogLog; when a problem maps to a Redis structure the solution is a few O(1)/O(log n) commands, not a job.

Leaderboards (sorted sets)

The showcase use of sorted sets (Lesson 2). A leaderboard is a sorted set where the score is the ranking value:

  • ZADD leaderboard 4820 "player:7" — set or update a player’s score (O(log n)).
  • ZREVRANGE leaderboard 0 9 WITHSCORES — the top 10, instantly.
  • ZREVRANK leaderboard "player:7" — a player’s rank (their position), in O(log n).
  • ZRANGEBYSCORE / ZREVRANGEBYSCORE — players within a score band (“ranks 100–110 around me”).

Real-time rankings over millions of players, updated and queried in O(log n). The same thing in a relational database means an ORDER BY ... LIMIT (and an expensive rank computation) on every read — slow and load-heavy. In Redis it’s a built-in. This pattern extends to anything “ranked by a number”: trending items (score = recent activity), priority queues (score = priority), time-ordered feeds (score = timestamp).

Rate limiting

The classic Redis coordination job (Lesson 10), done a few ways depending on precision:

  • Fixed window — INCR rate:user:42:<minute>, reject if over the limit, EXPIRE so it resets. Simple; has edge bursts at window boundaries.
  • Sliding window — a sorted set of request timestamps per user: add the current timestamp, remove ones older than the window, count what’s left. Smooth, precise, slightly more work.
  • Token bucket — a Lua script tracking tokens and refill rate, one atomic operation per request. The most flexible (allows bursts up to a cap with a steady refill).

All are atomic, fast, per-user, and run entirely in Redis — no database round trips on the hot path.

Counting uniques at scale (HyperLogLog)

Counting unique things — unique visitors, unique search terms — normally means storing every distinct id (a set), which costs memory proportional to the cardinality: millions of uniques = lots of RAM. HyperLogLog is a probabilistic structure that estimates the unique count in a fixed ~12 KB, regardless of how many uniques there are, with about 0.8% error:

  • PFADD visitors:2026-10-30 user:42 user:99 ... — add elements.
  • PFCOUNT visitors:2026-10-30 — estimate the unique count (~0.8% error).
  • PFMERGE — combine HLLs (e.g. daily into monthly).

So you can count millions of unique visitors across many days using kilobytes, not gigabytes — trading a tiny, bounded error for enormous memory savings. When you need an approximate unique count at scale (and you almost always can tolerate 0.8% error for analytics), HyperLogLog is the tool.

Bitmaps and geospatial

Two more structures that solve specific problems compactly:

  • Bitmaps — a string treated as an array of bits (SETBIT/GETBIT/BITCOUNT). Track daily-active-users by setting bit N when user N is active today; BITCOUNT gives the active count, and BITOP combines days (users active on day A and B). A million users is ~125 KB (one bit each) — astonishingly compact for presence/activity tracking.
  • Geospatial — GEOADD stores locations (lat/long) in a sorted set (encoded as geohashes), and GEOSEARCH answers ”what’s within 2 km of this point?” sorted by distance. “Shops near me,” “drivers near the rider” — a few commands instead of a spatial database.

The theme: structures, not bolt-ons

The unifying point is that none of these are special features bolted onto Redis — they fall out of the core data structures and the single-threaded atomicity:

  • A leaderboard is literally a sorted set.
  • A unique-count is a HyperLogLog (or a set).
  • A rate limiter is a counter or sorted set with atomic operations.
  • Active-user tracking is a bitmap; “near me” is a geospatial sorted set.

So the way to find the right Redis solution is always the same question from Lesson 2: which structure does this problem map onto? When it maps cleanly, the implementation is a handful of O(1)/O(log n) commands — atomic, fast, in-memory — rather than a batch job or a specialised system. That mapping is the real skill of using Redis well, and it’s why Redis shows up in so many systems doing so many different jobs. The final lesson brings it back to operating all this safely in production.

Pitfalls to Avoid

  1. Building a leaderboard outside Redis. Sorting in the app or an ORDER BY on every read is slow and load-heavy. A sorted set gives O(log n) updates, top-N and rank built in. Use it.
  2. Storing every id to count uniques at scale. A set of millions of ids burns RAM. If ~0.8% error is acceptable (it usually is for analytics), use HyperLogLog — fixed ~12 KB for any cardinality.
  3. Using HyperLogLog when you need exact counts or the members. HLL is an estimate and can’t list its members. For exact counts or membership, use a set (and accept the memory).
  4. Fixed-window rate limits where boundary bursts matter. A fixed window allows up to 2× the limit across a boundary. If that matters, use a sliding window or token bucket.
  5. Ignoring the memory of the structure. A giant sorted set (leaderboard with tens of millions of entries) or bitmap still costs memory and can be a big key (Lesson 12). Cap, shard, or expire where appropriate.
  6. Reaching for a specialised system prematurely. “Near me” doesn’t always need a spatial database; a unique count doesn’t always need a data-warehouse query. If it maps to a Redis structure and the scale fits, Redis is simpler.

Quick Recap

  • Leaderboards = sorted sets: ZADD / ZREVRANGE (top-N) / ZREVRANK (rank), all O(log n) — real-time rankings that are painful in a relational DB.
  • Rate limiting: INCR+EXPIRE (fixed window), a sorted set (sliding window), or a Lua token bucket — atomic, per-user, no DB round trip.
  • HyperLogLog: estimate unique counts in ~12 KB for any cardinality (~0.8% error) — millions of uniques without storing every id (PFADD/PFCOUNT/PFMERGE).
  • Bitmaps (SETBIT/BITCOUNT) track active users as bits (tiny); geospatial (GEOADD/GEOSEARCH) answers “within X km”.
  • The theme: these fall out of the data structures — map the problem to a structure, and the solution is a few O(1)/O(log n) commands.

Next lesson, the last: running all this safely — operating Redis and the pitfalls (big keys, slow commands, when NOT to use it).