Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Every number so far has been arithmetic, and arithmetic gives you a ceiling without telling you which ceiling you hit first. That ordering is the thing worth carrying out of this module, because it decides what you go and measure on a bad night. The same 32-core box with the same 25 Gbps card has at least four different ratings depending purely on what you ask it to do: it will echo small responses over warm connections at well over a million a second, proxy two-kilobyte cache hits at around one and a half million, serve a real JSON endpoint with three cache calls and a signature check at a couple of hundred thousand on paper and well under a hundred thousand in practice, and accept brand-new TLS connections at about fifty thousand. Those numbers span a factor of thirty on identical hardware. This is why a million requests a second is not one problem — it is somewhere between one box and twenty boxes and a genuinely hard research problem, and which of those you are facing is settled entirely by connection reuse, response size and what the request actually does. Once you know your row, you know your ceiling, and you know which counter to watch. That is the whole point of the napkin: not to be right, but to be specific enough to be proved wrong quickly.
Four jobs on one box. For each, compute all three ceilings — CPU, packets per second, bandwidth — and take the smallest, because the smallest is the only one you will ever meet. Then the diagram gives the order in which limits arrive as you raise them, and the commands tell you which one you are sitting on right now.
# ceiling.py — one box, four jobs, four completely different ceilings
BOX = ("1 socket, 32 physical cores, ~3 GHz sustained, "
"25 Gbps NIC with multiple queues, tuned kernel")
CORES, UTIL = 32, 0.60
NIC_GBPS = 25
KERNEL_MPPS = 8.0 # a tuned multi-queue kernel path. Stock, single
# queue, is closer to 1.5. Measure yours.
jobs = [
# name cpu_us pkts/req resp_bytes
("echo / static from page cache", 3, 4.5, 200),
("reverse proxy, keep-alive, cache hit", 12, 4.5, 2_048),
("JSON API, 3 Redis calls, JWT verify", 79, 4.5, 2_048),
("TLS handshake, ECDSA P-256, new conn", 400, 16.0, 5_000),
]
for name, cpu_us, ppr, resp in jobs:
cpu_ceiling = CORES * UTIL / (cpu_us / 1e6)
pps_ceiling = KERNEL_MPPS * 1e6 / ppr
bw_ceiling = NIC_GBPS * 1e9 / (resp * 8)
rps, bound = min((cpu_ceiling, "CPU"),
(pps_ceiling, "packets/s"),
(bw_ceiling, "bandwidth"))
print(f"{name:<40} {rps:>11,.0f} rps bound by {bound}")
# echo / static from page cache 1,777,778 rps bound by packets/s
# reverse proxy, keep-alive, cache hit 1,525,879 rps bound by bandwidth
# JSON API, 3 Redis calls, JWT verify 243,038 rps bound by CPU
# TLS handshake, ECDSA P-256, new conn 48,000 rps bound by CPU
# Apply the measured derate to the CPU-bound rows and you get the honest
# rating of one commodity box:
# trivial keep-alive work ......... 1 to 2 million rps
# a real JSON endpoint ............ 50,000 to 150,000 rps
# brand-new TLS connections ....... about 50,000 per second
#
# A million requests a second is therefore anywhere between one box and
# twenty boxes, depending entirely on which of those three you meant.openssl speed -elapsed ecdsap256 on your own box and read the sign/s figure — that is the server side of one handshake. Multiply by your core count for the whole-box ceiling, then compare it against the 2,500 per core per second the script assumes.KERNEL_MPPS from 8.0 to 1.5, which is roughly a stock single-queue receive path with no RSS, and re-run. Watch nearly every row become packet-bound. That one tunable is the difference between a box rated at 1.7 million and one rated at 330,000.wrk2 -R at that rate against one box for five minutes. If it holds with a stable p99, your arithmetic is calibrated. If it does not, run nstat -az before and after and find which counter moved — that names the ceiling the napkin missed.