Loading...
Loading...
Backend interview guide
Scaling, caching, databases, queues, load balancing and designing common systems. Every answer is short enough to say aloud, and every question links to the lesson that teaches it.
60 questionsLast updated
Forgetting to set lastRefill = now, so old time is counted on every call and the limit leaks; forgetting the Math.min cap, so an idle client saves up a huge burst; using the wall clock, which can jump backwards; and doing the check and the decrement without a lock.
Each server would have its own buckets, so a user could get five times the limit by hitting different servers. The state has to move to a shared store such as Redis, where the check and update are done atomically; the next lesson covers that.
Lesson: Implementing a token bucket in JavaMany people share one public IP through NAT: a hostel, a college lab, an office or a mobile network. A strict per-IP limit blocks all of them together. At the same time attackers can rotate through many IPs, so IP limits should be generous and backed by per-user or per-account limits.
Lesson: Where to apply limits and returning 429429 when one client has used up its own limit: the problem is that client. 503 when the server itself is overloaded or down for everyone, for example while shedding load. Both can carry Retry-After.
In-memory counters split the traffic, so each user would get ten times the limit. I would move the counter to a shared store such as Redis: INCR on a key per user per window plus EXPIRE, or a Lua script for a token bucket so the whole check is atomic.
A token bucket. Real apps send short bursts, for example loading a page that makes five calls at once, and a token bucket allows a burst up to its capacity while keeping the long-run rate. A leaky bucket would queue those calls and add delay; it suits steady outgoing work such as sending SMS.
Lesson: Rate limiting practiceA race condition: an unsynchronized read-check-write of the token count, or a check-then-put on a plain HashMap that can create two buckets for one key. I would make tryAcquire synchronized and use ConcurrentHashMap.computeIfAbsent.
Wait the number of seconds in Retry-After. If there is no header, back off exponentially (1 s, 2 s, 4 s… up to a cap) with some random jitter, and give up after a few tries with a clear message to the user.
It is the simplest and cheapest: one counter per key, and in Redis just INCR and EXPIRE. For generous limits a double burst at the boundary does no real harm. I would only pay for a sliding log or counter where the limit is small and sensitive.
Roughly: memory read about 100 ns, SSD random read about 100 µs, a round trip inside a datacenter about 0.5 ms, a simple database query by key around 1 ms, and a cross-continent round trip about 150–200 ms. The ratios matter more than the exact figures.
Lesson: Useful numbers for estimationIt turns division by 86,400 into dropping five zeros, which I can do quickly and without mistakes while talking. The answer is about 14% low, which does not change the design, and I can mention it.
Lesson: Useful numbers for estimationIt is the reason caches work: keeping hot data in memory, such as product details in Redis or the database buffer pool, turns a disk read into a memory read. It also explains why a design that needs many disk reads per request will be slow.
Lesson: Useful numbers for estimationIt is the ratio between the busiest moment and the daily average. Normal consumer apps see about 2–3× in the evening; event-driven apps (sales, ticket openings, exam results) can see 10× or more. If I have real traffic data I compute it from the busiest hour; otherwise I state an assumption.
Lesson: Estimating daily users to requests per secondIt depends on what one server can do. If a ShopLite instance handles about 500 simple requests a second, I need about 5 servers at 70% load plus a spare, behind a load balancer. That is moderate: no exotic technology, but more than one box.
Lesson: Estimating daily users to requests per secondCompare it with real metrics: requests per second by hour from the load balancer or Actuator metrics, the real read/write ratio from database statistics, and the real peak factor from the busiest hour. Then update the assumptions for the next estimate.
Lesson: Estimating daily users to requests per secondThey are thousands of times larger than rows, so they would make the database huge, slow to back up and slow to replicate. Object storage such as S3 is cheaper per GB, keeps its own copies and works well with a CDN. The database keeps only the key or URL.
Lesson: Estimating storage and bandwidth over yearsNot for storage: 150 GB across a primary and replicas fits easily on one MySQL server. I would shard only if writes per second or the data size outgrew one primary, and the estimate says neither happens soon.
Lesson: Estimating storage and bandwidth over yearsBecause growth compounds. At 30% a year, year five is almost three times year one, and the five-year total is nearly twice a flat estimate. Ignoring growth leads to buying too little disk and planning migrations too late.
Lesson: Estimating storage and bandwidth over yearsItems × bytes per cached item × the hot share × overhead. With the 80/20 rule I cache the popular 20%; for 150,000 products at 5 KB that is about 150 MB, doubled for Redis overhead to about 300 MB, so a 1 GB node is plenty.
Lesson: Using estimates to pick a designAssumptions first: DAU, requests per user, peak factor, read/write ratio. Then traffic: average and peak RPS. Then storage: records × size × days × years, plus media. Then decisions: servers, cache, replicas, object storage. Finally what would change them, such as 10× growth.
Lesson: Using estimates to pick a designI redo the database line with their number. At 50% hits, 17,000 peak reads become 8,500 database reads instead of 3,400, which tips us into needing a read replica or two. Showing how the decision changes matters more than defending my guess.
Lesson: Using estimates to pick a designAssuming 20 requests per user per day, that is 2 × 10⁸ requests a day, divided by about 10⁵ seconds: about 2,000 QPS, really about 2,300. With a 5× peak I would design for roughly 12,000 QPS, and if 1 in 50 requests writes, about 230 writes a second at peak.
Lesson: Estimation practiceUnit conversions between KB and bytes, MB and KB, or ms and µs. Each is a factor of 1,000. I write the unit next to every number and check that they cancel to what I want.
Lesson: Estimation practiceI ask which links are hot. If clicks are spread out, the 80/20 rule gives 20% of all links × about 100 bytes × 2 for overhead. If most clicks hit recent links, I cache only, say, the last week: 7 million links × 200 bytes, about 1.4 GB.
Lesson: Estimation practiceAccept their number, redo the affected line and say what changes. The point of writing assumptions down is that one can be swapped without redoing everything, and showing which decision flips is the useful part.
Lesson: Estimation practiceA link is created once and opened many times, often 100 times or more. So redirects decide the design: they must be a fast key lookup, mostly served from a cache, and they must scale out with more app servers.
Lesson: Design a URL shortenerI would encode a number from a shared counter in base62. To avoid calling the counter on every create, each server takes a range of ids, for example 1,000 at a time, from a database row. Codes never collide, and I can start at 62⁶ so every code has 7 characters.
Lesson: Design a URL shortenerFor public share links it is usually fine. If links can point to private content, I would use random codes from SecureRandom with a uniqueness check, or add a secret part, so nobody can walk through the codes.
That link becomes a hot key, but it is one small entry, so the cache serves it from memory on every app server or from Redis. A CDN or browser caching can also help if we accept 301 or short cache times.
Lesson: Design a URL shortenerThe base62 idea is the same, but paste keys must be unguessable because unlisted pastes are private by link. I draw 8 random symbols from SecureRandom and insert only if the key is free, instead of using a counter.
The object becomes an orphan that nobody can reach, which is harmless. A periodic job can list objects with no matching row and delete them. Writing the row first would be worse, because readers could find a row with no text.
Lesson: Design PastebinWithout it one user could upload huge files and fill storage or slow reads for everyone. A clear limit, such as 512 KB with a 413 response, keeps cost and latency predictable.
Lesson: Design PastebinA client's requests are spread across servers, so each one sees only part of the traffic. With 20 servers a client could get up to 20 times the limit. Splitting the limit per server also fails when the load balancer sends traffic unevenly.
Lesson: Design a rate limiter as a serviceIt depends on the endpoint. For browsing I fail open so the shop keeps working; for login and OTP I fail closed because leaving them open invites abuse. I also put a short timeout on the Redis call so a slow store does not slow the whole API.
Lesson: Design a rate limiter as a serviceI record allowed and rejected counts per rule and per client and watch them on a dashboard. If good clients hit 429 often, the limit is too low; if a rule never rejects anything during an attack, it is too high or keyed wrongly.
Lesson: Design a rate limiter as a serviceServices call a Notification API with user, template and data. The API checks preferences and puts one job per channel on email, SMS and push queues, plus a separate urgent queue for OTPs. Workers read the queues, render templates and call providers, retrying with backoff and moving repeated failures to a dead-letter queue.
Lesson: Design a notification systemProviders are slow and sometimes down. Calling them in the request would make checkout slow and fail with them. With a queue the API answers 202 at once and workers retry quietly in the background.
Lesson: Design a notification systemThe API reads the user's preferences per category and drops channels they turned off, except for security messages. Non-urgent messages that fall in the user's quiet hours, such as 22:00 to 08:00 in their time zone, are delayed until the morning, and a per-user daily cap limits promotions.
Lesson: Design a notification systemFor most users fan-out on write, because reads are far more frequent than posts and push makes each read a single lookup. For accounts with a huge following I would pull their posts at read time. So the real answer is a hybrid with a follower threshold.
Lesson: Design a news feed (basic version)With a cursor, not an offset. Each page returns the time and post id of the last item, and the next request asks for older items. New posts at the top then do not shift the pages, so nothing is repeated or skipped.
Lesson: Design a news feed (basic version)A few seconds is fine for a feed, so I use a queue: the post service saves the post, publishes an event and returns. Fan-out workers update feeds in the background, which is eventual consistency.
Lesson: Design a news feed (basic version)I would give the six parts in about two minutes: the problem and who uses it, the architecture as boxes and a request flow, the main data, one hard problem with how I fixed it, and what I would change next. I keep numbers real, such as how many users I tested with.
Lesson: Explaining the design of your own projectFor a small user base, one stateless Spring Boot service and one MySQL database is simple to build, test and run. I kept it stateless with JWT so I can add a second instance behind a load balancer without code changes.
Lesson: Explaining the design of your own projectI would correct it honestly: I tested it with a specific load, and it is designed so it can scale, for example stateless servers and indexed queries. Then I explain what I would add to reach a bigger number, instead of claiming it already does.
Lesson: Explaining the design of your own projectTwo minutes on requirements, two on estimates, one on the API, two on how codes are generated, two on the data model and read path, and one on extras like aliases and expiry. Then I ask which part the interviewer wants me to go deep on.
Lesson: Classic design questions practiceI compare push inserts per day, posts times average followers, with pull lookups per day, feed reads times accounts followed, and I look at the largest account. Small authors are pushed, very large ones are pulled, and most real apps end up hybrid.
Lesson: Classic design questions practiceThe user waits for slow outside providers, and the order fails or is retried when one of them is down, which can send duplicates. Enqueue one job per channel, answer 202, and let workers send with retries and dedup keys.
Lesson: Classic design questions practiceThat code becomes a hot key, but it is one small entry, so the cache serves it from memory and the database is not touched. If we do not need click counts for it, a 301 or a CDN can take even more load off our servers.
Lesson: Classic design questions practiceNumbers decide the design. In the waiting-queue problem, 2 million users against a booking limit of 500 per second shows that a queue is needed and that it takes about 67 minutes to clear.
Lesson: Mock design round with a checklistI restate it to confirm, then say what changes and what stays the same, and name the new trade-off. I avoid restarting, because a clear design should let me change one part.
Lesson: Mock design round with a checklistI do timed mock rounds with the checklist, then score myself with a rubric of eight items. I practise the items I miss most, such as trade-off sentences, instead of only doing new questions.
Lesson: Mock design round with a checklistThey usually go through different boxes: reads hit caches and replicas, writes hit the primary database and often a queue. Two short numbered flows are easier to follow and show that I know where each kind of load goes.
Lesson: Drawing clear architecture diagramsToo many things that are not on the request path, arrows in both directions, unnamed boxes and missing step numbers. I keep only the boxes a request passes through and put things like logging and auth in one note.
Lesson: Drawing clear architecture diagramsI walk a request through the numbered steps and look for boxes with only one copy, such as one load balancer or one primary database. Each one is a single point of failure, and I say how I would add a standby or a replica.
Lesson: Drawing clear architecture diagramsWhether there is slow or fan-out work that must leave the request path, and how much. For a few events per second a simple queue or even a database table is enough; Kafka fits very high event rates or many consumers replaying a stream.
Lesson: Common mistakes in fresher answersEvery part must be up for the request to work, so their availabilities multiply. Three parts at 99.9% give about 99.7%, which is roughly three times the downtime of one part.
Lesson: Common mistakes in fresher answersI show the numbers that make it enough and say exactly which limit I would hit first and what I would add then. A simple design with clear thresholds is a strength, not a weakness.
Lesson: Common mistakes in fresher answersWhen reads load the primary database and indexes and caching are already in place. Replicas serve reads, but they lag a little, so reads that must see the user's own latest write still go to the primary.
Lesson: System design interview questions and short answersA wrapper around a remote call that stops calling a failing service for a while after many errors, failing fast instead of waiting. After a pause it lets a few test calls through and closes again if they succeed.
Lesson: System design interview questions and short answersRequest rate, error rate and p95/p99 latency per endpoint, plus database connections and queue lengths. These four show most problems before users report them.
Lesson: System design interview questions and short answersEach lesson has quizzes, practice and more interview questions on the same topic.
Open the first lesson