Approach 2: Database Auto-Increment
In one line: this approach fails in a specific, instructive way. Working through exactly how it breaks is more valuable than the approach itself, because the failure is a general lesson about schemes that depend on the node count.
The naive version
The potential problem: this design introduces a single point of failure. Dependence on a single database increases system risk and reduces availability — if the central database becomes unavailable, the entire system may become unavailable.
That is a serious failure mode: the ID generator sits in front of every write in the system, so its availability is an upper bound on everything.
The increment-by-m fix
To avoid the SPOF, modify the standard auto-increment. Instead of incrementing by one, use m database servers. Each server generates an ID and increments the next value by m — the number of servers.
m = 3 Server A: 1, 4, 7, 10, ... Server B: 2, 5, 8, 11, ... Server C: 3, 6, 9, 12, ...
Each server walks its own residue class, so no two servers can produce the same value. Uniqueness holds as long as m stays fixed.
Pro: this approach is scalable — as we add more servers, we update the value of m accordingly.
The single-node version of this that people actually ship
Before leaving counters, it is worth naming the implementation this usually becomes in practice, because an interviewer may expect it: a single-threaded in-memory store with an atomic increment — Redis and its INCR being the canonical choice.
It works for the same reason the database counter works and is much faster: one process, one command at a time, so two concurrent callers cannot receive the same value. If one gets 1000 the other gets 1001, with no locking to reason about.
It has the same shape of weakness, though, and the comparison is the point. It is still one authority, so it is still a single point of failure and still a round trip per ID. What it improves is the constant factor, not the structure — which is why the next lesson's move, amortising the coordination across a whole block, matters more than making the coordinator faster.
There is also a durability wrinkle specific to an in-memory counter: if it restarts and comes back with a stale value, it reissues identifiers it has already handed out. Persisting the counter, or advancing it in blocks so a restart resumes past anything issued, is what makes it safe.
How it breaks
Scaling across multiple data centers is difficult. Adding or removing servers causes ID misalignment and potential duplicates.
The concrete example is worth walking carefully:
m = 3 Server A generates 1, 4, 7 Server B generates 2, 5, 8 Server C generates 3, 6, 9 Server B fails. Update m to 2. Server A's next ID = 7 + 2 = 9 But Server C has ALREADY generated 9. Uniqueness is lost.
This is the same failure as hash mod n
The scheme depends on m — the node count — being part of the ID-generation formula. Change the membership and every server's future sequence shifts, colliding with values already issued.
That is structurally identical to hash(key) % m partitioning from the Databases and Key-Value Store chapters. Any scheme whose correctness depends on the current node count breaks when membership changes — and membership always changes.
Recognizing that pattern across three different problems is exactly the kind of transfer an interviewer is testing for.
This solution is risky because a unique ID system must not be a SPOF and must maintain strict uniqueness while scaling.
Scorecard
| Unique | Scalable | Available | 64-bit numeric ID | |
|---|---|---|---|---|
| Using UUID | ||||
| Using database servers |
It fixes the size problem — these are compact numeric IDs — and it still fails uniqueness, for a completely different reason than UUIDs did. UUIDs fail probabilistically; this fails deterministically the moment you scale.
Key takeaway
Making the ID depend on the number of servers means membership changes become correctness bugs. What you actually want is a scheme where each server owns something that stays valid regardless of how many peers exist — which is the next approach.
Interview signal by level
| Level | What a strong answer sounds like |
|---|---|
| L4 | "Use a database with auto-increment." |
| L5 | Spots the SPOF: "one database in front of every write is a single point of failure — I'd shard it with increment-by-m." |
| Staff+ | Kills increment-by-m too: "that breaks when m changes — a failed server shifts the stride and collides with IDs already issued. It's the same trap as hash mod n. I want each generator to own something that stays valid independent of the peer count." |
Next: the approach that actually satisfies all four.