| Users/Requests | System Changes |
|---|---|
| 100 users | Single server handles command execution synchronously. Simple queue or direct calls. Low latency. |
| 10,000 users | Commands queued asynchronously. Use in-memory queue or lightweight broker. Add worker threads to process commands concurrently. |
| 1,000,000 users | Distributed command queue (e.g., Kafka, RabbitMQ). Multiple worker servers for parallel processing. Command storage for retries and audit. Command handlers scaled horizontally. |
| 100,000,000 users | Multi-region distributed queues for latency and fault tolerance. Command partitioning/sharding by user or type. Command metadata stored in scalable DB. Autoscaling workers. Use caching for command results if applicable. |
Command pattern in LLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
At low scale, the command handler server CPU and memory limits are the first bottleneck because commands are processed synchronously or with limited concurrency.
At medium scale (10K+ users), the command queue becomes the bottleneck if it cannot handle the volume or latency of commands.
At high scale (1M+ users), the database or persistent storage for commands and their states becomes the bottleneck due to high read/write operations.
- Horizontal scaling: Add more worker servers to process commands in parallel.
- Asynchronous queues: Use message brokers like Kafka or RabbitMQ to decouple command submission from processing.
- Sharding: Partition commands by user ID or command type to distribute load across queues and workers.
- Caching: Cache command results or states to reduce database load.
- Database optimization: Use read replicas and indexing for command metadata storage.
- Multi-region deployment: Deploy queues and workers closer to users to reduce latency.
Assuming each user issues 1 command per second:
- 100 users -> 100 commands/sec
- 10,000 users -> 10,000 commands/sec
- 1,000,000 users -> 1,000,000 commands/sec
- 100,000,000 users -> 100,000,000 commands/sec
Storage per command: ~1 KB (command data + metadata)
- At 1M commands/sec, daily storage = 1M * 1 KB * 86400 sec ≈ 86.4 TB/day
- Network bandwidth for command ingestion at 1M commands/sec ≈ 1 GB/s
These numbers show the need for efficient command retention policies and data archiving.
When discussing scalability for the Command pattern, start by explaining how commands are queued and processed. Then identify bottlenecks at each scale. Discuss asynchronous processing and horizontal scaling. Mention data storage and fault tolerance. Finally, explain how you would partition commands and use caching to improve performance.
Your database handles 1000 QPS for command metadata storage. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add read replicas and implement caching for command metadata to reduce direct database load. Also consider sharding the command data by user or command type to distribute writes.
Practice
Command pattern in system design?Solution
Step 1: Understand the Command pattern role
The Command pattern encapsulates a request as an object, which allows you to parameterize clients with queues, requests, and operations.Step 2: Compare with other patterns
Creating multiple instances relates to Prototype or Factory, a family of algorithms to Strategy, and a single instance to Singleton; these are not Command.Final Answer:
To encapsulate a request as an object, allowing parameterization and queuing of requests -> Option DQuick Check:
Command pattern = encapsulate request [OK]
- Confusing Command with Singleton or Factory patterns
- Thinking Command creates instances instead of encapsulating actions
- Mixing Command with Strategy pattern
execute method in a Command interface?Solution
Step 1: Recall Command interface basics
The Command interface typically defines a simpleexecute()method without parameters to perform the action.Step 2: Analyze options
The options with parameters (String[], int commandId, String commandName) or return types are not standard in Command pattern interfaces; the command object itself holds necessary data.Final Answer:
void execute(); -> Option BQuick Check:
Command execute method = void execute() [OK]
- Adding parameters to execute method unnecessarily
- Confusing Command with other patterns that require arguments
- Assuming execute returns a value
class Light {
turnOn() { console.log('Light is ON'); }
turnOff() { console.log('Light is OFF'); }
}
class TurnOnCommand {
constructor(light) { this.light = light; }
execute() { this.light.turnOn(); }
}
class TurnOffCommand {
constructor(light) { this.light = light; }
execute() { this.light.turnOff(); }
}
class RemoteControl {
setCommand(command) { this.command = command; }
pressButton() { this.command.execute(); }
}
const light = new Light();
const remote = new RemoteControl();
remote.setCommand(new TurnOnCommand(light));
remote.pressButton();
remote.setCommand(new TurnOffCommand(light));
remote.pressButton();Solution
Step 1: Trace first command execution
The remote sets the command to TurnOnCommand and calls execute, which calls light.turnOn(), printing 'Light is ON'.Step 2: Trace second command execution
The remote sets the command to TurnOffCommand and calls execute, which calls light.turnOff(), printing 'Light is OFF'.Final Answer:
Light is ON\nLight is OFF -> Option AQuick Check:
TurnOn then TurnOff commands print ON then OFF [OK]
- Mixing order of commands
- Assuming commands execute immediately without setting
- Confusing method names turnOn and turnOff
class Light {
turnOn() { console.log('Light is ON'); }
}
class TurnOnCommand {
constructor() { }
execute() { this.light.turnOn(); }
}
const light = new Light();
const command = new TurnOnCommand();
command.execute();Solution
Step 1: Check TurnOnCommand constructor
The constructor does not accept or assign the Light object tothis.light, sothis.lightis undefined.Step 2: Analyze execute method call
Callingthis.light.turnOn()fails becausethis.lightis undefined, causing an error.Final Answer:
The TurnOnCommand constructor does not receive or store the Light object -> Option CQuick Check:
Missing light reference in command = error [OK]
- Ignoring missing receiver object in command
- Thinking missing turnOff method causes error here
- Assuming execute must return a value
Solution
Step 1: Understand undo with Command pattern
Each Command object should implement bothexecute()andundo()methods to reverse its action.Step 2: Evaluate design choices
Storing a history stack of Command objects allows callingundo()on the last command efficiently. Other options either lack command encapsulation or are inefficient.Final Answer:
Store a history stack of Command objects and call an undo() method on the last command -> Option AQuick Check:
Undo = command history stack with undo() [OK]
- Using string logs instead of command objects
- Not implementing undo in commands
- Reloading entire document is inefficient
