Free preview

Sized in Connections, Not Requests

In one line: every previous chapter sized itself in requests per second, and most of them got it wrong. This chapter uses a different unit entirely, and it is the right one.

The system

WhatsApp connects users for one-on-one and group conversations, with delivery acknowledgements, media sharing, storage for offline users, and push notifications.

At the scale the chapter assumes: more than 2 billion daily active users sending more than 100 billion messages per day.

The capacity unit changes, and this is the first chapter in the module to get it structurally right

Look at how the server count is derived:

Number of servers = total connections / connections per server
                  = 2 billion / 10 million
                  = 200 servers

Not requests per second. Connections.

That is correct, and it is a genuinely different model. A messaging client holds a persistent WebSocket open for as long as the app is running — hours at a time, mostly idle. What consumes server resources is not the rate of messages but the number of sockets held open: file descriptors, buffers, and kernel state per connection.

Compare what every previous chapter did with the DAU-as-RPS convention:

ChapterModelError
YelpDAU as requests/second86,400x
NewsfeedDAU as requests/second8,640x
InstagramDAU as requests/second4,320x
TinyURLDAU as requests/second13,141x
WhatsAppDAU as concurrent connectionsStructurally right

The difference is that connections and daily-active users are at least the same kind of quantity — both are counts of users, not rates. Dividing users by users-per-server is dimensionally coherent in a way that dividing users by requests-per-second never was.

When a system holds long-lived connections, size it in connections. That is the C10K shape the YouTube, Maps, Quora, and Uber chapters all met and none of them sized for.

Though 2 billion is daily-active, not concurrent — and the formula says so

The formula in the design reads: "Total connections per day / number of connections per server."

Connections per day divided by a concurrent capacity. Those are different quantities, and the mismatch matters.

Not all 2 billion daily-active users are online simultaneously. They are spread across time zones, sleeping, at work, or with the app closed. Realistic simultaneity for a global messaging app is perhaps 10–20%:

100% concurrent -> 2,000M sockets -> 200 servers   <- the published figure
 20% concurrent ->   400M sockets ->  40 servers
 10% concurrent ->   200M sockets ->  20 servers

So 200 is a defensible upper bound — provision for everyone online at once and you will never be short — but it should be labelled as one rather than presented as the answer.

That said, this is a far smaller error than the earlier chapters made, and it errs in the safe direction. A correct model with a conservative input beats a wrong model with any input.

The ordering is the whole design: persist, then attempt delivery. Live delivery is best-effort; durability is not. A messaging system that delivers fast but loses a message when a phone is off has failed at the only thing it must do.

What the chapter never computes

1.16 million messages per second — the number that sizes the message tier

The chapter derives storage (10 TB/day) and bandwidth (926 Mb/s) from the message volume, and never converts it into a rate:

100,000,000,000 messages/day / 86,400 = 1,157,000 messages per second

Over a million messages a second, and it is the number that would size the message service and the Mnesia cluster in Lesson 6 — because every one of those messages is a write, a lookup of the recipient's server, a forward, and (until acknowledged) a stored row.

The bandwidth figure hides it, exactly as that building block's did: 926 Mb/s is trivial because a message is only 100 bytes. The operation count is not.

Bandwidth:  926 Mb/s    -> a single NIC handles it
Rate:       1.16M/sec   -> a substantial distributed write path

A small bandwidth figure can conceal an enormous request rate when the objects are tiny. The Uber chapter met this with 750,000 location updates per second inside 114 Mb/s; here it is 1.16 million messages inside 926 Mb/s. Same trap, same resolution: divide, then look at the quotient.

What this chapter adds

PropertyWhy it is new here
Bidirectional persistent connectionsMessages arrive server-initiated, so polling is not an option
Delivery state machineSent, delivered, read — the acknowledgement is a product feature, not an implementation detail
Storage as a temporary bufferMessages are stored only until delivered, then deleted
End-to-end encryptionThe server cannot read what it routes — stated as a requirement, and never designed

The third row is the distinctive one, and the fourth is the chapter's biggest gap

Storage as a buffer inverts the usual assumption. Every other chapter stored content to serve it later — tweets, photos, videos, all retained indefinitely. Here the design says "once delivered, the message is deleted from the database."

That is a real and privacy-motivated architectural choice, and Lesson 6 explores it. It also creates a contradiction with the requirements that Lesson 3 will name.

End-to-end encryption is stated as a non-functional requirement, listed in the evaluation as satisfied, and included in the summary's claim that the design covers "connection management, text and media messaging, group chat, and encryption."

It is designed nowhere. And Lesson 7 shows it is not a gap you can wave at — E2E breaks the group-messaging flow as drawn, because the design fans one message out to many recipients and there is no single ciphertext they can all decrypt.

A security property claimed in three places and specified in none is worth raising early, because it changes components rather than decorating them.

Key takeaway

This is the first chapter in the module to size capacity on the right unit — connections rather than requests — which is correct because a messaging client holds a mostly-idle socket for hours. The published input is still daily-active users rather than concurrent ones, making 200 servers a conservative upper bound rather than the answer. And the chapter never computes the figure that would size its message tier: 1.16 million messages per second, hidden inside a trivial 926 Mb/s because the objects are tiny. Two properties are new here — storage as a temporary buffer rather than an archive, and end-to-end encryption, which is claimed in three places, designed in none, and incompatible with the group flow as drawn.

Next: the requirements, and two that contradict each other.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue