The Runtime Theory
hardawesome-system-design#high-level-design#distributed-systems

Design Distributed ID Generator

Design a distributed unique ID generator using the Snowflake scheme — 41-bit timestamp, 10-bit machine id, 12-bit sequence — yielding 4096 IDs/ms/node with no coordination on the hot path.

The Runtime Theory Team2 min read
Solve it

solving happens on the judge — come back and mark it done

Sample cases

in1M IDs/sec sustained

out4096 IDs/ms/machine → ~245 machines at full tilt

in10K machines in the fleet

out10-bit machine id → max 1024; need 14 bits or per-DC ranges

inclock moves backward 5ms

outsequence stall: wait for clock catch-up, never reuse ids

inids must sort by time

outsnowflake is monotonic within a machine, roughly global

Many systems need unique, time-ordered, 64-bit ids with no database in the critical path — not sequential auto-increments (coordination bottleneck) and not full UUIDs (128 bits, not sortable). Snowflake answers: 64 bits = 41-bit timestamp (ms since epoch) + 10-bit machine id + 12-bit sequence.

Per machine, per millisecond, the 12-bit sequence gives 4096 ids — 4M ids/sec if the clock allows; 1M IDs/sec across ~245 machines at ~25% duty. The 41-bit timestamp covers ~69 years from an arbitrary epoch, so the machine id is the only externally assigned piece: it comes from a registry (ZooKeeper or a DB lease table) at boot.

Generator logic per request: read the current ms; if it matches the last ms, increment the sequence; on overflow, spin until the next ms. If the clock moved backward, the machine stalls — never emit an id from the past, or ordering breaks and ids collide with ones already handed out. The sequence resets to 0 when the ms advances.

Result: strictly increasing within a machine, approximately global, sortable by creation time, cheap — one clock read and a branch, no network call on the hot path. 64 bits fit a bigint, a Cassandra long, or an unsigned 64-bit Redis key.

The data model is trivial — the id is the product — but operational edge cases matter: clock skew breaks global ordering slightly (acceptable; consumers sort by id within a machine); machine-id exhaustion beyond 1024 machines (raise the machine field or per-datacenter ranges); id reuse after reassignment (never reuse; lease with TTL and tombstone). The only failure mode is clock discipline — NTP monitoring and the backward-clock stall are mandatory.

plaintext
ID request → generator:
  ms = now()
  if ms == last_ms: seq += 1          # 12 bits, max 4095
      if seq > 4095: spin until next ms
  else: last_ms, seq = ms, 0
  if ms < last_ms: stall until clock catches up
  return (ms - epoch) << 22 | machine_id << 12 | seq
Machine id ← ZooKeeper lease at boot (10 bits, max 1024 workers)

More practice in this topic

One dispatch a week

The trace behind each problem, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.