Design the like counter for Inkwell's posts, the kind every social app needs.
What it does
- Write (
like): a user likes a post. The like must be recorded durably. The app shows your own like on your screen straight away, so the server's job is to keep everyone else's count close behind. - Read (
get_count): a user opens a post and sees its current like count.
Workload
A constant 30 000 rps, 80% reads / 20% writes, over 20 seconds, against 1 000 000 posts that already exist.
The key distribution is extremely skewed (Zipfian, high skew). A few viral posts get most of the traffic, both reads and likes: the hottest post alone takes roughly a third of all likes, around 2 000 per second. Most posts are barely touched.
Global users
Users are spread across four regions: us-east (30%), eu-west (25%), ap-southeast (25%), sa-east (20%). RTT to origin ranges from ~10 ms (us-east) to ~220 ms (ap-southeast); RTT to the nearest CDN edge POP is 8 to 22 ms everywhere. Without an edge in front of your origin, every read pays the full distance. Likes themselves always travel to your origin.
Tiers
- Easy: survives the viral post. Every like on a post updates the same counter. One row, or one key, takes its writes one after another: a relational row about 750 a second, a key-value item about 1 000. Two thousand a second needs the counter split.
- Medium: counts you can trust. A count may be a little behind, but never far: under 0.5% of reads may return a count more than 100 ms out of date. A counter that changes every few milliseconds drifts fast on any copy that lags behind the primary.
- Hard: fast worldwide. Median latency under 65 ms across four regions, with medium's guarantee intact. On a post liked every 2 ms, a purge lands before almost any edge fill completes, so purging on every like leaves the edge empty. And a TTL much shorter than the trip to your servers leaves most reads waiting for the edge to fetch again.
Components you'll likely need
client: drives the workloadload_balancer: spreads requests across app replicasapp_server: application logiccacheandcdn: keep hot counts close to the app and to usersrelational_dborkv_store: storage. Neither takes 2 000 writes a second on one record; the KV store can split a hot key into sub-counters
Hints
kv_storeexposes adefault_consistencyknob (eventual or strong), per-partition throughput, and sub-counters per hot key for keys below a threshold: writes spread over the sub-counters, and every read adds them all up.cdnhas anon_writesetting:purgedrops the cached copy on every write (at the writer's edge at once, at the other regions' edges about a second later),ttl_onlykeeps serving it untilttl_msruns out, so the TTL bounds how far behind it can get.- The tier panel below the canvas shows which tiers passed after each run.