What they're testing
Whether you clarify requirements and estimate numbers before drawing boxes.
The short answer~30 seconds
I start with numbers: say 100M new links a month with a 100:1 read/write ratio, which is roughly 40 writes/sec and 4,000 reads/sec. That's a read-dominated system, so a cache in front of the store absorbs most of it. Keys are 7-character base62 for 3.5 trillion combinations; generated from a distributed counter encoded in base62 rather than a hash, because hashing needs collision handling and a counter doesn't. Store it in a key-value store, and redirect with 301 or 302 depending on whether you need click analytics.
The long answer
The 301-versus-302 choice is a small detail interviewers love, because it shows you think about consequences. 301 is permanent, so browsers cache it and subsequent clicks never reach your server — fast and cheap, but you lose analytics and can't change the target. 302 routes every click through you — countable, changeable, and more expensive. If the product sells analytics, the choice makes itself.
On key generation, the counter approach has a problem: sequential keys are guessable, so anyone can enumerate every link you host. The common remedy is having each node reserve a RANGE (say a thousand at a time) from an allocator and then permute bits within it — still collision-free, no longer consecutive. If you need genuine unguessability, use random keys and accept a collision check.
The most-skipped part is hot links. The click distribution is extremely skewed: one viral link takes most of the traffic for a few hours. So an LRU cache is fine, but you must think about hot keys in a distributed cache — a single key concentrating on one Redis shard. The remedies are replicating hot keys across shards, or a short-TTL in-process cache layer above it.
What they'll ask next
?What about custom aliases?
It turns the problem contentious: two people request /sale simultaneously. You need a UNIQUE constraint in the store and a 409 for the loser — a check-then-write is a race.
?How do you expire links?
Don't run a table-scanning job. Store expires_at, check on read — an expired link returns 410 — and reclaim in the background by time partition. In Redis, TTL does it for you.
These lose points
- Drawing architecture before asking about scale. A thousand links a day and a billion a day are different systems.
- Truncating an MD5 for the key without addressing collisions. Truncated hashes collide far sooner than intuition suggests.