Simple Notification Service (SNS) System Design
The prompt sounds small: "Design a simple notification service, something like AWS SNS. Publishers create topics, subscribers attach endpoints to a topic (an HTTP webhook, a queue, an email address, a phone number, a mobile device), and when someone publishes a message to the topic, every subscriber gets a copy."
Everyone can draw the first version. A POST /publish handler looks up the topic's subscribers and loops over them, sending each one a copy. It works for a topic with three subscribers. Then one of those subscribers is a partner's webhook that starts taking five seconds to time out, and every publish to the topic now takes five seconds. Then a mobile app with eight million installed devices announces a flash sale, and one publish has to become eight million deliveries. The word "simple" in the name describes the product. It has three verbs: create a topic, subscribe, publish. It doesn't describe the system behind those verbs.
The Trap Built Into a Familiar Question
Two failures show up again and again:
- The Mailman: delivers inside the publish request, one subscriber after another. The publisher's latency becomes the sum of every subscriber's latency, and one dead endpoint stalls everything behind it. Signal: hasn't separated the publisher's clock from the subscriber's.
- The Kafka Reciter: says "it's just Kafka" and maps every topic to a Kafka topic and every subscriber to a consumer group. That leaves ten million topics, pushes to third-party URLs that Kafka doesn't make, and per-subscriber retry and backoff that nobody owns. Signal: names a tool instead of designing the system the tool would sit inside.
The passing performance starts from one asymmetry. At peak, 150,000 publishes a second come in, an ordinary write load for a replicated log. Out of them come about 600,000 deliveries a second, and most of those go to servers we don't own and can't fix. The design acknowledges a publish as soon as it's durable on two of three availability zones, then fans it out asynchronously. Small topics expand inline and large ones split into pages of a thousand. Each delivery is retried with backoff and jitter. Every endpoint gets its own concurrency cap and circuit breaker, so a dead partner webhook parks its own traffic instead of consuming the fleet. The system is judged by how it behaves when someone else's endpoint is down.
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