A ticketing platform in the mould of Ticketmaster opens a major on-sale. After a prior outage 2 million signed-in users have lost their sessions, and 70% of them try to log in within 10 minutes. Passwords are hashed with Argon2id at 64 MiB memory, 3 passes, taking about 100 ms per hash on one core. Roughly how much capacity does the login tier need, and what would you change?
Show the full answer Hide the answer
The assumptions, stated
1.4 million attempts (70% of 2 million) over 600 seconds, spread evenly for now, with one hash per attempt and no retries. The hash costs 100 ms of CPU and 64 MiB of RAM per concurrent hash. Cores are 3 GHz class and hashing is the dominant cost per login.
The arithmetic
Average rate: 1,400,000 / 600 = 2,333 logins per second. CPU demand: 2,333 x 0.1 s = 233 core-seconds per second, so about 233 cores fully busy. Memory: each in-flight hash holds 64 MiB, and with 233 concurrent hashes that is 233 x 64 MiB = about 15 GB of RAM committed to hashing alone.
Real arrivals are not even. The first minute after the outage ends will take a peak of 3 to 5 times the average, so the peak is 700 to 1,200 cores and 45 to 75 GB of hashing memory for short bursts. Retries from failed attempts (users who mistype, or whose request times out and retries) can add 20 to 30%.
The number, with its range
Plan for roughly 300 cores sustained and a burst ceiling near 1,000 cores. The error is dominated by the peak factor, not the hash cost: a 2x error on arrival shape changes the answer more than a 30% change in hash time.
Which assumption dominates the error
Arrival burstiness, then retry behaviour. If the client retries on timeout without backoff, the login tier is in a feedback loop in which slow responses create more load.
What the number rules in and out
It rules out sizing the login service like an ordinary stateless API: a memory-hard hash makes every login expensive on purpose, which is what makes offline cracking slow, and it turns a login storm into a CPU storm.
Levers, in order of cost:
- Admission control and queueing with a bounded number of concurrent hashes per instance, returning "try again in N seconds" with jitter, rather than accepting every request and timing all of them out.
- Preserve sessions across incidents so users do not need to log in again: long-lived refresh tokens, and a session store that survives restarts, remove the demand at its source.
- Do not weaken the hash to cope (dropping to one pass or 8 MiB); that trades a capacity incident for a weaker credential store.
- Pre-warm capacity for known events (an on-sale is scheduled) and use waiting rooms.
When this arithmetic is unnecessary
For a service with a few hundred thousand users and no synchronised events, a normal fleet absorbs it. Do this sum where a shared event synchronises human behaviour: on-sales, product drops, payday, a post-outage return.
Common weak answers
- "Autoscale on CPU." Scale-out takes minutes and the burst lasts one.
- "Lower the work factor." It saves capacity by weakening the stored hashes.