| Users/Observers | Events per Second | Notifications Sent | Latency Impact | Resource Usage |
|---|---|---|---|---|
| 100 observers | 1000 events | 100,000 notifications | Low latency (~ms) | Low CPU & memory |
| 10,000 observers | 10,000 events | 100 million notifications | Moderate latency (tens of ms) | High CPU, memory, network |
| 1,000,000 observers | 100,000 events | 100 billion notifications | High latency (seconds) | Very high CPU, memory, network |
| 100,000,000 observers | 1,000,000 events | 100 trillion notifications | Unusable latency (minutes+) | Extremely high resource usage, system overload |
Observer pattern in LLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
The first bottleneck is the notification dispatch system. As the number of observers grows, sending updates to all observers becomes expensive in CPU, memory, and network bandwidth. The system struggles to handle the volume of notifications in real-time.
- Batch notifications: Group multiple events before notifying observers to reduce message count.
- Hierarchical observers: Use intermediate aggregators to reduce direct notifications.
- Asynchronous messaging: Use message queues or event buses to decouple event generation and notification delivery.
- Filtering: Notify only observers interested in specific event types to reduce unnecessary notifications.
- Horizontal scaling: Distribute notification dispatch across multiple servers.
- Caching: Cache event states to avoid redundant notifications.
At 10,000 observers and 10,000 events/sec:
- Notifications per second = 10,000 events * 10,000 observers = 100 million notifications/sec
- Assuming 1 KB per notification, bandwidth needed = 100 million KB/sec ≈ 95 GB/sec (unrealistic for single server)
- CPU and memory usage to serialize and send notifications will be very high.
- Storage needed depends on event persistence; if storing all events, requires large scalable storage.
Start by explaining the basic observer pattern and its use case. Then discuss how scaling the number of observers and events affects system resources. Identify the bottleneck clearly and propose practical solutions like batching, filtering, and asynchronous messaging. Use real numbers to show understanding of system limits.
Your notification system handles 1000 QPS with 1000 observers. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Implement batching or filtering to reduce the number of notifications sent per event, or introduce asynchronous messaging to decouple event generation from notification delivery. This reduces CPU, memory, and network load before scaling hardware.
Practice
What is the main purpose of the Observer pattern in system design?
Solution
Step 1: Understand the Observer pattern role
The Observer pattern is designed to let one object notify others about changes automatically.Step 2: Match purpose with options
To allow objects to automatically update when another object changes correctly describes automatic updates between objects without tight coupling.Final Answer:
To allow objects to automatically update when another object changes -> Option BQuick Check:
Observer pattern = automatic updates [OK]
- Confusing Observer with data storage
- Thinking it creates class hierarchies
- Assuming it improves function speed
Which of the following is the correct way to register an observer in the Observer pattern?
subject = Subject()
observer = ConcreteObserver()
# What code registers the observer?Solution
Step 1: Recall common Observer pattern method names
Typically, the subject has a method namedattachoraddObserverto register observers.Step 2: Identify the most standard method
WhileaddObserveris used in some languages,attachis the classic and widely accepted method name.Final Answer:
subject.attach(observer) -> Option DQuick Check:
Register observer = subject.attach(observer) [OK]
- Calling register on observer instead of subject
- Using subscribe which is not standard here
- Confusing addObserver with observer methods
Given this code snippet, what will be printed?
class Subject:
def __init__(self):
self.observers = []
self.state = 0
def attach(self, observer):
self.observers.append(observer)
def set_state(self, state):
self.state = state
for obs in self.observers:
obs.update(state)
class Observer:
def __init__(self, name):
self.name = name
def update(self, state):
print(f"{self.name} received state {state}")
subject = Subject()
obs1 = Observer('A')
obs2 = Observer('B')
subject.attach(obs1)
subject.attach(obs2)
subject.set_state(5)Solution
Step 1: Follow the attach and set_state calls
Observers A and B are attached to the subject. Whenset_state(5)is called, it updates the state and callsupdate(5)on each observer.Step 2: Understand the update method output
Each observer prints its name and the new state, so both print lines with state 5.Final Answer:
A received state 5 B received state 5 -> Option AQuick Check:
Observers print updated state 5 [OK]
- Thinking observers print old state
- Assuming no output without explicit print
- Confusing method names causing errors
Identify the bug in this Observer pattern implementation:
class Subject:
def __init__(self):
self.observers = set()
def attach(self, observer):
self.observers.add(observer)
def notify(self):
for obs in self.observers:
obs.update()
class Observer:
def update(self, state):
print(f"State updated to {state}")
subject = Subject()
obs = Observer()
subject.attach(obs)
subject.notify()Solution
Step 1: Check method signatures and calls
The Observer'supdatemethod expects astateargument, butnotifycallsupdate()without any argument.Step 2: Identify mismatch causing error
This mismatch will cause a runtime error due to missing required positional argument.Final Answer:
Observer.update requires a state argument but notify calls without it -> Option AQuick Check:
Method argument mismatch causes error [OK]
- Ignoring missing argument errors
- Thinking sets are invalid for observers
- Misunderstanding attach method purpose
You are designing a stock price alert system using the Observer pattern. Multiple clients want updates only when the stock price changes by more than 5%. How should you modify the Observer pattern to handle this efficiently?
Solution
Step 1: Understand the requirement for selective updates
Clients want updates only if price changes exceed 5%, so notifying on every change is inefficient.Step 2: Implement threshold logic in Subject
Adding a check in the Subject to compare new price with old and notify observers only if change > 5% reduces unnecessary notifications.Final Answer:
Add a threshold check in the Subject before notifying observers -> Option CQuick Check:
Efficient notify = threshold check in Subject [OK]
- Not filtering updates causing overload
- Using polling which wastes resources
- Removing Observer pattern loses decoupling benefits
