| Users / Instances | 100 Users | 10,000 Users | 1,000,000 Users | 100,000,000 Users |
|---|---|---|---|---|
| Singleton Instance Count | 1 per process | 1 per process | 1 per process | 1 per process |
| Application Servers | 1-2 servers | 5-10 servers | 500 servers | 50,000+ servers |
| Singleton Usage Scope | Local to each server process | Local to each server process | Local to each server process | Local to each server process |
| Shared State Across Servers | Not shared | Not shared | Not shared | Not shared |
| Potential Issues | None | None | State inconsistency across servers | State inconsistency across servers |
Singleton pattern in LLD - Scalability & System Analysis
The Singleton pattern ensures only one instance per process. At small scale, this works well. But as users grow and servers multiply, the singleton instances are isolated per server. This means shared state is not truly global. The first bottleneck is state inconsistency across multiple servers because the singleton does not synchronize state between servers.
- Distributed Singleton: Use a distributed coordination system (like Redis, ZooKeeper) to maintain a single logical instance across servers.
- Centralized State Store: Move shared state to a central database or cache to keep data consistent.
- Stateless Servers: Avoid storing state in singleton; keep servers stateless and share state externally.
- Load Balancing: Add more servers to handle traffic, but ensure singleton logic is adapted for distributed environment.
- Caching: Use caching layers to reduce load on centralized state stores.
Assuming 1 server handles ~2000 concurrent users:
- At 10,000 users: ~5-10 servers needed.
- At 1,000,000 users: ~500 servers needed.
- Singleton instances: 1 per server process, so hundreds to thousands of instances.
- Network bandwidth for coordination: depends on frequency of state sync; can be 10s-100s Mbps at large scale.
- Storage: minimal for singleton instance itself, but centralized state store size depends on data.
When discussing Singleton pattern scalability, start by explaining it works well for single-process scenarios. Then highlight challenges when scaling horizontally, especially state sharing. Propose solutions like distributed coordination or stateless design. Show awareness of trade-offs between simplicity and distributed complexity.
Your singleton instance holds configuration data in one server process. Traffic grows 10x and you add more servers. What do you do first?
Answer: Recognize that singleton instances are now multiple and isolated. To keep configuration consistent, move the configuration to a centralized store or use a distributed coordination system so all servers read the same data.
Practice
Singleton pattern in system design?Solution
Step 1: Understand Singleton pattern goal
The Singleton pattern is designed to restrict a class to a single instance.Step 2: Compare options with Singleton definition
Only To ensure only one instance of a class exists throughout the application matches the purpose of Singleton by ensuring one instance exists.Final Answer:
To ensure only one instance of a class exists throughout the application -> Option AQuick Check:
Singleton = single instance [OK]
- Thinking Singleton allows multiple instances
- Confusing Singleton with factory pattern
- Assuming Singleton creates new instances each call
Solution
Step 1: Identify Singleton instance method requirements
The method to get the Singleton instance must be static and publicly accessible.Step 2: Analyze options for correct access and static usage
public static getInstance() { ... } is public and static, which is correct. public void getInstance() { ... } is not static, private static getInstance() { ... } is private, static getInstance() { ... } misses access modifier.Final Answer:
public static getInstance() { ... } -> Option AQuick Check:
Singleton instance method = public static [OK]
- Making getInstance() private or non-static
- Omitting access modifier
- Using void return type instead of instance
class Logger {
static instance = null;
constructor() {}
static getInstance() {
if (this.instance === null) {
this.instance = new Logger();
}
return this.instance;
}
}
const log1 = Logger.getInstance();
const log2 = Logger.getInstance();
console.log(log1 === log2);Solution
Step 1: Understand Singleton instance creation
The first call to getInstance() creates the instance; the second returns the same instance.Step 2: Compare references of log1 and log2
Both variables point to the same instance, so strict equality returns true.Final Answer:
true -> Option BQuick Check:
Same instance check = true [OK]
- Assuming new instance created on each call
- Confusing equality with object content
- Expecting false due to separate variables
class Config {
static instance;
constructor() {}
static getInstance() {
if (!instance) {
instance = new Config();
}
return instance;
}
}Solution
Step 1: Check static variable access inside static method
Static variables must be accessed with 'this.' prefix inside static methods.Step 2: Identify missing 'this.' usage
The code uses 'instance' instead of 'this.instance', causing a reference error.Final Answer:
Missing 'this.' before 'instance' inside getInstance method -> Option CQuick Check:
Static variable access requires 'this.' [OK]
- Ignoring 'this.' prefix for static variables
- Changing constructor visibility incorrectly
- Assuming static keyword missing on method
Solution
Step 1: Understand thread safety in Singleton
In multi-threaded environments, multiple threads may create multiple instances if not synchronized.Step 2: Evaluate options for thread-safe Singleton
Double-checked locking with a volatile static instance ensures only one instance is created safely.Final Answer:
Use double-checked locking with a private static volatile instance variable -> Option DQuick Check:
Thread-safe Singleton = double-checked locking [OK]
- Ignoring thread safety in Singleton
- Making constructor public defeats Singleton
- Using global variables breaks encapsulation
Ready to prove it?
Pass the test and this pattern moves unknown
