Before building anything, you can work out roughly how big it needs to be. A few multiplications turn "how many users" into "how many servers, and what it costs", and they tell you early whether a plan is cheap, expensive or impossible.
From users to requests
Start from what the product team knows: how many people use the feature each day, and how much each of them does. Multiply, then divide by the seconds in a day (about 86 400, call it 100 000 for mental maths).
| Inkwell Groups | |
|---|---|
| Daily users | 2 300 000 |
| Requests per user per day | 50 |
| Requests per day | 115 000 000 |
| Average per second | about 1 330 |
Round freely. An estimate that's within a factor of two is useful; one with four significant digits is pretending.
Peaks, not averages
Nobody uses Inkwell evenly through the day. Evenings are busy, nights are quiet, and the busiest hour usually carries two to four times the average. Systems fail at the peak, so size for the peak.
| Requests per second | |
|---|---|
| Average | about 1 330 |
| Busiest hour (3 times the average) | about 4 000 |
| Plan for | about 4 000, before any headroom |
Also split reads from writes: they often go to different places and cost different amounts. Groups is about 9 reads for every write.
What one server can take
Next, what each building block can do. These are the numbers in this simulator, with the hourly price of each:
| Tier | App server replica | Database node |
|---|---|---|
| Small | 700 rps, $0.05 | 2 500 rps, $0.12 |
| Medium | 1 400 rps, $0.10 | 6 600 rps, $0.30 |
| Large | 2 800 rps, $0.20 | 15 000 rps, $0.70 |
| XLarge | 5 600 rps, $0.40 | 32 000 rps, $1.50 |
The database column is for Groups' mix of 9 reads to each write. A medium node does about 8 000 reads a second, or about 2 500 writes, since a write costs about three times the work; mixed 9 to 1, that comes to about 6 600. The medium app server's 1 400 is its CPU limit from Scaling Out: 4 cores at about 3 ms of CPU per request. Each tier up doubles the cores and so the requests a second; it doesn't make one request faster, since a bigger machine of the same kind has more cores, not quicker ones. Real machines land in the same range: one Postgres node handles tens of thousands of simple queries a second, over 100 000 for key lookups on a large machine, one Redis node (an in-memory key-value store) on the order of 100 000 operations a second, and a 1 Gbps network link carries about 125 MB a second.
Divide the peak by one server's capacity to get a first count: 4 000 ÷ 1 400 is a bit under 3 medium app servers, so 3 with nothing to spare.
Headroom
Three servers at 95% busy technically keep up, but queues grow sharply near 100%, and the slowest requests get slow. Plan to run at about 60 to 75% of capacity, and round up.
Databases slow down earlier still. Every query shares the node's disk, memory and internal locks, so in this simulator a database query takes about one and a half times as long at 70% busy and three times as long at 90%, long before the node turns anything away. Slower queries also hold their connections longer, which is how a busy database runs out of connections.
Cost
In this simulator, as on real clouds, bigger machines cost about as much per request as smaller ones. So the cheapest design isn't "the smallest machines" or "the biggest machines"; it's the one whose capacity matches the peak plus headroom, with no idle tier left over. Check each part separately: the app servers, the database, everything with its own limit.
| Comments at 2 500 rps, 9 reads to a write | App servers | Database | Per hour |
|---|---|---|---|
| Too small | 2 medium | small | $0.35: servers near 90% busy, database full |
| Right-sized | 3 medium | medium | $0.63 |
| Bigger than needed | 2 xlarge | large | $1.53 |
Each hourly total includes the load balancer, $0.03 an hour.
Storage and bandwidth
The same multiplication sizes storage: items a day, times bytes each, times how long you keep them. And requests a second times bytes each gives the bandwidth.
| Groups messages | |
|---|---|
| New messages a day | 10 million |
| Size of each | about 1 KB |
| Per year | 10 million × 365 × 1 KB: about 3.6 TB |
| Kept 5 years, with 3 copies | about 55 TB |
A few numbers are worth knowing by heart, because they decide where time goes. Treat them as orders of magnitude: hardware keeps getting faster, but the gaps between the rows stay huge.
| Operation | Roughly |
|---|---|
| Read from memory | 0.1 microseconds |
| Read from an SSD | 100 microseconds |
| Read 1 MB from memory | tens of microseconds |
| Round trip inside a datacenter | 0.5 milliseconds |
| A database query inside a datacenter | a few milliseconds |
| Round trip across a continent | 50 milliseconds |
| Round trip across the world | 150 to 300 milliseconds |
In the wild
The ideas in this chapter, and where you'll meet them in real systems and interviews:
| Idea | Where you'll meet it |
|---|---|
| Rules of thumb | a day is about 100 000 seconds; 1 million requests a day is about 12 a second |
| Latency numbers | "Latency numbers every programmer should know", popularised by Jeff Dean |
| Prices | the AWS, Google Cloud and Azure pricing calculators |
Try the chain
Now do it yourself. Work down Groups from users to servers to storage, and see where your numbers drift from the reference.
A few quick rounds on the conversions that trip people up:
Your practice
Inkwell is launching Groups. Using the numbers from the product team, about 4 000 requests a second at the busiest hour, size the app servers and the database: fast at the peak, and as cheap as you can make it.