System Design blueprint · Gaming
Real-time gaming leaderboard
Ingests validated score updates from millions of players into sharded Redis sorted sets. It serves global, regional and friends rank queries in milliseconds and rotates seasons into an archive. It must never show a cheated score or lose a legitimate one, and it must keep ranks consistent while a season resets.
- Steps
- 8
- Subjective questions
- 33
- Objective questions
- 33
The problem and the outcome
Problem: Players expect to see their rank change seconds after a match. A relational ORDER BY over millions of rows cannot answer 'what is my rank' or 'who is around me' fast enough under heavy write load.
Outcome: Rank, top-N and around-me queries run in logarithmic time against in-memory sorted sets, and suspicious scores are held back before anyone sees them. Each season resets cleanly, and its final standings are kept for rewards and history.
Architecture
How it works, step by step
- The game server, not the client, produces the match result and signs it. The Score API checks auth and the signature, rate-limits each player and assigns an idempotency key per match.
- Anti-cheat runs synchronous plausibility checks such as max score per match, match duration, impossible stats and replayed match IDs. Suspicious results go to a review queue instead of the live board.
- Accepted events are published to a Kafka topic partitioned by player ID, which keeps per-player order. They are also written to a durable score ledger, which is the source of truth.
- The leaderboard writer consumes the events and runs ZADD with the GT flag on keys like lb:{season}:{region}. A member's score only moves up when it beats its best, and replays are harmless.
- The Rank Query API answers top-N with ZREVRANGE and my-rank with ZREVRANK. Around-me fetches the player's rank, then a small range above and below it. Popular top-N results are cached for a second or two.
- For a friends leaderboard, the API fetches the friend ID list from the social service and calls ZMSCORE on the season key. It sorts the small result in application code instead of keeping a sorted set per user.
- At season end, the scheduler stops writes to the old key and points writers and readers at the next season's key. This is a config switch, not a delete.
- The scheduler snapshots the frozen board to object storage for rewards and history, then sets an expiry on the old key. If Redis data is lost, the board is rebuilt by replaying the ledger.
Tech stack
- Redis Cluster or Valkey (sorted sets)
- Apache Kafka
- Apache Cassandra or ScyllaDB (score ledger)
- Amazon S3 or GCS with Parquet (season archive)
- gRPC/HTTP API behind an API gateway
- Kubernetes CronJob or Temporal for season rotation
- Prometheus and Grafana
Key design decisions
- Partition sorted sets by season and region, not by score range. Redis Cluster places a whole key on one shard, so one giant global set becomes a hot node. A global top-N is built by merging each shard's top-N.
- Encode tie-breaks into the score, for example the score in the high part and an inverted timestamp in the low part. Stay within the 53 bits a double holds exactly so earlier achievers rank higher deterministically.
- Keep the ledger as the source of truth and treat Redis as a rebuildable projection. This allows cheaper persistence settings on Redis and clean replays after a revocation.
- Compute friends boards on read with ZMSCORE over a bounded friend list. A per-user sorted set would cost a fan-out write for every score change.
- Show exact rank only for the top tier. Lower tiers get a percentile from score histograms, which avoids cross-shard exact rank counting for every player.
Common mistakes
- Trusting client-reported scores. Without server-authoritative results and signatures, cheaters fill the top of the board within hours.
- Deleting the old season key at midnight while writes are still in flight. Late events land in the wrong season or recreate the deleted key.
- Using ZADD without GT or idempotency. Retried or reordered events can lower a player's best score or double-count incremental points.
- Running ZRANGE over huge ranges or KEYS in production. A large reply blocks a single-threaded Redis shard and spikes latency for everyone on it.
- Letting revoked cheaters keep their place in archived seasons. Revocations must flow to both the live set and the season snapshot used for rewards.
What to measure
- p99 latency for rank, top-N and around-me queries
- Ingest-to-visible lag from match end to the rank update
- Kafka consumer lag per partition on the leaderboard writer
- Anti-cheat flag rate and the share of flags overturned on review
- Time to rebuild a shard's sorted set from the ledger
Most-asked interview questions
Subjective questions 33
1How would you return a player's exact global rank when you have tens of millions of players?Asked almost every time
I'd store best scores in a Redis sorted set, where ZREVRANK is logarithmic, so one rank lookup stays cheap even at tens of millions of members. The catch is that a single key lives on one cluster shard, so a single global set becomes a memory and hotspot risk. I'd split by region or season. For the global top hundreds, I'd merge each shard's top-N. For everyone else, I'd keep a score histogram and return a percentile, such as top three percent, rather than an exact cross-shard count. Exact global rank for the elite tier, approximate for the long tail, is usually what players and product actually need.
2Walk me through the end-to-end architecture of this leaderboard, from match end to a rank showing on screen.Asked almost every time
The authoritative game server ends the match, builds a result and signs it. The Score API verifies auth and the signature, rate-limits the player and attaches an idempotency key per match. Anti-cheat runs fast plausibility checks. Suspicious results go to a review queue, and clean ones are written to a durable score ledger and published to Kafka, partitioned by player ID. A leaderboard writer consumes the events and runs ZADD GT on season and region sorted sets in Redis. The Rank Query API serves top-N, my-rank, around-me and friends queries from Redis, with a short cache in front of hot top-N reads. A scheduler rotates seasons by switching config and archives the frozen boards to object storage.
3Why must the game server, rather than the client, produce and sign the match result?Asked almost every time
The client runs on hardware the player controls. Anything it sends can be modified, replayed or invented, so a client-reported score is just a claim. The authoritative game server simulates the match, so it knows the real outcome. It signs the result with a key that never leaves the server side, for example an HMAC key or a private key held in a secrets manager. The Score API verifies that signature, which proves the result came from our infrastructure and was not altered in transit. Signing does not catch a compromised game server or game-logic exploits, so plausibility checks still run afterwards. Keys should be rotated, and the signature should cover the match ID, player ID, season and timestamp so it cannot be reused.
4Why is the score ledger the source of truth instead of Redis?Asked almost every time
Redis is optimised for fast ranking, not durability. Replication is asynchronous, so a failover can drop recently acknowledged writes. Persistence settings vary, and memory limits or operator mistakes can lose keys. The ledger is a durable, append-only record of every accepted result with its match ID, player, season, score and timestamp. Because the board only stores each player's best score per season, it can always be derived from the ledger by taking the max per player. That gives us rebuilds after data loss, audits for disputes, corrections after late cheat detection and reward calculation that does not depend on cache state. Redis becomes a materialised view we can throw away and recreate.
5Two players have the same score. How do you decide who ranks higher?Asked almost every time
By default, Redis orders equal scores lexicographically by member, so ties are broken by player ID string. That is deterministic but arbitrary, and players will see it as unfair. A common rule is that whoever reached the score first ranks higher. I would encode that into the score itself, for example score multiplied by a large factor plus (a far-future constant minus the achievement timestamp in seconds). The result must stay within 2^53 so a double represents it exactly. That limits how many bits go to the real score versus the timestamp, so I would size it explicitly. GT still works because a higher real score always produces a higher composite. The API decodes the real score before displaying it.
6Why fetch friend scores with ZMSCORE and sort in code instead of keeping a sorted set per user?Asked almost every time
A per-user friends set means every score update fans out to every friend's set. A player with hundreds of friends turns one write into hundreds, and memory grows with the total number of friendship edges rather than the number of players. Reading on demand is cheaper. Get the friend list from the social service, issue one ZMSCORE on the season key, drop the nils and sort a few hundred numbers in the application. That is O(F) in Redis for F friends and is fast. It breaks down when F is very large, such as creators with huge follower counts. In that case cap the list, batch the calls, or treat follower boards as a separate feature. The friend list can be cached briefly to reduce load on the social service.
7A Redis primary holding a leaderboard shard fails. What happens and what do you lose?Asked almost every time
Redis Cluster or Sentinel promotes a replica, usually within seconds. Writes to that shard fail or retry until promotion finishes. Because replication is asynchronous, the new primary can miss the last writes the old one acknowledged. Nothing legitimate is truly lost, because every accepted result is in the ledger and in Kafka. Recovery works like this: the writer's Kafka consumer offsets only advance after successful writes, so it resumes and re-applies recent events. ZADD GT makes re-application safe. For a wider gap, replay that shard's players from the ledger. Reads may show a slightly stale rank for a short time. I would alert on failovers and on consumer lag, and run a reconciliation check afterwards.
8Anti-cheat flags a score as fraudulent hours after it went live on the board. How do you remove it?Asked almost every time
ZADD GT cannot lower a score, so corrections need a separate path. First mark the result as revoked in the ledger, keeping it for audit rather than deleting it. Then recompute that player's best remaining legitimate score for the season from the ledger. Write it with a plain ZADD without GT, or ZREM if nothing legitimate remains. Do this through the same per-player partition, or under a per-player lock, so a concurrent live update cannot race the correction. Invalidate any cached top-N that contained the player. If rewards were already calculated from a snapshot, the reward service needs a revocation step too. Log every correction with the reason, and a ban usually blocks future submissions at the Score API.
9A match ends one second before the season closes but its event arrives after the switch. Which season does it count for?Asked almost every time
It should count for the season in which the match ended, not the one in which it was processed. The game server stamps the match end time and the season ID into the signed result, and the writer routes using that field instead of the current config. To make that work, the old key stays writable for a short grace window after the season boundary. Readers switch to the new season immediately, but late events can still land on the old board. After the grace window, the old key is frozen, and anything later is rejected or sent for manual handling. The snapshot for rewards is taken only after the freeze. That way legitimate end-of-season scores are not lost and the archive matches the ledger.
10How do you handle a season reset without downtime or lost scores?Very often asked
I never reset a key in place. Every season gets its own key, like lb:s12:apac. At the boundary, the scheduler flips a config value so writers and readers move to the new key, and events carry their match timestamp so late arrivals are routed to the season they belong to. The old key is frozen for a grace window to absorb stragglers and anti-cheat revocations. Then I snapshot it to object storage for rewards and history, and only after that do I set an expiry. Because the ledger holds every event, I can regenerate any season's standings if the snapshot is disputed.
11Where does anti-cheat sit in this pipeline, and how do you avoid slowing down honest players?Very often asked
I split it into two layers. The synchronous layer is cheap and deterministic. It verifies a signature from the authoritative game server, rejects replayed match IDs, and applies plausibility bounds like maximum score per match or per minute. That adds very little latency. The asynchronous layer looks at patterns over time, such as win-rate jumps, impossible accuracy or device fingerprints. It can revoke scores later through the same writer path. Borderline results go to a review queue instead of the live board. Honest players see their score almost instantly, and a cheater's score either never appears or is removed across live and archived boards.
12Step 3 writes to both the ledger and Kafka. How do you avoid the dual-write problem?Very often asked
If the API writes the ledger and then publishes to Kafka as two independent calls, a crash between them leaves the two out of sync. A score could be recorded but never ranked, or ranked but never recorded. I would make the ledger write the single commit point. Use a transactional outbox: in the same database transaction, insert the ledger row and an outbox row, then have a relay or change-data-capture connector publish outbox rows to Kafka. Publishing is then at-least-once. That is fine because events carry the match idempotency key and ZADD GT is idempotent for the same best score. A reconciliation job can periodically compare ledger maxima against Redis for a sample of players to catch drift.
13Why partition the Kafka topic by player ID, and what does that buy you?Very often asked
Kafka only guarantees order within a partition. Keying by player ID sends all of a player's events to one partition, so one consumer processes them in order. That keeps per-player logic simple, such as cumulative modes or any future step that depends on sequence, and it avoids two consumers racing on the same member. It also spreads load evenly because there are millions of player IDs, which avoids hot partitions. With ZADD GT, ordering matters less for the best-score board, since the max wins regardless of order. But the ordering is still valuable for auditing and alternative score modes. The trade-off is that the partition count limits consumer parallelism, so it should be sized with headroom from the start.
14Why does ZADD GT make replays harmless, and what changes if the game mode uses cumulative points instead of best score?Very often asked
With GT, Redis updates an existing member only if the new score is greater than the stored one. Replaying the same event sets the same value, and replaying an older, lower event is a no-op. The operation is idempotent, so at-least-once delivery from Kafka is safe. Cumulative points are different. ZINCRBY adds every time, so a redelivered event double-counts. In that case the writer needs dedupe: record processed match IDs in Redis with a TTL and do the check and the increment atomically in a Lua script or function. Another option is to compute the total in the ledger and write it to Redis as an absolute value. Absolute values keep the write idempotent again.
15How do you implement the around-me view, and what edge cases matter?Very often asked
Call ZREVRANK to get the player's zero-based position, then ZREVRANGE with WITHSCORES from rank minus k to rank plus k. Both are logarithmic plus the small range size. Edge cases: if the player is near the top, clamp the start at zero. If the player has no score this season, ZREVRANK returns nil, so show a 'not ranked yet' state. The two calls are not atomic, so the board can shift between them. Running both in a short Lua script or a MULTI block on the same key gives a consistent snapshot. Display ranks should be one-based. Around-me is per-user and changes constantly, so I would not cache it. It is cheap enough to compute live.
16Give me a rough capacity estimate for memory and write throughput. How would you approach it?Very often asked
I would state assumptions rather than quote magic numbers. Say there are N active players per season and each sorted set member costs some bytes for the member string, the score, the skiplist node and the hash entry. I would measure that with MEMORY USAGE on a test set of realistic size instead of guessing. Memory equals N times the bytes per member times the number of boards, because each player sits in a regional board and possibly a global one. Double it for replicas and add headroom. For writes, peak matches per second times players per match gives ZADDs per second. Pipelining in the writer batches these, so the limit is usually network and CPU per shard. Then I would load-test one shard to find its ceiling and divide.
17Describe how you rebuild a leaderboard from the ledger if Redis data is lost.Very often asked
First stop serving that board, or mark it degraded, so users do not see a partial ranking as final. Build into a fresh key such as a rebuild suffix, not the live one. Query the ledger for the maximum accepted score per player for that season and region, excluding anything later revoked by anti-cheat. Stream the results into Redis with pipelined ZADD calls in batches. Meanwhile the live writer keeps consuming Kafka. Writing to both keys during the rebuild, or replaying Kafka from a recorded offset afterwards, covers events that arrived mid-rebuild. GT makes overlap safe. Then switch the config pointer to the rebuilt key. Verify counts with ZCARD and spot-check ranks against the ledger before declaring it healthy.
18During the season switch, how do you keep readers from seeing an inconsistent mix of old and new seasons?Very often asked
The current season is a single versioned config value that services read from a config store and cache locally. A query resolves the season once at the start and uses that key for every call it makes. An around-me request will not take a rank from the old season and neighbours from the new one. Instances may flip a few seconds apart, so the API should return the season ID in responses and clients should label boards by season. For the first moments the new board is nearly empty, which is correct. Clients can show 'new season started' instead of an empty-looking leaderboard. A rollback is just pointing the config back.
19Your key pattern is lb:{season}:{region}. What does that mean for Redis Cluster slot placement?Very often asked
In Redis Cluster, a substring in curly braces is a hash tag. Only the text inside the first pair of braces is hashed to choose the slot. If the key is literally lb:{s12}:eu, every region of season 12 lands in the same slot and therefore on the same node. That defeats the point of sharding by region. If the braces in the design are just template placeholders, I would make the real key something like lb:s12:eu, so each region hashes independently. I would only use a hash tag on purpose, when I need multi-key operations on keys that must live together. Each regional board then sits on a different node, and load and memory spread across the cluster.
20How is the idempotency key chosen and enforced, and why not rely only on ZADD GT?Very often asked
The natural key is the match ID plus player ID, created by the game server and covered by the signature, so it cannot be forged or changed. The API and ledger enforce uniqueness on it, for example with a unique constraint, so a retried or replayed submission becomes a no-op that returns the original outcome. GT only protects the Redis board, and only for best-score semantics. It does nothing for the ledger, for reward counts, for cumulative modes or for anti-cheat statistics, all of which would be skewed by duplicates. A seen match ID also feeds the replayed-match check. The key is enforced at the entry point and GT is a second safety net downstream.
21Top-N of the global board is read far more than anything else. How do you handle that hot key?Very often asked
All top-N reads for one board hit one key on one primary, so that node's CPU becomes the limit. First, the short API-side cache absorbs most traffic, since everyone sees the same top 100. Second, serve these reads from replicas. A rank that is a few hundred milliseconds stale is acceptable here. Third, a background job can compute top-N on a fixed schedule and push it to a local cache or CDN-backed endpoint, so user traffic never touches Redis for that view. Writes still go to the primary, and pipelining keeps write cost low. I would only split the board itself if writes become the bottleneck, because splitting makes exact ranking harder.
22Why not just store scores in a relational database and use ORDER BY with an index?Very often asked
Top-N with an index on score is fine in SQL. The hard part is 'what is my rank', which needs a count of rows with a higher score. For a player in the middle of tens of millions, that scans a large slice of the index on every request, and the index is constantly updated under heavy write load. A Redis sorted set keeps a skiplist that supports rank lookups in logarithmic time in memory, so my-rank and around-me stay fast while writes keep flowing. We still use a durable database, as the ledger, for what it is good at: correctness, history and audit. Redis is the serving index derived from it.
23You cache popular top-N results for a second or two. How do you stop a cache stampede when the entry expires?Often asked
When a hot key expires, thousands of concurrent requests can miss at once and all hit Redis with the same ZREVRANGE. I would use request coalescing, also called single-flight: within each API instance, the first miss fetches and the others wait for that result. Across instances, a short lock or a background refresher can rebuild the entry just before expiry, so readers always see a value. Adding small random jitter to TTLs avoids synchronised expiry across keys. The data is a ranking that is already allowed to be a second or two stale, so serving a slightly old value during refresh is acceptable. It is far better than overloading the primary of a hot shard.
24Why set an expiry on the old season key instead of deleting it right after the snapshot?Often asked
Keeping it for a while means support can answer disputes, the rewards job can retry, and players can still view last season's final board, all from fast storage. An expiry also removes the risk of a scheduler bug deleting the live key, because the delete is deferred and bounded. One caution: freeing a very large sorted set synchronously can block the Redis thread. With lazy-free settings such as lazyfree-lazy-expire enabled, expired keys are reclaimed in a background thread. For manual cleanup, use UNLINK rather than DEL. After the key expires, history is served from the object-storage snapshot.
25How would you design the per-player rate limiter in the Score API?Often asked
A token bucket per player ID works well. It allows a small burst, because matches can end back to back, while capping the sustained rate at something above what real gameplay can produce, given minimum match durations. State can live in Redis, updated atomically with a short Lua script, or in a gateway with built-in limiting. It should be a separate cluster from the leaderboard so abuse cannot hurt ranking. Limits should also apply per game server and per API credential, since a leaked server key is a bigger threat than one player. Rejected requests return a clear retryable error, and repeated violations feed the anti-cheat signals rather than being silently dropped.
26What happens to a result sent to the review queue, and how does an approved one reach the board?Often asked
A flagged result is stored in the ledger with a pending status, so it is durable but not ranked. The player might see 'score under review'. Reviewers or automated second-stage models with heavier checks, such as replay analysis, approve or reject it. On approval, the system publishes the same event to the normal Kafka topic, and the writer applies ZADD GT like any other result. Since GT keeps the max, a late approval cannot overwrite a higher legitimate score. The event keeps its original season and timestamp. If that season is already frozen, it goes through an explicit correction process for the archive and rewards. On rejection, the status becomes revoked and it never touches Redis.
27What would you monitor and alert on for this system?Often asked
Ingestion: Score API error rates, signature failures, rate-limit rejections and the review-queue rate. A sudden spike can mean an exploit or a bad game build. Pipeline: Kafka consumer lag per partition, writer error and retry rates, and end-to-end latency from match end to visible rank. Redis: memory per shard, command latency, CPU, replication lag and failover events. Reads: p99 latency per query type and cache hit ratio. Correctness: a periodic reconciliation that samples players and compares the ledger maximum to the Redis score. Season operations: switch time, snapshot success and expiry set. Alerts go on lag, reconciliation mismatches and snapshot failures, because those threaten the never-lose-a-score requirement.
28What privacy concerns apply to leaderboards, especially the friends board?Often asked
Leaderboards publish data about people, so the design needs defaults and controls. Show display names, never real names or contact details. Respect a privacy setting that hides a player from public boards while still ranking them privately. Respect blocks, so a blocked user does not appear in your friends board. The friends query should only include confirmed friends returned by the social service, not arbitrary IDs passed by the client, otherwise it becomes a lookup tool. For data-protection laws such as India's DPDP Act or the GDPR, account deletion has to remove the member from live Redis keys and handle the ledger and archives under the retention policy, for example by pseudonymising IDs. Minors may need stricter defaults.
29A player moves from one region to another mid-season. How should their regional ranking behave?Often asked
Decide the rule explicitly. A common choice is that region is fixed for the season at first ranked match, which avoids gaming the system by hopping to weaker regions. Each event then carries the season region from the player profile, not the server's location. If moves are allowed, the writer must ZREM the player from the old regional key and ZADD the best score into the new one. Run both as one atomic step per player, through the per-player Kafka partition. The global board, if it exists, is unaffected. Whatever the rule, record it in the ledger so rebuilds reproduce the same placement, and document it for players.
30Players outside the top thousand only care about a rough percentile. How might you serve that more cheaply?Often asked
Exact rank from ZREVRANK is already logarithmic, so cost is not usually the problem. The value of percentiles shows up when the board is split across shards or when you want a stable message like 'top 5 percent'. You can get it from ZREVRANK divided by ZCARD on one board. Across shards, precompute a score histogram or quantile thresholds every minute or so with a background job, then map a player's score to a percentile with a lookup. That is a constant-time read, cacheable, and accurate enough for display. Exact numbers are kept for the top tiers, where rewards depend on them, and for the snapshot used in payouts.
31Players are worldwide. How would you deploy this across geographic regions?Often asked
Keep each regional board's write path close to its game servers: a regional Score API, Kafka and Redis, so ingestion latency stays low and failures stay contained. For a global board there are two options. You can maintain one global key in a home region and forward accepted events to it asynchronously, accepting cross-region delay of seconds. Or you can keep regional boards only and compute global rank by combining counts across them, which is slower per query. Read replicas or cached top-N copies in each geography keep reads fast. The ledger needs a clear home per player, or a replicated store, so rebuilds have a single answer. I would not use active-active writes on one sorted set.
32The leaderboard writer falls behind during a big tournament. How do you handle backpressure?Often asked
Kafka absorbs the burst durably, so lag means delay, not loss. The aim is to recover quickly. The writer should pipeline ZADDs in batches and group them by target shard, so each round trip carries many commands. Scale writer instances up to the partition count. Keep the work per event minimal: no remote calls in the hot path, and the season and region already in the event. If one shard is saturated, more consumers will not help, and that board needs more capacity or a split. Users should see honest status, for example 'ranks updating', when lag passes a threshold. Alert on lag growth rate, not just absolute lag.
33How would you test that this system never loses a legitimate score and never shows a cheated one?Sometimes asked
Unit-test the pure logic: signature verification, plausibility rules, composite tie-break encoding and its 2^53 bound, and season routing by match time. Integration tests replay the same events several times and out of order, and assert that the board equals the ledger maximum. Chaos tests kill the writer mid-batch, fail over a Redis primary and pause Kafka, then run reconciliation and expect zero mismatches. Season tests inject events just before and after the boundary and within the grace window. Security tests submit tampered, unsigned and replayed payloads and confirm none reach Redis. Load tests drive peak match-end bursts while measuring read p99. A reconciliation job should run continuously in production too.
Objective questions 33
1What is the time complexity of ZREVRANK on a Redis sorted set with N members?Asked almost every time
Why: Sorted sets use a skip list with span information, so finding a member's rank takes logarithmic time.
2In this design, which component is trusted to produce the final match result?Asked almost every time
Why: Clients run on hardware players control. Only the game server, which simulated the match, produces and signs the result.
3Which Kafka partition key preserves per-player event order?Asked almost every time
Why: Kafka orders events only within a partition. Keying by player ID puts all of a player's events in one partition.
4Why is ZINCRBY risky with an at-least-once Kafka consumer?Asked almost every time
Why: ZINCRBY is not idempotent, so duplicate deliveries double-count unless they are deduplicated.
5A cheated score must be lowered to the player's best legitimate score. Which approach works?Asked almost every time
Why: GT never lowers a score, so corrections need a plain ZADD or ZREM based on the ledger's legitimate maximum.
6What is the source of truth for scores in this design?Asked almost every time
Why: The ledger durably records every accepted result. Redis is a rebuildable view derived from it.
7A match ends just before the season boundary and its event is processed just after. How should it be routed?Asked almost every time
Why: Routing by the match's own season ID, while the old key accepts writes in a grace window, preserves legitimate end-of-season scores.
8Which ZADD option ensures a player's stored score only changes when the new score is higher?Very often asked
Why: GT updates an existing member only if the new score is greater than the current one, which suits best-score leaderboards. It still adds new members.
9What is the time complexity of ZREVRANGE key 0 M-1 on a sorted set with N members?Very often asked
Why: Redis finds the start position in O(log N) and then returns M elements.
10What does ZMSCORE return for a requested member that is not in the sorted set?Very often asked
Why: ZMSCORE returns one entry per requested member, with nil for members that do not exist.
11By default, how does a Redis sorted set order members that have equal scores?Very often asked
Why: Ties are ordered lexicographically by the member string, which is deterministic but not a fairness rule.
12In Redis Cluster, which part of the key lb:{s12}:eu is hashed to choose the slot?Very often asked
Why: When a key contains a hash tag, only the substring inside the first pair of curly braces is hashed.
13What does ZADD with the GT flag do when the member does not yet exist?Very often asked
Why: GT restricts updates to existing members. It does not prevent new members from being added.
14Which pattern prevents the ledger and Kafka from diverging when a crash happens between the two writes?Very often asked
Why: The outbox row commits atomically with the ledger row and is then published reliably, so there is one commit point.
15Why can a Redis failover lose writes that were already acknowledged?Very often asked
Why: The primary acknowledges writes before replicas receive them, so a promoted replica can be missing the latest writes.
16What does the Redis WAIT command provide?Very often asked
Why: WAIT confirms replication to N replicas. It does not make Redis strongly consistent, and failover can still lose writes.
17For a friends leaderboard built with ZMSCORE, what is the Redis cost per query for F friends?Very often asked
Why: ZMSCORE looks up each requested member in the hash table, so cost grows with the number of friends.
18What is the main reason this design avoids a sorted set per user for friends boards?Very often asked
Why: Per-user sets need write fan-out and memory proportional to friendship edges. Reading on demand avoids both.
19Which check detects a valid signed result being submitted a second time?Very often asked
Why: A replayed result has a valid signature, so only tracking already-seen match IDs catches it.
20Why can't a player forge a server-signed result with an HMAC signature?Very often asked
Why: Producing a valid HMAC requires the secret key, which is never shipped to clients.
21Kafka consumer lag for the leaderboard writer is steadily growing. What does it indicate?Very often asked
Why: Lag is the gap between produced and consumed offsets. Events stay durable in Kafka but rank updates get delayed.
22In Redis Cluster, why does one very large global leaderboard sorted set become a bottleneck?Often asked
Why: Keys map to hash slots and each slot is owned by one node, so all memory and traffic for that key land on a single shard.
23When packing score and timestamp into one composite sorted-set score, what limit must you respect?Often asked
Why: Sorted-set scores are IEEE 754 doubles, which represent integers exactly only up to 2^53.
24Which command removes a very large key without blocking the Redis main thread while memory is freed?Often asked
Why: UNLINK removes the key from the keyspace immediately and reclaims its memory in a background thread.
25What is the main trade-off of caching top-N results for one to two seconds?Often asked
Why: A short TTL trades a small amount of staleness for much less read load on the hot key.
26Which technique prevents many concurrent cache misses from all querying Redis for the same top-N?Often asked
Why: Single-flight lets one request fetch the value while the others wait for it, avoiding a stampede.
27ZREVRANK returns 0 for a player. What rank should the UI display?Often asked
Why: ZREVRANK is zero-based, so the top player has rank 0 and should be shown as rank 1.
28For around-me with k neighbours, what should happen when the player's rank r is less than k?Often asked
Why: Clamping the start to 0 avoids a negative start index, which ZREVRANGE would treat as an offset from the end.
29Why is a token bucket a good fit for per-player score rate limiting?Often asked
Why: Matches can end back to back, and a token bucket tolerates small bursts while limiting abuse over time.
30What is the main benefit of implementing the season switch as a config pointer change?Often asked
Why: Flipping a pointer to a new key needs no data movement, and pointing it back undoes the change.
31Since Redis 6.2, which form is recommended over ZREVRANGE for reverse-ordered range queries?Often asked
Why: Redis 6.2 unified range commands under ZRANGE, with REV for descending order. ZREVRANGE is deprecated but still works.
32How many hash slots does Redis Cluster use?Sometimes asked
Why: Redis Cluster splits the keyspace into 16384 hash slots, which are distributed across primaries.
33How does Redis store small sorted sets to save memory?Sometimes asked
Why: Small sorted sets use a compact listpack encoding and convert to a skiplist with a hash table once configured thresholds are exceeded.
Track your progress through every blueprint in your dashboard.
Start learning