Solutions · Leaderboards & rate-limit
Sorted sets, atomic counters, and a Lua script for the tricky bits.
Realtime leaderboards with `ZADD` / `ZRANGE` and per-key rate-limits with `INCR` / `EXPIRE` — running on the same managed Redis that handles your sessions.
Two primitives, a lot of features
Sorted sets and counters cover most of what real-time applications need. A leaderboard is `ZADD scores user_id score` to update and `ZREVRANGE scores 0 9` to read the top 10 — both O(log N) on Redis. Rate-limiting is `INCR ratelimit:<key>` plus `EXPIRE` on first write. For atomic token-bucket logic we ship a Lua script you can run server-side.
Sorted sets
Atomic counters
Lua server-side
Streams for events
Code sample
-- KEYS[1]: the rate-limit key
-- ARGV[1]: emission interval in milliseconds (e.g. 200 = 5 req/s)
-- ARGV[2]: burst tolerance in milliseconds (e.g. 1000 = burst of 5)
-- Returns: 1 if allowed, 0 if rate-limited.
local now = redis.call('TIME')
local now_ms = tonumber(now[1]) * 1000 + math.floor(tonumber(now[2]) / 1000)
local emission_interval = tonumber(ARGV[1])
local burst = tonumber(ARGV[2])
local last = tonumber(redis.call('GET', KEYS[1])) or 0
local tat = math.max(last, now_ms)
local allow_at = tat - burst
if now_ms < allow_at then
return 0
end
redis.call('SET', KEYS[1], tat + emission_interval, 'PX', burst + emission_interval)
return 1Leaderboard sketch
For a daily-reset global leaderboard with millions of users: use one sorted set per day (`lb:2026-05-26`) so reads are bounded by that day's active users, not your whole user base. Schedule a daily job to drop yesterday's key. Compute the all-time top with a periodic job that merges day-sets via `ZUNIONSTORE`.
Examples
- Game leaderboards — daily, weekly, all-time
- Real-time auction bids — top-N bidders, atomic update on each bid
- API rate-limiting — per-IP, per-API-key, per-tenant
- Concurrent-job limiter — at most N background jobs running per tenant
- Trending content — sorted set keyed by decayed score
Frequently asked questions
Is `INCR` really safe under concurrency?
How do I avoid hot-key contention on rate-limits?
When should I switch to Streams instead of sorted sets?
Leaderboards in three commands, rate-limits in one Lua script.
256 MB free Redis handles tens of thousands of concurrent leaderboard entries.