1Context and scope
A message sent to a channel has to be stored durably, shown to everyone in the channel within a second, indexed for search and, for people who are away, pushed to their phone. Presence (who is online) is a constant trickle of heartbeats. This design covers sending and reading messages, the real-time fan-out and presence, based on Slack’s engineering posts about its messaging stack and Vitess, scaled to a browser run.
2Goals and non-goals
Goals
- 5,000 requests a second: 45% history reads, 40% sends, 15% presence heartbeats.
- Success at least 99%, p99 at most 500 ms, Apdex at least 0.90.
- Every send is stored and fanned out; redeliveries never duplicate.
Non-goals
- WebSocket connection handling itself (the pub/sub stands in for the edge servers).
- Files, calls and apps.
- Enterprise grid and multi-region.
3Capacity estimate
| Quantity | Value | How |
|---|---|---|
| Sends | ≈ 2,000/s | 40% of 5,000: one MySQL write and one Kafka event each |
| Messages database | 600 connections, 48 vCPU | 2,000 × 10 ms ≈ 20 connections busy on writes |
| Fan-out | 256 workers at ≈ 3 ms | each message: a pub/sub publish, an index write, and a push for 30% |
| History reads | ≈ 2,250/s | through a 32 GB cache of recent messages, 15 min TTL |
| Presence | ≈ 750/s | 5,000 slots at 1 ms: nowhere near its limit |
| Search index writes | ≈ 2,000/s | 256 slots, 3 ms CPU on 32 vCPU |
The rest of the doc
The design · Key concepts · Alternatives considered · Failure modes and fixes · Try it in the lab · Check yourself · Further reading
Unlock the Slack design doc
Every component and why it is there, the capacity numbers behind it, what breaks when you push it and how to fix it, and the same system open in the lab to break and fix yourself. Paid once, on your account.