Design a Likes Counter
A likes counter is a number that shows how many people have liked one post, photo, or video. The number must update fast under a flood of likes and must never count one person's like twice.
The ask
A likes counter shows the total likes on one item and updates it as people like and unlike. Readers check the number constantly, and writers change it constantly.
One person holds at most one like on one item. Tapping like twice can never make one person's support count double.
The displayed number may lag a few seconds behind the truth. A displayed number that double-counts or loses likes is never acceptable.
Most items collect likes slowly. One viral item can collect them faster than a single counter can accept.
Estimate the scale
Likes across the service run at 1,000,000,000 a day. The load spreads over millions of items.
1,000,000,000 likes / 86,400 seconds = 11,574 likes per second.
The hard case is concentration, not the average. One viral post takes 1,000,000 likes in its first hour.
1,000,000 likes / 3,600 seconds = about 278 likes per second on one counter.
A single counter record updated by every liker becomes a queue of writers on one row. That one row is the bottleneck the design must remove.
API and data
Like takes a person ID and an item ID. It records the like and raises the count only when no like record exists yet.
Unlike takes the same two IDs. It removes the like record and lowers the count only when a record exists.
Get count takes an item ID. It returns the displayed total, served from a cache whenever possible.
A like record holds the person, the item, and the time. The record is the truth, and the counter is a fast summary of the records.
The pair of person and item is unique in the like store. The uniqueness rule itself blocks double likes at the storage layer.
High-level design
A like first writes its like record. Only a successful new record sends an increment to the counter.
Increments travel through a queue to the counter shards. A bursty minute queues briefly instead of crushing the counter.
The counter for each item is a sharded counter. Its total is split across shards, and each shard absorbs part of the write flow.
Reads sum the shards and cache the result for a few seconds. Readers see a near-live number without paying a full sum per view.
Quiet items keep the same shape with less work. Their shard sums are tiny and their cached counts stay valid longer.
Deep dive: the hot counter
A sharded counter splits one total across many small counters. Each increment lands on one shard, chosen in turn, so no single shard takes the whole flood.
The counter is sharded 100 ways. The sharded-counter design figure gives each shard 1,000 increments per second of capacity.
100 shards x 1,000 increments per second = 100,000 increments per second of capacity.
The viral post needs about 278 increments per second. The sharded design holds that rate with huge headroom.
The trade sits on the read side. One exact read must sum every shard the counter owns.
One counter read = 100 shard reads.
Caching pays that read cost once for many viewers. The design accepts a display a few seconds stale in exchange.
Keeping the count honest
Retries after a like must not double-count. The unique like record settles the question before any increment is sent.
An increment lost in a crash leaves the counter below the truth. The like records still hold the real state.
A background recount compares counters against the like records. Drift is corrected from the records, shard by shard.
Unlike follows the mirror path. A removed record sends one decrement, and a repeated unlike sends nothing.
Deleted items keep their counts frozen. The records stay for audit, and no new increments are accepted.
When parts fail
A failed counter shard freezes its share of the total. The displayed count dips below the truth until the shard returns or is recounted.
A failed queue delays increments, never likes. The like records are written first, so delayed counts catch up from the queue.
A cache failure pushes reads to the shard sums. Reads slow down, and the numbers stay correct.
Evaluation and trade-offs
Sharding trades read cost for write survival. One hot item takes 100,000 increments per second of capacity, and each exact read pays 100 shard reads.
The like record trades a storage write for honesty. Every like is provable, and every counter can be rebuilt from records.
A slightly stale display trades freshness for calm reads. The count is a social signal, so seconds of lag cost nothing real.
The design fits because the truth and the summary have separate jobs. Records guard correctness, and shards guard speed.
Scale of the counter
| Work | Count | Rate |
|---|---|---|
| Likes, whole service | 1,000,000,000 a day | 11,574 per second |
| Likes, one viral post | 1,000,000 in one hour | about 278 per second |
| Counter shards | 100 | 100,000 per second capacity |
Exercise
A person taps like, then unlike, then like again. What should the counter do?