| Users | Notifications/Day | Key Changes |
|---|---|---|
| 100 | ~1,000 | Simple queue, single server, direct DB writes |
| 10,000 | ~100,000 | Message queue introduced, caching user preferences, DB indexing |
| 1,000,000 | ~10,000,000 | Multiple app servers, distributed queue, read replicas, push notification services |
| 100,000,000 | ~1,000,000,000 | Sharded DB, global CDN for media, microservices, event-driven architecture |
Design a notification system in HLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
At around 10,000 users, the database becomes the first bottleneck. Writing and reading notification data for many users causes high latency and connection limits. The single server and simple queue cannot handle the volume efficiently.
- Horizontal Scaling: Add more application servers behind a load balancer to handle more notification requests.
- Message Queues: Use distributed queues (e.g., Kafka, RabbitMQ) to decouple notification generation from delivery.
- Caching: Cache user notification preferences and recent notifications to reduce DB load.
- Database Read Replicas: Use replicas to distribute read traffic and reduce load on the primary DB.
- Sharding: Partition the database by user ID or region to scale writes and storage.
- Push Notification Services: Use external services (e.g., Firebase, APNs) for mobile push notifications to offload delivery.
- CDN: Use CDN for static media in notifications to reduce bandwidth and latency.
- At 1M users sending 10 notifications/day: ~10M notifications/day ≈ 115 notifications/sec.
- Database: Needs to handle ~115 writes/sec plus reads; a single DB can handle ~5,000 QPS, so one instance is sufficient but close to limits.
- Message Queue: Must support ~115 enqueue/dequeue operations per second, well within Kafka or RabbitMQ capabilities.
- Bandwidth: Assuming 1 KB per notification, 115 KB/s ≈ 0.9 Mbps, easily handled by 1 Gbps network.
- Storage: 10M notifications/day x 1 KB = ~10 GB/day; plan for archiving and tiered storage.
Start by clarifying notification types and user scale. Discuss data flow from event to delivery. Identify bottlenecks at each scale. Propose incremental scaling solutions: caching, queues, DB replicas, sharding. Mention trade-offs and real-world constraints like latency and cost.
Your database handles 1000 QPS. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add read replicas to distribute read traffic and reduce load on the primary database. Also, introduce caching for frequent reads and consider message queues to decouple processing.
Practice
Solution
Step 1: Understand the role of event processor
The event processor detects events that trigger notifications, deciding when a message should be sent.Step 2: Differentiate from other components
The notification sender delivers messages, user preference manager stores user choices, and message storage keeps records.Final Answer:
Event processor -> Option AQuick Check:
Event detection = Event processor [OK]
- Confusing sender with event detector
- Thinking user preferences trigger events
- Assuming storage decides timing
Solution
Step 1: Identify quick lookup needs
User preferences require fast access by user ID or key, so a data structure with O(1) average lookup is ideal.Step 2: Match data structures to lookup speed
Hash maps provide constant time lookup, unlike linked lists, queues, or stacks which are slower for direct access.Final Answer:
Hash map -> Option BQuick Check:
Fast key-value access = Hash map [OK]
- Choosing linked list which is slow for lookup
- Confusing queue or stack with lookup structures
- Ignoring key-based access needs
Solution
Step 1: Understand queue capacity limits
Queues have fixed or limited size; when full, they cannot accept new items immediately.Step 2: Identify common handling of full queues
Systems usually drop new notifications or delay them until space frees up; automatic unlimited expansion is rare to avoid resource exhaustion.Final Answer:
New notifications are dropped or delayed -> Option DQuick Check:
Full queue = drop or delay new notifications [OK]
- Assuming infinite queue size
- Thinking notifications bypass queue
- Believing system crashes on full queue
Solution
Step 1: Analyze duplicate message causes
Duplicates often occur if the system processes the same event multiple times without checking if notification was already sent.Step 2: Evaluate other options
Missing user preferences or synchronous sending do not cause duplicates; a single queue can still handle duplicates if deduplication exists.Final Answer:
No deduplication in event processing -> Option CQuick Check:
Duplicates = missing deduplication [OK]
- Blaming user preferences for duplicates
- Confusing synchronous sending with duplication
- Assuming single queue causes duplicates
Solution
Step 1: Identify scalability and multi-channel needs
Supporting multiple notification types and scaling requires decoupling components and asynchronous processing.Step 2: Match architecture patterns
Event-driven microservices with message queues allow independent scaling, handle user preferences, and support multiple channels efficiently.Step 3: Eliminate unsuitable options
Monolithic apps limit scalability; polling causes delays; batch processing is too slow for timely notifications.Final Answer:
Event-driven microservices with message queues and preference service -> Option AQuick Check:
Scalable multi-channel = event-driven microservices [OK]
- Choosing monolithic for scalability
- Using batch processing for real-time needs
- Relying on polling causing delays
