Skip to content

Redis INCR vs KGS

Two approaches that eliminate collisions entirely

Both Redis INCR and the pre-generated key pool solve the collision problem completely. Neither needs a collision check. Neither needs retries. But they have very different trade-offs — and only one is right for a public URL shortener.


Option 1 — Redis INCR counter

Instead of generating random codes and checking for collisions, use Redis as a distributed counter. Every creation request increments the counter and base62-encodes the result.

Creation request arrives
→ Redis: INCR url_counter → returns 1000000 (unique, atomic, guaranteed)
→ Base62 encode 1000000:

  1000000 in base62:
  1000000 ÷ 62 = 16129 remainder 22  → 'M'
  16129   ÷ 62 = 260   remainder 9   → '9'
  260     ÷ 62 = 4     remainder 12  → 'C'
  4       ÷ 62 = 0     remainder 4   → '4'

  Result: "4C9M" → pad to 6 chars → "004C9M"

→ INSERT into DB with short_code = "004C9M"
→ Done. Zero collision check. Zero retry.

Why it works:

Redis is single-threaded. INCR is atomic — it increments and returns the new value in a single operation. Two simultaneous calls always get different values. One gets 1000000, the other gets 1000001. No race condition possible.

App server 1: INCR → 1000000
App server 2: INCR → 1000001   ← different value, guaranteed
App server 3: INCR → 1000002   ← different value, guaranteed

Every counter value is unique by definition. Encoding a unique number always produces a unique code.

Why it looks attractive:

No KGS. No pre-generated pool. No background worker to operate. No pool size monitoring. One Redis command and you have a unique short code. It is significantly simpler than the KGS approach.


Why Option 1 gets rejected

Problem 1 — Codes are predictable and enumerable.

Counter values are sequential. If a user receives bit.ly/004C9M, they know the previous URL was bit.ly/004C9L and the next will be bit.ly/004C9N. They can walk through the entire sequence and enumerate every URL in the system.

User gets:  bit.ly/004C9M
They try:   bit.ly/004C9L → someone else's URL ← exposed
            bit.ly/004C9K → someone else's URL ← exposed
            bit.ly/004C9J → someone else's URL ← exposed

For a public URL shortener, users expect privacy. A user who shortens a document link, an internal dashboard, or a pre-announcement page does not expect anyone to discover it by incrementing a counter. Sequential codes make every URL in the system discoverable by any user.

Random codes (KGS approach) have no this problem — knowing one code tells you nothing about any other code.

Problem 2 — Redis is now a hard SPOF for creation.

With the INCR approach, every single creation request needs Redis to be alive. If Redis goes down:

Redis down
→ INCR fails
→ No counter value available
→ Creation fails immediately
→ Zero fallback

With the KGS + pool approach, app servers hold a local batch of 100 pre-fetched keys. Redis going down does not immediately stop creation — app servers drain their local batch first, buying time:

Redis down
→ App servers use local batch (100 keys each, 20 servers = 2000 keys)
→ At 1k creations/sec → ~2 seconds of local runway
→ Plus Redis circuit breaker kicks in
→ Graceful degradation instead of hard failure

The pool approach treats Redis as a supply chain, not a live dependency. The INCR approach makes Redis a hard blocker on every single creation request.


Option 2 — Pre-generated key pool + KGS (the right approach)

The KGS generates keys sequentially (same uniqueness guarantee as INCR, same base62 math), stores them in a Redis pool in advance, and app servers LPOP keys on demand.

Creation request arrives
→ App server pops key from local batch (pre-fetched from Redis pool)
→ INSERT into DB
→ Done. Zero Redis call on hot path. Zero collision check. Zero retry.

What it fixes:

Predictability:  KGS generates sequential codes internally but shuffles
                 the pool — or generates in random order — before pushing
                 to Redis. Codes handed to users are not sequential.

Redis SPOF:      App servers pre-fetch 100 keys locally. Redis down
                 → local batch still works → graceful degradation.

Simplicity cost: KGS is a 50-line background worker. Monitoring pool
                 size is one metric. The operational overhead is minimal.

Side by side

Redis INCR KGS + Pool
Collision checks None None
Code predictability Sequential — enumerable Random — private
Redis failure impact Creation fails instantly Local batch buys time
Operational complexity Very simple Small background worker
Right for Internal tools, no privacy concern Public URL shortener

Interview framing

"Redis INCR is a clean approach — atomic, no collisions, no KGS needed. But two problems: codes are sequential and enumerable (privacy violation for a public shortener), and Redis is a hard SPOF on every creation. KGS + pool solves both — random code order from the pool, and app servers pre-fetch locally so Redis failure doesn't immediately break creation. For a public URL shortener, KGS wins."