Classic design · Mid
Distributed counter (celebrity likes and views)
Classic interview design. Key points: hot key and sharded counters, and job scheduling.
Short answer
Classic interview design. Key points: hot key and sharded counters, and job scheduling. A post's like counter is the example Firestore's own documentation uses for documents that work as counters, alongside an item's favorites.
01 · THE PROBLEM
A number everyone increments
A post's like counter is the example Firestore's own documentation uses for documents that work as counters, alongside an item's favorites.
The limit shows up when the counter is a single document. In Firestore you cannot update a single document at an unlimited rate and, with frequent enough increments, contention arises on that document's updates.
Each like reaches the likes API.
The API increments a single document, which holds the counter's value.
When the increments become frequent enough, updates to that document start competing with each other.
Under high, sustained volume of concurrent operations, the single document can become a hot spot.
The scaling documentation describes the same hot spot: high, sustained volumes of concurrent operations on a single document can cause a hot spot on it, and the recommendation is to change the data model to split or replicate the data across multiple documents.
02 · SHARDING THE COUNTER
Many documents, one sum
The documentation's solution is the distributed counter: each counter is a document with a subcollection of shards, and the counter's value is the sum of the shards' values. It is the idea of sharding the write applied to a single number.
Each like reaches the likes API, as before.
To record the like, the API picks a random shard and increments only that one.
The next like picks another shard, and the writes are spread across different documents.
The counter's value is the sum of the shards' values.
Write throughput grows linearly with the number of shards.
To increment, a random shard is chosen. Write throughput grows linearly with the number of shards: a distributed counter with 10 shards supports 10 times more writes than a traditional counter. In the documentation's code example, each shard can be incremented once per second, which is why several shards are needed to allow more frequent increments.
03 · THE PRICE OF READING
Sharding pushes the cost onto the reader
The documentation points out the cost of the number of shards. With few shards, some transactions have to retry before succeeding and writes get slower; with too many shards, reads get slower and more expensive.
Reading the value costs more with each added shard: read cost grows linearly with the number of shards, because the entire subcollection of shards has to be loaded.
In practice, this becomes a sizing question: how much write traffic the counter gets and how much it is read.
04 · CONSOLIDATED TOTAL AND JOBS
Reading a ready-made number
One way to offset the read cost is to keep the total in a separate total document, updated at a slower cadence, and have clients read that document. The tradeoff is that clients have to wait for that document to be updated, instead of computing the total by reading all the shards right after each update.
Likes keep going to the shards, as before.
Reading the value by summing the shards requires loading the whole subcollection, and the cost grows linearly with their number.
The total document is updated at a slower cadence than the writes; in this design, the consolidation job does that.
Clients read the total from that document, instead of summing the shards.
The tradeoff is waiting for the total document to be updated, instead of computing the total right after each update.
| Aspecto | Sum of the shards | Total document |
|---|---|---|
| How the value is obtained | Sum of all shards on every query | The client reads the total document |
| Read cost | Grows linearly with the number of shards | Offsets the read cost of the shards |
| Total freshness | Computed right after each update | The client waits for the total document to be updated |
A scheduled job is a natural way to implement this slower cadence. The interval between runs is a product decision: how stale the number can appear to the reader. The total now converges to the sum of the shards with a delay, a typical tradeoff of eventual consistency.
05 · ALTERNATIVES AND WRAP-UP
Shard, replicate, or increment in memory
Firestore in Datastore mode documentation points to two ways out: use sharding or replication to handle hot spots. Replication keeps N copies of the same entity and allows a read rate N times higher; sharding is for writing at a higher rate and breaks the entity into smaller pieces.
Outside Firestore, the Redis counter pattern uses atomic increment operations: the idea is to send an INCR command to Redis on every operation.
Frequently asked questions
What is Distributed counter (celebrity likes and views)?
Classic interview design. Key points: hot key and sharded counters, and job scheduling.
What does the Distributed counter (celebrity likes and views) design cover?
It is organized in these sections: A number everyone increments, Many documents, one sum, Sharding pushes the cost onto the reader, Reading a ready-made number, and Shard, replicate, or increment in memory.
How long is Distributed counter (celebrity likes and views) and what level is it?
It takes about 14 minutes to read and is rated Mid level.
Now design it yourself
Run this case as an interview in the System Design school: you make the decisions, the tutor challenges them and you see how your design scores.