| Scale | Users (Members) | Books | Loans Active | System Changes |
|---|---|---|---|---|
| 100 users | 100 | 1,000 | 50 | Simple in-memory data structures, single server, no caching needed |
| 10,000 users | 10,000 | 100,000 | 5,000 | Use database for persistence, add indexing on books and members, basic caching for frequent queries |
| 1,000,000 users | 1,000,000 | 10,000,000 | 500,000 | Database sharding by member ID or book ID, read replicas, caching layer (Redis), horizontal scaling of application servers |
| 100,000,000 users | 100,000,000 | 1,000,000,000 | 50,000,000 | Advanced sharding and partitioning, distributed caching, microservices for different domains (Book, Member, Loan), CDN for static content, asynchronous processing for loan updates |
Class design (Book, Member, Librarian, Loan) in LLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
At small scale, the database is the first bottleneck because it handles all queries for books, members, and loans. As users grow, the database query load and storage needs increase rapidly. Without indexing and caching, response times degrade.
At medium scale, the application server CPU and memory become bottlenecks due to processing many concurrent requests and managing business logic.
At large scale, network bandwidth and data partitioning challenges arise, especially for loan transactions and book availability updates.
- Database: Add indexes on frequently queried fields (book ID, member ID). Use read replicas to distribute read load. Implement sharding by member or book ID to split data across servers.
- Caching: Use Redis or Memcached to cache frequent queries like book availability and member info.
- Application Servers: Horizontally scale by adding more servers behind a load balancer to handle more concurrent users.
- Data Partitioning: Partition loans and books by region or category to reduce cross-server queries.
- Asynchronous Processing: Use message queues for loan updates and notifications to reduce synchronous load.
- Microservices: Separate Book, Member, and Loan services to isolate load and scale independently.
- Requests per second (QPS): For 1M users, assume 10% active daily, each making 5 requests/hour -> ~140 QPS.
- Storage: 10M books at 1 KB metadata each -> ~10 GB; 1M members at 1 KB each -> ~1 GB; 500K active loans at 1 KB each -> ~0.5 GB.
- Bandwidth: Assuming 1 KB per request/response, 140 QPS -> ~0.14 MB/s (~1.1 Mbps), manageable with standard network.
Structure your scalability discussion by first describing the system components and their interactions. Then, analyze how load grows with users and data. Identify the first bottleneck clearly. Propose targeted solutions for each bottleneck, explaining why they fit. Use concrete numbers to justify your choices. Finally, mention trade-offs and future scaling steps.
Your database handles 1000 QPS. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add read replicas to distribute read queries and reduce load on the primary database. Also, implement caching for frequent reads to reduce database hits. Consider query optimization and indexing if needed.
Practice
Solution
Step 1: Identify the class representing a book
The class namedBooklogically holds details about books such as title, author, and ISBN.Step 2: Confirm other classes' roles
Memberis for library users,Librarianmanages operations, andLoantracks borrowing, so they don't store book details.Final Answer:
Book -> Option BQuick Check:
Book class stores book info [OK]
- Confusing Member with Book class
- Assigning book details to Loan class
- Thinking Librarian stores book info
borrowBook inside the Member class in Python?Solution
Step 1: Understand method definition in Python classes
Instance methods must haveselfas the first parameter to access object data.Step 2: Check method parameters for borrowing a book
The method needs the book to borrow, so it should accept abookparameter afterself.Final Answer:
def borrowBook(self, book): -> Option DQuick Check:
Instance method with self and book param [OK]
- Omitting self parameter
- Not passing book argument
- Defining method without parameters
class Loan:
def __init__(self, book, member):
self.book = book
self.member = member
loan = Loan('1984', 'Alice')
print(loan.book, loan.member)Solution
Step 1: Analyze the Loan class constructor
The constructor__init__assignsbookandmemberto instance variables.Step 2: Check the print statement output
Printingloan.bookandloan.memberoutputs the strings '1984' and 'Alice' separated by space.Final Answer:
1984 Alice -> Option AQuick Check:
loan.book and loan.member print values [OK]
- Expecting object memory address output
- Confusing variable names with strings
- Assuming error due to parameters
Librarian class:class Librarian:
def __init__(self, name):
self.name = name
def addBook(book):
print(f"Adding {book} to library")Solution
Step 1: Check method parameters in class
Instance methods must includeselfas the first parameter to access instance data.Step 2: Verify addBook method signature
addBooklacksself, so it will cause an error when called on an instance.Final Answer:
Missing self parameter in addBook method -> Option AQuick Check:
Instance methods need self param [OK]
- Thinking print syntax is wrong
- Expecting constructor to return value
- Believing class names must be lowercase
Solution
Step 1: Understand responsibilities of each class
Bookstores book info,Memberrepresents users,Loantracks borrow records, andLibrarianmanages library operations.Step 2: Identify who controls borrowing rules
TheLoanclass should handle checking if a book is currently loaned out before allowing borrowing, as it tracks loan records.Final Answer:
Loan -> Option CQuick Check:
Loan class tracks loan status [OK]
- Putting borrowing logic inside Book class
- Assigning loan status check to Member
- Expecting Librarian class to enforce borrowing rules
