Design ink.ly, Inkwell's URL shortener, in the spirit of bit.ly or t.co.
What it does
- Write: a user submits a long URL and gets back a new short code (e.g.
aB3xQ). About 1 write in 10 instead edits where an existing code points. - Read: a user opens a short code and is redirected to the long URL.
Workload
A constant 10 000 rps, 95% reads / 5% writes, over 20 seconds. The service already stores 100 000 short links when the run starts.
Popularity is heavily skewed (Zipfian): a handful of links get most of the clicks. A user who edits a link and then opens it must land on the new target (read-your-writes).
Global users
Users are spread across three regions and you can't move your origin closer to all of them at once:
| Region | Share | RTT to origin | RTT to nearest edge POP |
|---|---|---|---|
| us-east | 40% | ~10 ms | ~8 ms |
| eu-west | 30% | ~75 ms | ~14 ms |
| ap-southeast | 30% | ~220 ms | ~18 ms |
Tiers
An edge POP can answer a redirect it has cached without touching your origin, which is what makes it fast for distant users. Anything it can't answer (a cache miss, a new link, an edit) still travels to your origin and pays most of that distance. With a single origin, some requests from ap-southeast will always take 150 ms or more, so the tiers judge speed by the median (p50) and keep p99 as a sanity bound.
- Easy: stays up. 10 000 rps is more than the default app tier and database can absorb. Size them so almost nothing fails.
- Medium: correct reads. An owner who edits a link must land on the new target straight away; everyone else may see the old one for a few seconds, never more than 5. Watch for anything that can serve an old copy for longer: caches that aren't invalidated on edits, edges that keep a copy too long, writes acknowledged before they're durable.
- Hard: fast worldwide. Median latency under 40 ms for users on three continents, without losing medium's correctness.
Components you'll likely need
client: drives the workloadload_balancer: spreads requests across app replicasapp_server: application logic, routes reads and writes downstreamcache: fronts the store for hot readscdn: edge POPs close to usersrelational_dborkv_store: persistent storage. Every read is by code, so either fits; say why you'd pick oneid_generator: mints short codes for writes
Hints
- The catalog drag-and-drop palette is on the left.
- Connect components by dragging from one node's right edge to another's left edge.
- Use Validate to check graph constraints before running.
- The tier panel below the canvas shows which tiers passed after each run.