| Users | Requests per Second (RPS) | Validation Complexity | Latency Requirements | Storage Needs |
|---|---|---|---|---|
| 100 users | ~50 RPS | Simple synchronous validation | Low latency (~100ms) | Minimal, mostly in-memory |
| 10,000 users | ~5,000 RPS | Moderate complexity, caching possible | Low latency (~50-100ms) | Moderate, some persistent logs |
| 1,000,000 users | ~500,000 RPS | High complexity, distributed validation | Very low latency (~20-50ms) | High, distributed storage and caching |
| 100,000,000 users | ~50,000,000 RPS | Very high complexity, sharded and cached | Ultra low latency (~10-20ms) | Very high, multi-region storage and caching |
Move validation in LLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
The first bottleneck is the validation logic CPU and memory on the application servers. As user count and requests grow, the synchronous move validation consumes significant CPU cycles and memory, causing increased latency and request queuing.
At medium scale, the database or state store that holds game state for validation also becomes a bottleneck due to high read/write operations.
- Horizontal scaling: Add more application servers behind a load balancer to distribute validation requests.
- Caching: Cache frequently accessed game state to reduce database hits during validation.
- Asynchronous validation: For less critical moves, validate asynchronously to reduce latency impact.
- Sharding: Partition game state by user or game session to distribute load across multiple databases.
- Use of in-memory data stores: Employ Redis or similar for fast state access during validation.
- Optimize validation logic: Simplify or precompute rules to reduce CPU usage.
- At 10,000 users (~5,000 RPS), assuming each validation request is ~1KB, bandwidth needed is ~5MB/s.
- Database must handle ~5,000 QPS, near upper limit for a single instance; requires read replicas or caching.
- Application servers: each handles ~2,000 concurrent connections; need ~3 servers minimum.
- Storage: logs and game state grow with users; estimate ~10GB/day at 10K users, scaling linearly.
Start by defining the scale and requirements clearly. Identify the critical path for move validation and its latency needs. Discuss bottlenecks in CPU, memory, and database. Propose scaling solutions step-by-step, justifying each with the bottleneck it addresses. Mention trade-offs like consistency vs latency. Use real numbers to show understanding.
Your database handles 1000 QPS. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add read replicas and implement caching to reduce direct database load before scaling vertically or sharding.
Practice
Solution
Step 1: Understand move validation role
Move validation checks if a requested change or move follows system rules.Step 2: Identify its main goal
The goal is to prevent invalid or harmful actions that could break system logic or data.Final Answer:
To ensure changes follow rules and prevent invalid actions -> Option DQuick Check:
Move validation = Prevent invalid moves [OK]
- Confusing validation with data storage
- Thinking validation speeds up by skipping checks
- Mixing validation with UI creation
Solution
Step 1: Check syntax correctness
if move.position < 0 or move.position > max_position: return False uses proper comparison operators and syntax for boundary check.Step 2: Identify errors in other options
if move.position == 'any': return True uses string instead of number, C uses assignment (=) instead of comparison (==), D uses invalid syntax 'then'.Final Answer:
if move.position < 0 or move.position > max_position: return False -> Option CQuick Check:
Boundary check uses < and > with proper syntax [OK]
- Using assignment '=' instead of comparison '=='
- Using invalid keywords like 'then'
- Checking position against wrong data types
move.position = 5 and max_position = 4?
def validate_move(move, max_position):
if move.position < 0 or move.position > max_position:
return False
return True
print(validate_move(move, max_position))Solution
Step 1: Evaluate condition with given values
move.position = 5, max_position = 4, so 5 > 4 is true.Step 2: Determine return value
Since condition is true, function returns False.Final Answer:
False -> Option BQuick Check:
5 > 4 triggers False return [OK]
- Assuming 5 <= 4 is true
- Confusing return values
- Ignoring condition logic
def validate_move(move, max_position):
if move.position <= 0 or move.position >= max_position:
return False
return TrueSolution
Step 1: Analyze boundary conditions
Condition disallows move.position <= 0, so position 0 is invalid.Step 2: Check if position 0 should be allowed
Usually position 0 is valid boundary, so disallowing it is a bug.Final Answer:
It incorrectly disallows move.position = 0 -> Option AQuick Check:
Check boundary inclusiveness carefully [OK]
- Confusing < and <= in conditions
- Assuming 0 is always invalid
- Ignoring inclusive vs exclusive boundaries
Solution
Step 1: Consider modular design benefits
Separating boundary and occupancy checks into modules improves clarity and reusability.Step 2: Evaluate scalability and maintainability
Modular validators can be updated independently and composed flexibly, aiding scalability.Final Answer:
Use separate modular validators for boundary and occupancy checks, composed in sequence -> Option AQuick Check:
Modular design = scalable and maintainable [OK]
- Combining all logic makes code hard to maintain
- Skipping important checks reduces reliability
- Validating after applying moves risks inconsistent state
