Before you choose between one server and fifty, you need to know roughly how much work there is. Not exactly. Roughly. Is it 10 requests a second, or 10,000? A gigabyte of data a year, or a terabyte a day? Those answers lead to completely different designs.
The tool for this is back-of-the-envelope estimation: quick, rough maths with round numbers, done in a few minutes. Its job is to tell you the size of the problem, so you neither build a spaceship for a bicycle ride nor a bicycle for a trip to the moon.
In this lesson we'll estimate Tiffin's load properly: requests, data and bandwidth.
Rules for rough maths
A few habits make estimation fast and good enough:
- Round aggressively. A day has 86,400 seconds. Call it 100,000. You'll be off by 15%, which doesn't matter when you're trying to tell 10 from 10,000.
- Write down every assumption. "Each customer makes 20 requests per session" is a guess. Writing it down lets others challenge it, and lets you fix one number later without redoing everything.
- Always use units. "500" means nothing. 500 requests per second, 500 GB per year, 500 ms: those mean something.
- Think about the peak, not just the average. Systems fall over at the busiest moment, not the average one.
- Aim for the right power of ten. If your answer is between 200 and 800 requests a second, "a few hundred" is the useful conclusion.
An estimate isn't a prediction. It's a way to find out which order of magnitude you're designing for.
Numbers worth knowing
You need a feel for how fast things are and how much one machine can do. These are typical values, rounded:
| Thing | Rough number |
|---|---|
| Read from memory | ~100 nanoseconds |
| Read 1 MB sequentially from memory | ~50 microseconds |
| Random read from an SSD | ~100 microseconds |
| Round trip inside one data centre | ~0.5 ms |
| Simple indexed database query | 1 to 5 ms |
| Round trip across a country | 30 to 60 ms |
| Round trip to another continent | 150 to 250 ms |
| One server, simple API requests | 1,000 to 5,000 per second |
| One PostgreSQL server, simple queries | 5,000 to 50,000 per second |
| One PostgreSQL server, writes | 1,000 to 10,000+ per second |
| RAM on one large server | 256 GB to several TB |
These vary a lot with hardware and workload. But they're the right order of magnitude, and that's all we need.
And three conversions to keep handy:
- 1 million per day ≈ 12 per second on average.
- 1 KB x 1 million = 1 GB.
- 1 request per second, all year ≈ 30 million requests.
Step 1: Who uses Tiffin, and how much?
Tiffin is in one city. Here are our assumptions:
| Assumption | Value |
|---|---|
| Customers who open the app on a typical day | 150,000 |
| Orders per day | 50,000 (about 1 in 3 sessions orders) |
| API requests per customer session | ~20 (restaurant list, a few menus, cart, checkout, status) |
| Share of the day's traffic in the 7pm to 10pm dinner rush | 60% |
| Restaurants open, each with a kitchen tablet | 800 |
| Kitchen tablets poll for new orders | Every 5 seconds |
| Riders on shift at peak | 1,000 |
| Rider app sends its location | Every 10 seconds |
Step 2: Requests per second
Do each client separately, at peak.
Customer app. 150,000 sessions x 20 requests = 3,000,000 requests a day. 60% of those, 1.8 million, land in the 3-hour dinner rush. 3 hours is about 10,800 seconds.
1,800,000 / 10,800 s ≈ 170 requests per second
Kitchen tablets. These don't care about dinner time; they poll steadily while the restaurant is open.
800 tablets / 5 s = 160 requests per second
Rider app.
1,000 riders / 10 s = 100 requests per second
Total at peak: 170 + 160 + 100 = 430. Call it ~500 requests per second.
Count only the customers and you'd say 170 a second. The tablets and the riders, which are easy to forget, push it to 430, more than two and a half times as much. Same app, more careful assumptions.
Look at the split. The kitchen tablets, which most people would forget, generate nearly as much traffic as all the customers. Over a whole day they generate more: 160 per second for 14 opening hours is about 8 million requests, against 3 million from customers. Estimation is often most useful for surprises like this. If we ever need to cut load, polling is the first place to look (Module 6 offers alternatives).
Step 3: Can one server handle it?
Say an average request uses 5 ms of CPU time on the server (parse, check, query, build JSON). One CPU core can then do:
1 s / 5 ms = 200 requests per second per core
An ordinary 8-core server can do about 1,600 requests a second. Our peak is about 500. So one server runs at around 30% CPU at the busiest moment of the day.
Conclusion: one server is enough, with room for about 3 times the traffic. That's comfortable for now, and tells us that if Tiffin triples, we'll need to think about more servers (Module 4).
What about the database? Each request does one to three queries, so at peak that's roughly 500 to 1,500 queries a second, mostly simple indexed reads. Writes are much rarer: each order creates a handful of rows (order, items, payment, status changes), so 3 orders a second is a few dozen writes, plus 100 rider location updates. A single PostgreSQL server handles that easily.
Step 4: How much data?
Now storage. Estimate the size of one record, then multiply.
Orders. An order row is about 250 bytes. With three items at ~100 bytes each, a payment row, and index overhead, call it ~1 KB per order, all in.
50,000 orders/day x 1 KB = 50 MB per day
50 MB x 365 ≈ 18 GB per year
Tiny. Ten years of orders fit comfortably on one server.
Menus. 800 restaurants x ~60 dishes x ~500 bytes ≈ 24 MB. Negligible.
Rider locations, if we keep every point:
1,000 riders x 1 point per 10 s x ~10 active hours/day
= 1,000 x 3,600 = 3.6 million points per day
3.6 million x 100 bytes ≈ 360 MB per day ≈ 130 GB per year
This is more than seven times the orders data, for information nobody will look at after the order is delivered (except perhaps for disputes). A good estimate leads straight to a design question: should we keep every location point at all? A sensible answer is to keep the latest location in the database, and the full trail only for a few weeks.
Photos. 800 restaurants x 60 dishes x a few sizes x ~100 KB ≈ 15 GB. That's large files that never change, so they belong in object storage (like Amazon S3), not in the database. The database stores only the URL.
Step 5: Bandwidth
Bandwidth matters most for things like images and video. A customer session might load 40 dish photos at ~30 KB each:
40 x 30 KB = 1.2 MB per session
150,000 sessions x 1.2 MB = 180 GB per day
At peak: 60% of 180 GB over 10,800 s ≈ 10 MB/s ≈ 80 Mbit/s
That's more traffic than all the API calls put together, served from one server's network card at dinner time. It's a strong hint that photos should be served from somewhere closer to users and built for big files. That's a CDN, which we'll meet in Module 3.
The summary that matters
After five minutes of maths, here's what we know:
| Question | Answer | What it means |
|---|---|---|
| Peak requests | ~500 per second | One server is enough, with about 3x headroom |
| Biggest traffic source | Kitchen tablet polling | First place to look when cutting load |
| Database load | ~1,500 queries per second, few writes | One PostgreSQL server is fine |
| Order data | ~18 GB a year | No storage problem for years |
| Rider locations | ~130 GB a year if all kept | Don't keep them all |
| Photos | ~15 GB, ~80 Mbit/s at peak | Object storage and a CDN, not the database |
Every row in that table turned into a design decision. That's the point of estimating.
Ten cities
Tiffin expands to 10 cities of similar size, so everything is about 10 times bigger. Estimate peak requests per second, order data per year, and rider location data per year (if all kept). Which of our "one server" conclusions still hold?
Show one answer
Peak requests: ~5,000 per second (assuming all cities share one dinner rush, which they do in one country). That's about three times what one 8-core server can do. We need more servers, or a much bigger one: Module 4.
Database queries: ~5,000 to 15,000 per second. Possible on one strong PostgreSQL server, but getting close to its limits. Caching (Module 3) and read replicas (Module 5) become important.
Order data: ~180 GB a year. Still fine on one database for years.
Rider locations: ~1.3 TB a year if all kept. Definitely not going into the main database. Keep only recent points, or move them to a store built for high write volume.
What to remember
- Estimation tells you the order of magnitude you're designing for. Round hard, write down assumptions, always use units.
- Design for the peak. For Tiffin, 60% of traffic lands in the 3-hour dinner rush.
- 1 million per day is about 12 per second. A simple request uses a few milliseconds of CPU, so one core handles about 200 a second.
- Count every client. Background polling can generate more traffic than the users you were thinking about.
- Estimate storage per record, then multiply. Big, fast-growing data (locations, photos) often belongs somewhere other than the main database.
- Every estimate should end in a decision: one server or many, keep or discard, database or object storage.