Expert · Deployment and scaling · topic 51 of 54 · 30 min
System design: planning a big backend
Explanation
A simple way to approach any design question
- Requirements: what must it do (features)? How fast, how reliable, how big (non-functional requirements)?
- Numbers: how many users, requests per second, how much data per year? Rough is fine.
- API: the main endpoints, with inputs and outputs.
- Data model: the main tables or collections and their keys.
- High-level diagram: clients, load balancer, app servers, database, cache, queue, CDN.
- Bottlenecks: what breaks first at 10 times the traffic, and how you would fix it.
Back-of-the-envelope numbers
Daily active users: 10,00,000 (10 lakh)
Requests per user per day: 20
Requests per day: 2,00,00,000 (2 crore)
Seconds in a day: 86,400
Average: 2 crore / 86,400 = about 232 requests per second
Peak (5x, evening rush): about 1,160 requests per second
Storage: 1 lakh new records a day x 500 bytes = 50 MB a day, about 18 GB a yearMonolith or microservices?
A monolith is one app that does everything, deployed as one unit. Microservices split the system into many small apps (users, orders, payments), each with its own database and deploys, talking over the network. Microservices let big teams work and deploy separately, but they add real costs: network failures between services, harder debugging, data spread across databases and much more to monitor.
| Modular monolith | Microservices | |
|---|---|---|
| Deploy | One app | Many apps, each on its own |
| Calls between parts | Function calls (fast, reliable) | Network calls (slower, can fail) |
| Good for | Small and medium teams, most products | Many teams that need to ship separately |
| Main risk | Becoming a tangled "big ball of mud" | Complexity, outages between services |
Queues, events and consistency
A message queue holds jobs or events until a worker takes them, for example RabbitMQ, Kafka, Amazon SQS or Redis streams. Instead of doing everything inside the request, the API saves the order, puts an "order.placed" event on the queue and answers quickly. Workers then send the SMS, update the restaurant screen and record analytics. If a worker is slow or down, the events wait safely instead of failing the order.
When data is copied across servers, you sometimes have to choose. If the network between them breaks, a system can either refuse some requests so it never shows wrong data (consistency first), or keep answering with data that may be slightly old (availability first). A bank balance or a train seat needs consistency. A like counter or "people viewing this hotel" can be a little out of date.
Worked example: a URL shortener
- Requirements: make a short link from a long URL; visiting the short link redirects fast; links last for years; about 1 lakh new links and 1 crore visits a day.
- API: POST /api/links { url } returns { code: "aZ3k9Qx" }; GET /:code answers 301 or 302 with a Location header.
- Data model: links(code PRIMARY KEY, long_url, user_id, created_at).
- Codes: take a unique number from a counter (or the row id) and write it in base 62 (0-9, a-z, A-Z). 7 characters give 62^7, about 3.5 trillion codes.
- Reads are 100 times more than writes, so cache popular codes in Redis and add read replicas; count clicks through a queue so redirects stay fast.
const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
function encodeBase62(n) {
if (n === 0) return '0';
let out = '';
while (n > 0) {
out = ALPHABET[n % 62] + out;
n = Math.floor(n / 62);
}
return out;
}
console.log(encodeBase62(125)); // '21'
console.log(encodeBase62(1000000000)); // '15ftgG'Short case: the Tatkal rush
Tatkal train booking opens at a fixed time each day, so lakhs of people press "Book" in the same minute for a few thousand seats. A design for this kind of rush usually: puts users in a virtual waiting queue so the booking service gets a steady flow; keeps seat counts in a fast cache for display, but makes the final seat check inside a database transaction so a seat is never sold twice; rate limits each user and IP and blocks bots; serves all static pages from a CDN; and makes payment steps idempotent (safe to retry) so a double click does not charge twice.
Watch the lesson
System design: planning a big backend · 1/7
System design means planning how the parts of a big backend fit together, before you build.
Prefer a video by a teacher? Find free videos on “system design for beginners url shortener” on YouTube ↗
In real life: A food delivery app during an IPL final
During a big cricket final, orders on a food delivery app jump at the innings break. The team planned for this with numbers: normal peak 500 orders a minute, expected 5,000. The order API stays a modular monolith on many stateless servers. Placing an order only saves it and puts an event on a queue, so the API answers in under a second. Workers then notify restaurants, assign riders and send SMS at their own pace. Restaurant menus are cached, and images come from a CDN. Nothing here is exotic; it is the basic toolkit, sized with real numbers.
Practice (0/3 done)
Write estimateRps(dailyUsers, requestsPerUser, peakFactor) for back-of-the-envelope sums. perDay = dailyUsers x requestsPerUser. average = perDay / 86400, rounded UP to a whole number. peak = perDay x peakFactor / 86400, rounded UP. Return { perDay, average, peak }.
Short links use base 62. With the alphabet "0-9, then a-z, then A-Z" (given in the starter), write encodeBase62(n) for a whole number n >= 0 (0 gives "0") and decodeBase62(code) that turns a code back into the number. Example: 62 is "10" and 3843 is "ZZ".
Design a flash sale for a shopping app: 10,000 phones at a special price go on sale at 12:00 noon, and 20 lakh people are expected to try in the first five minutes. Use the six steps from this lesson.
Quick quiz
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.