Section 3: Two Numbers, Four Orders of Magnitude Apart - Scale Estimation & Workload Analysis
Executive Summary: This section does the arithmetic every later section cites. We derive one property from scratch — 220 rooms to 0.00076 booking writes per second and 0.76 peak search QPS — and find that a beachfront hotel's entire reservation system is one PostgreSQL instance with nothing bolted to it. Then we scale to Marriott: 174 million bookings a year, peaking at 28 writes per second, which a laptop absorbs. The number that re-architects the system arrives last: 6,300 inventory cells per city search at 4,100 peak searches per second is 25.8 million cell reads per second. Writes here are precious but rare; reads are cheap but astronomical, and designing for the wrong one is how this interview is lost.
Section 2 ended with a contract full of promises: 300 ms search, 99.99% on the booking path, never oversell. Promises are free. The interviewer uncaps their marker and asks the question that prices them:
"Before you draw anything — how big is this?"
Most candidates answer "big" and start drawing. You are going to answer with a chain of multiplications, out loud, and let the result tell you what you are allowed to build. The discipline matters more than the digits: a number you derive is a number you can be held to, and that is the only thing able to forbid a component.
Stage A: One Hotel, Derived From Nothing
The Marlin Bay Miami is 120 Standard King, 60 Double Queen, 30 Ocean-View Suite and 10 Accessible rooms — 220 rooms, and critically only four sellable products, because Section 1 established that a hotel sells fungible room types rather than named rooms. Everything else follows from those two facts and a 365-day booking horizon.
| Step | Arithmetic | Result |
|---|---|---|
| Inventory cells | 4 room types x 365 dates | 1,460 rows |
| Rejected alternative (D1) | 220 physical rooms x 365 dates | 80,300 rows |
| Room-nights available / yr | 220 x 365 | 80,300 |
| Room-nights sold / yr | x 75% annualised occupancy | 60,225 |
| Bookings / yr | 60,225 / 2.5 nights average stay | 24,090 |
| Bookings / day | 24,090 / 365 | 66 |
| Booking writes / sec, average | 66 / 86,400 | 0.00076/s (~1 every 22 minutes) |
| Booking writes / sec, peak | 10x, concentrated in the evenings | 0.008/s (~1 every 2 minutes) |
| Searches / day | 66 x 100 look-to-book | 6,600 |
| Search QPS, average | 6,600 / 86,400 | 0.076 QPS |
| Search QPS, peak | 10x | 0.76 QPS |
Storage closes the case. A booking record — guest, dates, rate, payment-provider token, audit trail — runs about 2 KB, so 24,090 bookings is 48 MB a year, and the seven-year retention tax and legal require is about 340 MB. The inventory table, 1,460 rows at 200 bytes, is 292 KB. Not 292 MB. A beachfront hotel's entire sellable availability for a year is smaller than a phone photo.
Key Insight: Under 1 QPS, under half a gigabyte, forever — one sentence that is a licence to delete components. One managed PostgreSQL instance with a synchronous standby runs this property: no cache, because 0.76 peak QPS reads from a buffer pool holding all 292 KB of inventory; no search index, because there are four room types; no queue in the commit path; no shards, because 340 MB will not outgrow a laptop in a decade; no second region, because if Miami is underwater the hotel is closed too.
"But what about Black Friday? Spring break?" Multiply by ten and you get 0.008 writes per second; multiply by a hundred and you still have not reached one per second. Say the uncomfortable thing plainly: at one property, every piece of machinery you want to add must now argue with a number, and it will lose. That is not an argument for sloppiness — it is Decision D3, PostgreSQL on a single primary, with its rejected alternatives named: DynamoDB, because the core operation is an atomic conditional decrement across N date rows, which Postgres gives free and Dynamo needs TransactWriteItems for; Cassandra, because last-write-wins on a counter is the double-booking bug. Flip trigger: roughly 50,000 booking writes per second, or genuine multi-region active-active writes for one property. Neither is coming.
Quick check before moving on:
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson