System Design

Design Shared Counter

Global view/like counters — sharding, aggregation, and read-your-writes at billions of events/day.

Interview tip Separate hot counter shards from periodic flush to DB. Mention local aggregation, Redis INCR, and handling counter rebuild after loss.

① Functional requirements

  • increment(entity_id) — add 1 or N
  • get_count(entity_id) — current total
  • batch_get(entity_ids[]) — mget counts
  • Optional decrement for unlike
  • Admin reset / adjust count

② Non-functional requirements

  • 1M increments/sec peak
  • get p99 < 10ms
  • Counts accurate within 1% or flush every few seconds
  • Horizontally scalable
  • Survive Redis node loss without permanent drift

③ Back-of-the-envelope scale

Assumptions
  • 100B/day ≈ 1.2M incr/sec average; 3× peak → ~4M/sec
  • 1B entities — most cold, top 1% hot
  • Batch flush every 5s reduces DB writes 100×
  • 100 counter shards × Redis cluster

④ High-level architecture

Counter Service
Clients
Counter API
Redis shards (INCR)
Flush workers → DB
Read cache / CDN edge
increment always hits Redis shard. Periodic flush merges shard delta into Cassandra/DB. Cold entities read from DB + cache.

⑤ Data flow & execution path

Increment path
① INCR shard② Async flush③ Merge DB total④ Read cache
Hot path: Redis INCR only — no DB on write
Flush: shard delta + persisted_total
Read: Redis + DB persisted + delta
Rebuild: replay increment log if Redis lost
Clarify acceptable staleness on read vs write cost. Viral video = hot key — local aggregator on API nodes.

⑥ API & interfaces

Endpoint / flowPurposeNotes
POST /v1/incr/{id}Incrementreturns new approximate count
GET /v1/count/{id}Read countcache-aside
POST /v1/mgetBatch readparallel shard fetch

⑦ Data model & storage

Redis: counter_key → integer delta. DB: entity_id → persisted_total, flushed_at. Optional Kafka log for replay.
StoreWhatWhy
Redis clusterHot countersINCR atomic
CassandraPersisted totalsWide-column per entity
KafkaIncrement logReplay and analytics

⑧ Deep dive — core components

Hot key mitigation

Per-API-node local buffer aggregates 1000 increments before single INCR. Risk brief loss on crash — acceptable for views. Or replicate hot key across nodes with periodic merge.

Accuracy vs cost

Flush every 5s: reads may lag few seconds. For likes show exact — shorter flush or read from Redis primary only.

⑨ Trade-offs & alternatives

DecisionOption AOption BPick when
StoreRedis + DBDB onlyRedis for speed; DB for durability
FlushTime-basedThreshold-basedTime simpler; threshold fewer writes for cold keys
Hot keyLocal aggregateKey replicateLocal aggregate lower Redis load
AccuracyStrongEventualViews tolerate eventual; payments need strong

⑩ 45-minute interview script

  1. 0–5 min: incr/get requirements
  2. 5–10 min: Scale math
  3. 10–20 min: Redis shard + flush
  4. 20–30 min: Hot key and accuracy
  5. 30–38 min: Failure recovery

⑪ Likely follow-up questions

QuestionShort answer
Unique viewer vs raw views?Separate dedupe set (HyperLogLog or bloom) for unique; raw incr for total views
Global vs per-region counts?Regional shards + periodic merge to global aggregate for display
Counter reset attack?Rate limit incr per IP/user; cap velocity; anomaly detection on spikes

⑫ Revision checklist

  • Redis INCR sharding
  • Periodic DB flush
  • Hot key local aggregation
  • Kafka replay log
  • batch_get parallel
  • Read merge persisted + delta
  • Monitoring shard balance
  • Rate limit abusive incr
counterredishot-keyaggregationscale