Section 5: Fifty-Three Bits and One Source of Truth - Data Modeling
Executive Summary: This section turns the API from Section 4 into stores, keys and records. Redis holds one sorted set per board and season (lb:weekly:2026-W44, lb:all-time), with the playerId as the member and a composite score as the score. That composite packs the run's score and a reversed timestamp into 53 bits, so ties resolve to the earlier achiever and every value stays exact in Redis's double. Behind Redis sit the Kafka run-results log (the truth), the player_best table (a conditional max), frozen season_standings for rewards, and a profile cache for display names. We compute Kai's composite to the last digit, settle ember_fox versus quietstorm, and answer the interviewer's favorite pushback: "Why not just Postgres with an index on score?"
The interviewer slides the marker back across the table: "You've got an API. Now tell me what's actually stored, and where."
Many candidates draw one box labeled "Redis" and move on. But a leaderboard has four jobs: remember every run, know each player's best, answer "what rank is 1,284,500?" in microseconds, and still hold last week's top 10,000 after the board moves on. So you say it out loud: four jobs, four stores, and exactly one of them is the source of truth.
The Rank Index: One Sorted Set per Board and Season
The Redis side is deliberately boring. Each board is a standalone primary with 2 replicas, not Redis Cluster, and its two side keys live on the same node:
| Key | Type | Member → score | Size | Lifetime |
|---|---|---|---|---|
lb:weekly:2026-W44 |
sorted set | playerId → composite | 80M × 100 B = 8 GB | Created by the week's first run; frozen (takes no more runs) after the 5-minute grace; kept resident one more week (16 GB with the previous week), then expired |
lb:weekly:2026-W44:pending |
sorted set | provisional playerId → composite | Small | Mirrors its board |
lb:weekly:2026-W44:shadow |
sorted set | banned playerId → composite | Small | Mirrors its board |
lb:all-time |
sorted set | playerId → composite | 150M × 100 B = 15 GB | Forever |
lb:all-time:pending |
sorted set | provisional playerId → composite | Small | Forever |
lb:all-time:shadow |
sorted set | banned playerId → composite | Small | Forever |
The interviewer will probe three things in that table.
The season lives in the key name. There is no reset operation. On Monday 00:00 UTC, runs whose endedAt falls in the new week simply start writing to lb:weekly:2026-W45. The old key is frozen, snapshotted and later expired, never deleted at midnight: a DEL of 80 million members would block the board's single main thread at the busiest moment of the week and destroy the evidence rewards need. We also reject true sliding windows: a weekly board is a calendar object, and players understand "this week." If product ever asks for a rolling "last 7 days" board, that's the flip trigger: a live lb:rolling7 key rebuilt daily from durable per-day bests, which Section 11 builds.
The member is the playerId, 48213377, not the handle kai_runs. Three reasons. Handles change, and a renamed member would orphan the old entry. A short numeric id is what the ~100 B per-member estimate from Section 3 assumes. And the friends board needs it: the Read API calls ZMSCORE lb:weekly:2026-W44 with the 41 ids of Kai and Kai's 40 friends in one round trip, sorts the results, and finds Kai 3rd of 41. A per-user friends sorted set would multiply every improvement by 40 writes; we'd reconsider only for clan-sized groups of ~5,000. Names and avatars come from the profile cache, which hydrates each API instance's 100-id top-100 list once a second.
Shadow bans and provisional holds reuse the same structure. A banned player's entry is removed from the public set and written to lb:weekly:2026-W44:shadow instead, so ZREVRANGE for everyone else never sees them; Section 10's held top-1,000 runs wait in :pending the same way. Either player's own view is composed: their "rank" is ZCOUNT lb:weekly:2026-W44 (<their composite> +inf + 1, and their entry is spliced into their private copy of the top 100 or around-me window. Those scripts touch several keys, the side key and the public one, but always on one node, which is why the side keys share the board's primary. If the boards ever move into Redis Cluster, hash tags (lb:{weekly:2026-W44}:pending) keep them in one slot.
Quick check before moving on:
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson