Dev Learning

Distributed counters

Counting is easy until everyone counts the same thing at once.

1

What problem does a sharded counter solve?

A view count, a like count, a rate meter. One row and an increment works fine, until thousands of writers hit the same row and all queue behind the same lock.

That row becomes a hot spot, and the fix depends entirely on whether the number has to be exact.

2

What a sharded counter costs you

What it costs you
Every technique here trades exactness or freshness for throughput. Sharded counters make reads more expensive, because you have to add the shards up. Approximate structures give you a number that is close but wrong. Batching in memory means losing the last few seconds of counts if a process dies. Pick which of those you can live with, and say so.

Every concept in here states a cost. A technique with no price is a technique you have not understood yet — and naming the cost out loud is most of what separates a senior answer from a junior one.

3

When to reach for a sharded counter, and when not to

Use it when

  • Any counter with many writers at once: views, likes, impressions, rate limits.
  • Analytics totals where a small error is invisible.
  • Counting distinct things over huge streams, like unique visitors, where being exact is not worth the memory.

Do not, when

  • The count is a resource people compete for: remaining seats, stock, an account balance. That is not a counter problem, it is a transaction problem, and approximation is not on the table.
  • Low write volume. One row and an increment is correct and simple.
4

How a sharded counter actually works

Single row — all writers queue on one lock~500/sec before it collapses
100 shard rows — contention divided~50,000/sec, reads sum 100 rows

The write problem became a read problem. That is the trade: reads now add up 100 rows, so cache the total and refresh it every few seconds.

One row versus 100 shards, same 50,000 increments a second.

Sharded counters are the standard answer. Instead of one row, keep N rows for the same logical counter, and have each writer increment a random one. Contention drops by roughly N. Reading means adding up N rows, which you then cache. So the number on screen is a couple of seconds old, which users cannot notice on a view count.

Write batching goes further. Each application server keeps a count in its own memory and flushes it every second or two as a single increment. A thousand increments become one write. The cost: if the process dies, you lose whatever it had not flushed. For view counts that is fine, but say it out loud rather than hoping nobody asks.

For counts over time windows, an approximate structure is often right. HyperLogLog estimates distinct counts, like unique visitors today, in about 12 KB with under 1% standard error, whether you saw a thousand items or a billion. A count-min sketch estimates how often each key appears, which is how you spot a hot key or an abusive caller without tracking every one of them.

The distinction that decides the design: is this number a display, or a decision? A like count is a display, so approximate and slightly old is correct engineering. Remaining tickets is a decision, and it must be exact at the moment you commit. That is enforced by a conditional update or a constraint, not by a counter you read and then trust. Treat stock as a counter and you will oversell.

There is a middle case worth knowing: something that is a decision, but not about one specific item, like a rate limit. There an approximate count is usually fine, because letting through 105 requests instead of 100 rarely matters. So you can shard or batch, as long as you choose which direction the error goes.

Common trap
  • Treating stock as a counter. It is a resource people compete for.
  • Adding up the shards on every request instead of caching the total.
  • Losing in-memory batches without ever admitting that it happens.
Say this
"View counts batch in memory per server, flush every second into one of 50 shard rows, and the displayed total is a cached sum refreshed every few seconds. Cost: the number is a couple of seconds old, and a crash loses under a second of counts. I would not use any of this for remaining tickets. That needs one row and a conditional update."
5

The a sharded counter follow-up an interviewer will ask

"Your view counter is a single row and a post goes viral. What happens?"

What a strong answer sounds like

Every increment for that post queues on one row lock. Throughput collapses to what one lock can process, latency climbs, and connections pile up waiting. And because those connections come from a shared pool, the damage spreads to endpoints that have nothing to do with view counts. So a hot row does not just make counting slow. It can take down neighbouring features. The fix is to stop making them compete. Batch increments in memory on each server and flush every second, and spread the stored counter over N shard rows so writers do not queue on one. Reads add up the shards and get cached for a few seconds. The costs are that the number can be a few seconds old, and that I lose unflushed counts if a server dies mid-flush. Both are entirely acceptable for views, and both are things I would refuse to accept for stock.

6

Your turn

60-second self-check

When is a sharded counter the wrong answer? Give the specific case.

Stuck? Take one hint at a time0 of 2 used
0 / 25 characters
7

Learn it from the source

This page gets you interview-ready. These take you to where the idea is actually specified or measured — read them when you want the real depth.

Where you will use this