Design Sharded Counters
A sharded counter is a counter split across many small counters, so no single counter takes every increment. A read adds the small counters together to give the total.
The ask
One counter can become very hot. A view count or a like count on a viral item takes increments from everyone at once. All those increments aim at a single number.
Increments must not be lost. Two increments arriving together must both count. A counter that drops updates under load is worse than a slow one.
Reads want the exact total. The total may lag reality by a moment. It may never invent increments or double-count them.
Most counters stay cold. The design spends shards only where heat exists. A quiet counter keeps one shard and one cheap read.
Estimate the scale
One hot counter takes 100,000 increments per second.
One shard absorbs 1,000 increments per second. A shard is one stored value that can be updated safely at that pace. Beyond it, updates queue and collide.
100,000 increments per second / 1,000 per shard = 100 shards for the hot counter.
Reads are far rarer than increments on the hot counter. People glance at the total while crowds press the button. The design therefore spends cost on reads to save the writes.
API and data
Increment takes a counter name and an amount, usually one. The call returns as soon as one shard has stored the increment. Read takes a counter name and returns the current total.
A shard record holds the counter name, the shard number and the shard's own running total. Each shard record lives on a different machine where possible. Spread keeps one machine's failure from taking many shards.
The counter's directory lists how many shards it has and where they live. Increment and read both start from the directory. Changing the shard count updates one directory entry.
Amounts can be negative for corrections. A shard total is just a number that moves up or down. The summing read treats every shard the same way.
High-level design
An increment arrives at a front door that knows the counter's shard count. The front door picks one shard and adds the amount there. Only that shard is touched.
Shard choice is random for a shared hot counter. Random choice spreads a crowd evenly. Hashing by writer would let one heavy writer heat one shard again.
Each shard is copied to a second machine. The copy receives every increment the shard accepts. A read can fall back to the copy when the main shard is down.
A read asks every shard for its total and adds the answers. The sum is the counter's value at that moment. New increments landing during the read belong to the next read.
Splitting the writes
A single stored value serialises its updates. Every increment waits for the one before it. At 1,000 updates per second that queue is the ceiling.
One hundred shards give one hundred independent queues. Each runs at its own safe pace. The counter's ceiling becomes the sum of the shard ceilings.
Ten shards would carry 10,000 increments per second. That covers a warm counter. Shard counts are set per counter from measured heat, not one global value.
Splitting works because increments commute. Adding one then two gives the same total as two then one. Order between shards never changes the sum.
Reading the total
An exact read of the worked counter costs 100 shard reads. One read per shard, then one addition. Read cost grows exactly with write capacity.
A cached total softens frequent reading. A refresher sums the shards once per second and serves readers the stored sum. The refresher pays 100 shard reads per second, and readers pay nothing per read.
The cached total can lag by up to the refresh gap plus the summing time. Counters that drive money or safety skip the cache. Display counters accept the small lag.
A failed shard blocks an exact sum. The read then uses the shard's copy. A sum missing a shard is never served as exact, since a partial sum silently lies.
Deep dive: the counter gets hotter
Heat can double without warning. A counter at 100,000 increments per second can jump to 200,000 when a bigger crowd arrives. Shards already at their ceiling start dropping pace.
200,000 increments per second / 1,000 per shard = 200 shards. The response is to grow the shard set, not to push shards harder.
Growing is gentle because old shards keep their totals. The directory starts listing 200 shards. New increments spread across all of them, and reads sum all of them.
No data moves during growth. The old totals stay where they are and stay part of every sum. Only the choice of target shards changes.
The read cost grows with the rescue. An exact read now costs 200 shard reads. The cached total matters more as heat rises, and its refresher pays the larger sum once per second.
Evaluation and trade-offs
Sharding trades read cost for write capacity. That trade wins when increments hugely outnumber reads. It loses for counters read as often as they change.
The sum stays exact. Nothing is estimated or sampled. Accuracy is kept, and the price is paid in shard reads instead.
One counter is easy, and a platform holds many. Per-counter shard counts keep cold counters cheap. Heat decides spending, counter by counter.
A single global counter across everything would need the same trick at larger scale. The pattern repeats per counter rather than growing one monster counter. Each hot name gets its own shards.
Shards, capacity and read cost
| Shards | Increments per second | Shard reads per exact total |
|---|---|---|
| 1 | 1,000 | 1 |
| 10 | 10,000 | 10 |
| 100 | 100,000 | 100 |
Exercise
A hot counter takes 100,000 increments per second, and one shard absorbs 1,000 increments per second. How many shards does the counter need?