Amazon Java Developer Interview Questions & Answers

amazon icon

Questions with Detailed ExplanationsWith Detailed Explanations

(Last Updated: August 28, 2026)

11. How would you design a URL shortening service?System DesignMediumAmazon

Question Details

Design a URL shortening service with unique aliases, redirect handling, collision avoidance, and scale considerations.

Short Interview Answer (30-60 seconds)

At a high level, this service turns long URLs into short links and quickly redirects users to the original page. The main challenge is keeping every alias unique while making the read-heavy redirect path fast. I would explain it in two main flows: creating a short link and redirecting an existing one. Stateless Java replicas handle requests, the Primary Database stores the official mapping, and the Distributed Cache speeds up redirects. The trade-off is that cached or replicated reads can briefly be behind the primary data.

Detailed Explanation

The goal is to turn a long web address into a short alias. Later, anyone opening that alias should reach the original address very quickly. The hard part is balancing correctness and speed. New aliases must not conflict with existing ones, while redirects happen often and should stay fast. The diagram separates these concerns into a create path and a redirect path. It also moves optional click analytics into background work, so recording clicks does not slow the main redirect response.

Useful Questions to Ask the Interviewer
  1. Should users be allowed to choose their own custom aliases?
  2. How much larger do we expect redirect traffic to be than create traffic?
  3. Do we need click analytics for every redirect?
How would you design a URL shortening service? diagram
How to Explain It in an Interview
1. Explain the entry path and guardrails

I would start by saying both flows use the same entry layer. DNS resolves the service address, and clients connect using HTTPS. The Load Balancer / API Gateway then sends requests to the URL Service.

The Guardrails can apply API Key / Tenant Auth when needed. They also provide Rate Limiting, URL Validation, and Alias Validation. An invalid URL or alias returns 400. An existing custom alias returns 409. A request over the rate limit returns 429.

2. Explain how a short link is created

For the create path, the client sends POST /shorten. The request contains a long URL and may include a custom alias.

A stateless Java 21/25 URL Service handles the request. Inside a JVM replica, the REST Controller sends it to the Shorten Handler. If a custom alias was supplied, the Alias Generator validates its uniqueness. Otherwise, it generates a random Base62 token, checks whether that token already exists, and retries after a collision.

The Mapping Repository writes the alias and long URL to the Primary Database. The database has a UNIQUE(alias) index, which is the final collision protection. After the database write succeeds, the Cache Client updates the Distributed Cache. The service then returns a JSON response containing the short URL.

3. Explain the fast redirect path

For the redirect path, the client sends GET /{alias}. The Redirect Handler asks the Distributed Cache for the long URL first.

On a cache hit, the long URL is returned quickly. The service then sends an HTTP 301 or 302 redirect to the client.

If the cache misses, the service performs a SQL read for the alias. The read can use the Primary Database or the optional Read Replica. When the mapping is found, the service puts it into the cache and returns the redirect. If the alias does not exist, the client receives 404.

4. Explain scaling and background analytics

The URL Service runs as multiple stateless JVM replicas. Separate JVM replicas do not share heap state. This lets the Load Balancer / API Gateway spread requests across more replicas as traffic grows.

The Primary Database remains the source of truth and handles all writes. The optional Read Replica receives data asynchronously from the primary and can serve extra lookup traffic. Because that copy happens later, it can be slightly behind the primary.

Click analytics is optional and stays outside the critical redirect path. The service can send a click event to the Event Queue / Stream. The event then goes to the Analytics / Metrics Sink in the background.

5. Explain the main trade-offs and operations

Redirect traffic is read-heavy, so the Distributed Cache removes many reads from the database. The cache can be repopulated after a miss, but it may briefly contain older data.

Random Base62 tokens are simple to generate, but collisions are still possible. The service therefore checks for an existing token and retries. The database unique index remains the final protection.

Metrics, Structured Logs, Distributed Tracing, and Alerts help operate the system. They show request rates, errors, cache behavior, database latency, JVM health, and other failures without changing the main request flow.

Engineering Considerations / Design Trade-offs

The benefit is that redirects stay fast because the Distributed Cache handles many repeated lookups. Stateless JVM replicas also make it easy to add more service capacity. The downside is that cached data can briefly be older than data in the Primary Database. The optional Read Replica can handle extra reads, but it may also be slightly behind because replication happens asynchronously. Random Base62 tokens are easy to create, but collisions can happen. We accept that because the service retries, while the UNIQUE(alias) index gives the database a final safety check.

Why Interviewers Ask This

Interviewers use this problem to see how you split a system into clear flows and choose where correctness matters most. They want to see whether you can make a read-heavy path fast without losing unique aliases. They also test your judgment around caching, database ownership, replicas, background analytics, rate limits, failures, and the trade-offs between speed, simplicity, and correctness.

Interviewer may ask next
How would the design change if redirect traffic became much larger?

I would keep the same basic design and scale the existing redirect path. First, I would add more stateless URL Service JVM replicas behind the Load Balancer / API Gateway. Because separate replicas do not share heap state, requests can be spread across them without relying on local session data.

The Distributed Cache would remain the main fast path. A high cache hit rate means most redirects avoid a database read. If database lookups still become heavy, I would use the optional Read Replica shown in the diagram for more alias lookups. All writes would continue going to the Primary Database.

Correctness stays the same. The primary still stores the official mapping, and its UNIQUE(alias) index still protects aliases. The main downside is more operational complexity. The Read Replica can also be slightly behind the primary because its replication is asynchronous.

What happens if two requests try to create the same alias at the same time?

I would keep the current create path and let the Primary Database make the final decision. For a custom alias, two requests could both check the alias before either write finishes. That means the earlier uniqueness check alone cannot safely prevent a race.

The important protection is the UNIQUE(alias) index in the Primary Database. Only one conflicting insert can succeed. The other custom-alias request receives a conflict and returns 409.

For an automatically generated alias, the Alias Generator creates a random Base62 token and checks whether it already exists. If a collision appears, it generates another token and retries. A collision can still happen between the check and database write, so the unique index remains the final safety check.

The downside is that a rare collision needs another generation attempt and another database operation.

12. How would you design a notification system?System DesignMediumAmazon

Question Details

Design a notification system that can deliver messages reliably and at scale, with attention to retries, fanout, and failure handling.

Short Interview Answer (30-60 seconds)

At a high level, I would separate accepting a notification from delivering it in the background. The main challenge is reliable fanout across many recipients and channels while handling provider failures. I would explain the design in three flows: request acceptance, fanout, and channel delivery. The API saves the request and an outbox record, workers publish it to a durable queue, and delivery workers call providers. Retries and a DLQ handle failures. The trade-off is eventual delivery and more operational complexity.

Detailed Explanation

The system must accept a notification request, save it safely, and deliver it through email, SMS, push, or webhook. The hard part is that delivery happens outside our system, so providers can be slow or fail. One request may also become many delivery jobs for different people and channels. The design separates request acceptance from background delivery. It adds retries, a dead letter queue for failed work, status tracking, and monitoring. This lets the API respond quickly while the delivery pipeline handles slow providers and failures safely.

Useful Questions to Ask the Interviewer
  1. Which delivery channels are required?
  2. Can one notification target many recipients?
  3. How quickly should the API accept requests and delivery happen?
  4. When a provider fails, should we retry only or use a secondary provider when configured?
How would you design a notification system? diagram
How to Explain It in an Interview
1. Accept the request safely

“For the first step, I would make accepting the request fast and safe.”

Client Applications send an HTTPS notification request to the API Gateway. The gateway handles authentication, authorization, validation, rate limits, and an idempotency key. The idempotency key helps recognize the same request sent again.

The request reaches stateless Notification API Service replicas running in separate JVMs. The service validates the request, selects the template, looks up user preferences, and writes notification metadata plus an outbox record to the Notification DB. The client receives 202 Accepted + notificationId.

2. Publish the saved request

“Next, I would move delivery work out of the API request.”

The Outbox Publisher Worker polls the Outbox Table. It publishes a NotificationRequested event to the Message Queue / Event Bus and updates the outbox record state. Because the database write happens first, accepted work remains recorded if publishing has a problem.

3. Fan out into channel jobs

“For fanout, one notification can become several smaller delivery jobs.”

The Fanout Processor consumes the event. It reads the User Profile & Preference Store for preferences, device tokens, and contact data. It creates jobs per recipient and channel.

Jobs go to the Email Queue, SMS Queue, Push Queue, or Webhook Queue. Separate queues let each channel handle its own load.

4. Deliver through workers

“For delivery, I would use separate worker replicas for each channel.”

Email, SMS, Push, and Webhook Workers consume their queues and call the matching provider or customer webhook endpoint. They update the Notification DB with delivery results.

Virtual threads can support many blocking provider calls. They are lightweight JVM threads, but the queues still provide backpressure when work arrives faster than providers can handle it.

5. Handle failures and operate the system

“Finally, I would make failure handling explicit.”

Temporary failures go to the Retry Scheduler / Delayed Retry Queue. It uses exponential backoff, so each retry waits longer, up to a maximum number of attempts. Permanent failures or poison messages go to the DLQ for inspection and manual replay.

Delivery is at least once, so a job may appear again. Consumers and providers must handle duplicates safely. Status can be delivered, failed, or retrying. If configured, a secondary provider can be used when one is unavailable.

Metrics, logs, traces, alerts, and a dashboard provide visibility. Security includes authenticated access, encrypted transport, and protection of PII. We scale by adding API replicas and queue consumers. The trade-off is eventual delivery, added cost, and more complexity for better reliability and scale.

Engineering Considerations / Design Trade-offs

The benefit is that the API can accept requests without waiting for slow providers. The outbox and durable queue reduce the chance of losing accepted work. Separate channel queues and workers also let each channel scale on its own. The downside is more moving parts and operating cost. We must run queues, workers, retry logic, a DLQ, and monitoring. Delivery is at least once, so duplicate jobs can happen and must be handled safely. Delivery is also eventual, so the client may receive 202 Accepted before the message reaches the user. We accept this complexity because it improves reliability and scale.

Why Interviewers Ask This

Interviewers ask this to see how you break a large problem into clear flows. They want to know whether you can separate fast request acceptance from slower background delivery. They also look for good judgment around reliable event publishing, fanout, retries, duplicate handling, backpressure, and failure recovery. A strong answer explains why each part exists and clearly states the cost of extra reliability and scale.

Interviewer may ask next
What would you change if the email provider was unavailable for several hours?

I would keep the same design and rely on the existing retry and fallback path. The Email Worker would still consume from the Email Queue and call the Email Provider. If the provider returns a temporary failure, the job would go to the Retry Scheduler / Delayed Retry Queue instead of being treated as delivered.

The scheduler would use exponential backoff, so each retry waits longer, and it would stop after the configured maximum attempts. If a secondary provider is configured, the system can route delivery there when the primary provider is unavailable. The Notification DB keeps the delivery status, so the notification can remain retrying until delivery succeeds or the retry limit is reached.

If the allowed attempts are exhausted, the job moves to the DLQ / Poison Messages area for inspection and manual replay. The main downside is slower delivery during the outage, plus more retry and provider-handling complexity.

How would this design handle one notification that must be sent to a very large number of recipients?

I would keep the same components and scale the fanout and delivery stages horizontally. The Fanout Processor would still consume the NotificationRequested event and create per-recipient, per-channel jobs. Those jobs would build up in the Email, SMS, Push, and Webhook Queues instead of forcing the API request to wait for every delivery.

I would add more Fanout Processor consumers and more channel delivery worker replicas as load grows. This matches the diagram's scaling model. The queues provide backpressure, which means work waits when providers cannot accept it as quickly as workers can send it. The Notification DB continues tracking delivery status and attempts.

This keeps request acceptance separate from the large delivery burst. The downside is that a very large fanout can take longer to drain, so some messages may be delivered later even though the work remains queued for processing.

13. How would you design a restaurant reservation system?System DesignMediumAmazon

Question Details

Design a restaurant reservation system with table availability, booking flow, and protection against double-booking.

Short Interview Answer (30-60 seconds)

At a high level, the system helps customers find an open table and reserve it safely. The hardest part is stopping two customers from booking the same table and time. I would explain it in three flows: checking availability, creating a reservation, and doing background work. Stateless Spring Boot replicas handle requests, while the primary relational database is the source of truth. Booking uses a transaction, row locks, a conflict-prevention rule, and an idempotency key. The trade-off is stronger booking correctness with more database work.

Detailed Explanation

The system must help a customer find a restaurant table for a chosen date, time, and party size, then reserve that table without another customer taking the same slot. The hard part is that availability can change between the search and the final booking. The diagram handles this by separating the availability lookup from the stricter booking path. It also keeps notifications and expired-hold cleanup outside the main customer response. The primary relational database stores the booking state and is the source of truth.

Useful Questions to Ask the Interviewer
  1. Can one restaurant have many tables with different capacities?
  2. Can reservations overlap when they use different tables?
  3. How long should a temporary table hold stay active?
  4. Should restaurant staff be able to change tables, time slots, and reservations?
How would you design a restaurant reservation system? diagram
How to Explain It in an Interview
1. Start with the entry point and request checks

I would say that customer and staff requests enter through the API Gateway and Load Balancer. Customer requests search availability or submit a booking. Staff requests manage restaurants, tables, time slots, and reservations.

The gateway handles authentication, input validation, rate limiting, and TLS. These checks reject invalid or excessive requests before they reach the Reservation Platform.

2. Explain the availability flow

For the read path, the Availability API receives the restaurant, date, time, and party size. It reads tables, time slots, and existing reservations from the Primary Relational Database. It returns the available slots through the gateway to the customer.

The Reservation Platform uses stateless Spring Boot application replicas. They scale horizontally behind the load balancer. Requests can be handled concurrently with virtual threads, which are lightweight Java threads suited to many blocking I/O tasks.

3. Explain the booking flow

For booking, the customer sends the selected slot and an idempotency key. The Reservation API starts a database transaction, which groups the booking changes into one controlled operation.

Inside the transaction, it checks availability again. It locks the candidate table rows or time-slot records using SELECT FOR UPDATE. It creates a short hold, then inserts the reservation only if no conflicting active reservation exists.

The database also has a unique or exclusion rule that prevents overlapping active reservations for the same table and time. After the transaction commits, the Reservation API returns the reservation details. If a conflict happens, it returns "slot no longer available" and asks the client to refresh availability.

4. Explain retries and background work

The idempotency key prevents the same client retry from creating multiple reservations. This is separate from the database rule that protects the table and time from competing bookings.

After a reservation is created, the Notification Worker sends confirmation and reminder work to External Services for email, SMS, or push delivery. The Scheduled Task or Cleanup Worker removes expired Table_Holds so those slots can be used again.

5. Explain operations and trade-offs

The Primary Relational Database stores Restaurants, Tables, Reservations, Table_Holds, and Time_Slots. Foreign keys protect relationships, while the overlap rule protects booking correctness.

Services send logs, metrics, and traces to Observability. The design also uses least-privilege access, input validation, rate limiting, and TLS. The main trade-off is that availability reads can scale across stateless application replicas, but confirmed bookings still depend on the primary transactional database and its locking rules.

Engineering Considerations / Design Trade-offs

The benefit is that double-booking protection stays close to the Primary Relational Database. A transaction, row locks, and the unique or exclusion rule give one clear place to decide whether a table is still free. The downside is that booking requests can wait when several customers compete for the same table and time. Stateless Spring Boot replicas make the application layer easier to scale, but every confirmed booking still uses the primary transactional write path. Availability reads are simpler and can be handled by any application replica. Notifications and expired-hold cleanup run outside the main response. We accept the extra database work because a correct reservation matters more than a slightly faster incorrect booking.

Why Interviewers Ask This

Interviewers want to see whether you can split a system into clear read, write, and background flows. They also want to see how you protect shared data when two users act at the same time. A strong answer shows judgment about transactions, row locks, idempotency, stateless scaling, security controls, and failure handling. The goal is not memorizing one diagram. It is explaining why each part is needed and what trade-off it creates.

Interviewer may ask next
What would you change if thousands of customers tried to reserve the same popular restaurant at the same time?

I would keep the same basic design, but I would protect the booking path more carefully during the spike. The Availability API can still run across stateless Spring Boot replicas because those requests mainly read current tables, time slots, and reservations. The Reservation API must stay stricter because it decides who actually gets a table.

I would keep the database transaction, availability re-check, row lock, short hold, and unique or exclusion rule. Those controls stop two customers from winning the same table and time. Rate limiting at the API Gateway also matters more during a spike because it limits excessive requests before they reach the platform.

Virtual threads can help each Java replica handle many blocking I/O requests concurrently. They do not remove the database locking cost. The main downside is that very popular slots can produce more lock waiting, so booking responses may become slower even while the design stays correct.

What happens if a customer sends the same booking request several times because the confirmation response was lost?

I would use the idempotency key already shown in the booking flow. The customer sends that key with the booking request, and the Reservation API uses it to recognize the same client retry instead of treating it as a new booking.

The original request still uses the normal transaction. The service re-checks availability, locks the candidate rows or time-slot records, creates the short hold, inserts the reservation if there is no conflict, and commits. If the first request already completed, another request with the same idempotency key must not create a second reservation.

This is different from double-booking protection. The unique or exclusion rule protects a table and time from competing reservations. The idempotency key protects one customer's repeated request from creating duplicates. The downside is that the service must keep enough information about the key and booking result to recognize retries correctly.

14. How would you design a click-tracking and popularity system?System DesignMediumAmazon

Question Details

Design a system to record item clicks, report click totals, and surface the most popular items at scale.

Short Interview Answer (30-60 seconds)

At a high level, I would treat this as a system that records clicks quickly and keeps popular-item counts ready to read. The main challenge is that click events come in fast, but reports and top-item lookups still need to stay fast. I would explain it in three parts: the security and ingestion path, the background counting path, and the read path that serves counts and popular items from cache with a store fallback. The trade-off is that reports may lag a little because some work happens in the background.

Detailed Explanation

The goal is to record every click on an item, keep a total count, and show which items are most popular. The hard part is that clicks can arrive very often, but people still expect quick responses when they ask for totals or top items. The diagram solves this by splitting the system into a fast request path, a background counting path, and a read path that can use saved results when they are already ready. That keeps the main request fast and moves heavier work out of the way.

Useful Questions to Ask the Interviewer
  1. How fresh do the counts need to be?
  2. Do we need exact totals for every time window, or only top items?
  3. Should click events be kept for audit and replay?
How would you design a click-tracking and popularity system? diagram
How to Explain It in an Interview
1. Explain the goal and the main idea

"At a high level, this is a system for recording clicks and ranking popular items." The key point is that writes are frequent, but reads must stay fast. I would say the design keeps the request path short and moves heavier counting work to the background. The diagram uses stateless Java 21/25 Spring Boot services, a raw event store, a queue, a cache, and a pre-aggregated popularity store.

2. Explain the write path

"For the write path, the click first goes through Edge & Security." That layer does WAF and DDoS protection, rate limiting by IP, user, or item, AuthN/AuthZ with API key or OAuth, and request validation and normalization. The Click Ingestion Service then saves the raw click in the Raw Clicks Store, which is append-only and partitioned by date. It also publishes the event to the Message Queue / Stream. The service returns 202 Accepted with an eventId, so the user does not wait for the background work.

3. Explain the read path

"For the read path, the Click Query Service handles click totals and top-N popular items." It first checks Cache (Read-Through), which is a Redis Cluster. On a cache hit, it returns fast. On a miss, it reads from the Popularity Store, which keeps pre-aggregated counts in a sharded key-value store. The Admin / Reporting API uses the same data for time-range reports, popularity trends, and exports. The cache is only a speed layer. The Popularity Store is the place where the counts live.

4. Explain background work

"The queue lets the system do counting in the background." The Aggregation Worker consumes events, micro-batches them, increments counters, updates time windows, and handles retries or a Dead Letter Queue when events keep failing. This work does not block the main request. That is the main reason the system can accept clicks quickly and still build good reports later. The Raw Clicks Store also gives an audit trail, so the data can be checked again if needed.

5. Explain scale, security, and trade-offs

"The system scales by keeping services stateless and by partitioning data by key and time." That lets the design use horizontal scaling and replicas safely. Replication, backups, retries, and the DLQ help reliability. Observability is covered with metrics, tracing, logs, and alerts. The main trade-off is freshness versus speed. Counts may lag a little because some work happens after the click is accepted. I would accept that trade-off because it keeps the main request path fast and protects the main store.

Engineering Considerations / Design Trade-offs

The benefit is that the system accepts clicks fast and does the heavier counting later. The Raw Clicks Store keeps a full trail, which helps audit and replay. The cache makes common reads faster, and the popularity store keeps popular counts ready. The downside is that some reports may be a little behind the newest clicks. Another cost is more moving parts, like the queue, worker, cache, and dead letter queue. We accept that because it keeps the main request path fast and makes the system easier to scale.

Why Interviewers Ask This

Interviewers want to see if you can split one busy problem into a fast path and a background path. They also want to know if you understand where the main data lives, when cache should be used, and how retries and bad events are handled. This question tests design judgment, trade-off thinking, and clear communication, not just memorized terms.

Interviewer may ask next
What if the product team wants click counts to update almost immediately after each click?

I would keep the same basic design, but I would make the background update path faster. The write path would still save the raw click first and send the event to the Message Queue / Stream. The Aggregation Worker would use smaller micro-batches and push updates to the Popularity Store more often. That keeps the system correct, because the raw event is still stored before the later count update. The cache can also be refreshed sooner for hot items. The downside is more write pressure on the worker and the popularity store, plus more cache churn. So the counts become fresher, but the system gives up some efficiency.

What if one item suddenly gets far more clicks than the rest?

I would keep the same architecture and rely on the partitioning by key and time that is already shown in the diagram. The Click Ingestion Service still writes the raw click, and the queue still smooths the burst before the Aggregation Worker updates counts. Because the services are stateless, I can add more instances to spread the work. The main thing to watch is that one very hot item can create uneven load in the queue and in the popularity store. The downside is more coordination and more careful scaling, but the design still stays correct because the raw event path and the background counting path do not change.

15. How would you design product reviews for a product page?System DesignMediumAmazon

Question Details

Design reviews for a product page, including duplicate-review handling, API shape, storage, and request flow.

Short Interview Answer (30-60 seconds)

At a high level, the goal is to let customers create product reviews safely and let other customers read them quickly. The main challenge is stopping duplicate reviews without making popular product pages slow. I would explain the design in three flows: writing a review, reading reviews, and updating summary data in the background. The reviews table stays the source of truth, while the Read Cache speeds up common reads. The trade-off is that rating summaries can lag slightly after a new review.

Detailed Explanation

The system must let a customer submit a review for a product and let other customers read reviews quickly. The difficult part is making each write safe when the same request is retried, while also keeping product pages fast. A customer should not accidentally create two active reviews for the same product. The design uses three flows: create the review, read reviews through a cache when possible, and update rating summaries in the background.

Useful Questions to Ask the Interviewer
  1. Can one user have only one active review per product?
  2. Is it acceptable if rating totals update a little after a review is created?
  3. Which review sort orders should the API support?
How would you design product reviews for a product page? diagram
How to Explain It in an Interview
1. Explain the request boundary

I would start with how requests enter the system. The Customer / Product Page UI sends HTTPS requests through the API Gateway / Load Balancer. It handles TLS termination, routing, logging, and health checks. The Authentication + Rate Limit Boundary verifies the JWT or session, extracts userId, rate-limits users, and adds WAF or abuse protection. The request then reaches stateless Java Review Service replicas on Java 21/25.

2. Explain the review write path

For a write, the client sends POST /products/{productId}/reviews with rating, title, body, and idempotencyKey. Validation checks the payload, product, and authenticated user. The Duplicate-Review Guard uses the idempotency key so a retry does not create another review.

The Review DB also enforces one active review per user and product with a uniqueness rule. This protects against racing requests. The Review Write Logic saves the review and an outbox row in the same database transaction. The reviews table is the source of truth. Success returns 201 Created with reviewId and status. An existing review or conflict does not create a second active review.

3. Explain the review read path

For a read, the client sends GET /products/{productId}/reviews with cursor and sort values. The Cache-Aware Read Path checks the Read Cache first. On a cache hit, the service builds the JSON response from cached summary and review data.

On a cache miss, the Review Read Logic reads review_summary and paginated reviews from the Review DB. It applies sorting and cursor pagination, then returns summary, reviews, and nextCursor. If the cache is unavailable, the service falls back to database reads.

4. Explain the background update

After the write transaction, new outbox events are polled and published to the Message Queue as ReviewCreated events. The Background Consumer / Summary Updater runs in a separate JVM process. It updates review_summary with average rating, rating counts, and total reviews, then invalidates or refreshes the Read Cache.

Failed processing uses exponential backoff. The consumer is idempotent, meaning replaying the same event should not apply the same update twice. Because this work happens later, aggregate counts may briefly trail a review.

5. Explain scale and operations

Stateless JVM replicas scale horizontally behind the gateway. Virtual threads help with many blocking database, cache, or HTTP calls, but they do not replace the durable Message Queue. Logs, metrics, and traces track request errors, database time, cache hit rate, queue lag, and calls across the system.

The trade-off is clear. The reviews table stays correct and reads stay fast, while derived summaries and cached data may be briefly behind.

Engineering Considerations / Design Trade-offs

The benefit is that the reviews table stays correct while common reads stay fast. Duplicate protection uses an idempotency key for client retries and a database uniqueness rule for racing requests. The Read Cache reduces repeated database work on popular product pages. The downside is that review_summary and cached data are derived from the main reviews table. They can be a little behind just after a new review is created. The Message Queue and Background Consumer also add more moving parts. If the cache fails, reads can fall back to the Review DB, but that puts more work on the database.

Why Interviewers Ask This

Interviewers ask this to see whether you can break one product feature into clear write, read, and background flows. They want to see how you prevent duplicate reviews, choose the source of truth, use a cache safely, and handle delayed summary updates. They also want to see whether you understand scaling, failure handling, and the trade-offs between fast reads and immediately fresh derived data.

Interviewer may ask next
What would you change if the product page had extremely high read traffic during a major sale?

I would keep the same design, but I would make the Read Cache carry more of the read traffic. The Java Review Service would still check the cache first for the summary and review page. This protects the Review DB from many repeated reads for the same popular products.

The reviews table would remain the source of truth. The Background Consumer / Summary Updater would still update review_summary and then invalidate or refresh the Read Cache after ReviewCreated events are processed. If the cache misses or becomes unavailable, the service can still fall back to the Review DB.

I would also add more stateless Java Review Service replicas behind the API Gateway / Load Balancer. That spreads incoming requests across more JVM processes. Virtual threads can help each replica handle many blocking cache and database calls.

The downside is that a busier read path depends more heavily on cache health. If the cache fails, database load can rise quickly.

What happens if the Background Consumer fails after a review has already been saved?

The saved review stays safe because the reviews table is the source of truth. The review row and outbox row were written in the same database transaction, so the event record is still present even if the Background Consumer / Summary Updater is unavailable.

The outbox path publishes ReviewCreated events to the Message Queue. When the consumer runs again, it processes the event, updates review_summary, and invalidates or refreshes the Read Cache. Failed processing uses exponential backoff. The consumer is idempotent, meaning processing the same event again should not apply the same summary change twice.

During the failure, the main review write does not need to be undone. Reads can still use the existing cache or fall back to the Review DB. The downside is that average rating, rating counts, total reviews, and cached summaries may stay old until the background work catches up.

16. How would you design a messaging app?System DesignMediumAmazon

Question Details

Design a messaging app with user conversations, message delivery, persistence, and basic scale concerns.

Short Interview Answer (30-60 seconds)

At a high level, this is a system for sending chats quickly and safely across phone, web, and desktop clients. The main challenge is that the send path must feel instant, but the message still has to be saved, delivered, and tracked correctly. I would explain it in three parts: the client entry path, the Java service and data layer, and the real-time plus background delivery paths. The trade-off is a little more moving parts for better speed and reliability.

Detailed Explanation

This system lets people send messages from mobile, web, and desktop. They can chat in real time, see who is online, send media, and get delivery updates. The hard part is that sending must feel fast, but the app still has to save every message safely and keep delivery status correct. The diagram answers this by splitting the design into an entry layer, a stateless Java service layer, several data stores, a real-time WebSocket delivery path, and a background path for retries and push notifications. It also separates fast delivery from background work.

Useful Questions to Ask the Interviewer
  1. Do we need only one-to-one chat, or also large group chats?
  2. Do you want read receipts and typing indicators to be shown immediately, or can they arrive a little later?
How would you design a messaging app? diagram
How to Explain It in an Interview
1. Explain the goal and the main idea

At a high level, this is a chat system that must feel instant. The send path must be correct, and delivery updates can wait a little. The diagram keeps the fast path small. It uses a public entry layer, stateless Java services, separate data stores, a WebSocket path for online users, and background work for slower tasks.

2. Explain the send path

For the create path, the client first connects through HTTPS or WSS. The request passes DNS, CDN, and the global load balancer, then the security layer. The Auth Service checks JWT, the API Gateway validates the request and rate limits it, and WAF blocks bad traffic. After that, the Message Service handles the send request. If it needs profile or membership data, the User Service and Conversation Service provide it. The Media Service handles uploads and stores files in object storage. The message is saved in the Message Store, while user and conversation data live in their own PostgreSQL databases. The write order matters because the app should save the message before it tries to fan out delivery.

3. Explain real-time delivery and reads

After the message is saved, the WebSocket Gateway Cluster pushes it to online users. The Presence Service keeps track of who is online or offline. The Fan-out Service sends the message to the right connected clients, and the connected client gets the inbox update right away. Redis is used as a cache for hot data like conversations and presence. That makes reads faster. The cache is only a speed layer. The Message Store is still the source of truth.

4. Explain background work, scale, and operations

Not every action should block the send path. The app publishes events to Kafka or Pulsar, and Java consumers process them in the background. Those workers handle read receipts, typing indicators, offline push prep, and analytics events. The Notification Service can turn those events into push, email, or SMS messages. If something fails, bad messages go to the DLQ. The service layer is stateless, so replicas can scale horizontally. PostgreSQL, Cassandra or ScyllaDB, and object storage split the storage jobs. That helps scale, but it adds more moving parts. Kafka makes background work safe, but some updates appear later. Multi-AZ deployment improves reliability, but failover can briefly interrupt writes. Logs, metrics, tracing, alerting, and dashboards help the team watch the system. TLS, JWT, rate limits, encryption, and audit logs protect the system.

Engineering Considerations / Design Trade-offs

The benefit is that the chat service can scale by adding more stateless Java replicas. Redis makes hot reads, like presence and recent chats, much faster. Kafka and the DLQ make background work safer, because retries do not block users. The downside is more moving parts. We must keep the cache, the main database, and the real-time path in sync. Another downside is that some things, like read receipts and push notifications, may appear a little later. Multi-AZ deployment also helps reliability, but a failover can briefly pause writes.

Why Interviewers Ask This

Interviewers want to see if you can break a chat app into the right flows and keep the fast path small. They also want to see if you know what must be stored safely, what can happen later, and how to use cache, queues, and WebSockets without mixing their roles. A strong answer shows judgment, not memorization. It also shows that you can explain trade-offs in simple words.

Interviewer may ask next
How would the design change if a single group chat can have millions of members?

I would keep the same basic design, but I would be more careful about fan-out. The message would still be saved once in the Message Store, and then the event bus would spread the work to background consumers. Online users could get the update through the WebSocket path, while offline users would get push later. The main change is that we would avoid doing all delivery work on the send request itself. That keeps the send path fast even when one chat room is very busy. I would also make sure the consumers can retry safely, because large groups create more retries and more duplicate events. The downside is that delivery status may lag more for very large groups, and the background system becomes more important.

What would you change if the product needed stronger read-after-write behavior for recent messages?

I would keep the same architecture, but I would be careful about where we read from right after a send. The sender should rely on the Message Store commit, not on Redis, because Redis is only a speed layer. For very fresh data, the service can read from the main store first and then update the cache. That keeps the result correct, even if the cache is still behind. For the UI, I would also avoid showing a strong promise until the save is complete. If the product needs the newest chat thread, I would skip the cache for that one read and use the main store directly. The downside is that some reads get slower, and the database gets more traffic.

17. How would you design a search suggester?System DesignMediumAmazon

Question Details

Design a search suggester that can return likely matches quickly as users type, with attention to ranking and latency.

Short Interview Answer (30-60 seconds)

At a high level, the goal is to return useful search suggestions while the user is still typing. The main challenge is keeping this path very fast while ranking results well. I would split the design into the online lookup path, the background ranking path, and the snapshot update path. Stateless Java replicas use a Distributed Response Cache and a local weighted Trie or FST for fast lookups. Query and click data improves future rankings. The trade-off is that suggestions can be slightly stale between snapshot updates.

Detailed Explanation

The goal is to predict useful search suggestions from a small prefix, such as "lap", before the user finishes typing. The difficult part is speed because every new keystroke may create another request. Ranking also matters because the most useful suggestions should appear first. The diagram separates this into a fast online path, background work that learns from queries and clicks, and snapshot updates that refresh the search data. Each Java replica keeps a local search index in memory, so most candidate lookups do not need a remote data store.

Useful Questions to Ask the Interviewer
  1. How many suggestions should we return for each prefix?
  2. Should suggestions change by locale or signed-in user context?
  3. How fresh must popularity and click signals be?
  4. What should happen when there are no strong prefix matches?
How would you design a search suggester? diagram
How to Explain It in an Interview
1. Explain how the request enters the system

I would start with the user-facing path because latency matters most there. The Browser / Mobile Search UI sends an HTTPS prefix request to CDN / Edge + API Gateway inside the Edge / Protection layer. This layer terminates HTTPS, validates prefix length and characters, and applies Rate Limiting / Abuse Control. Authentication is optional. When the user is signed in, the gateway can attach user context before forwarding the validated prefix.

2. Explain the fast online lookup path

The request reaches the Autocomplete Service Cluster running Java 21/25. Its replicas are stateless JVM processes, so separate JVMs do not share heap memory. Inside a replica, Request Handler receives the request and Prefix Normalizer cleans the prefix. Cache Check then checks the Distributed Response Cache for hot prefixes. On a cache hit, the service can use the stored Top N suggestions. On a cache miss, Candidate Generator reads the local read-only weighted Trie / FST snapshot stored in that replica's memory.

3. Explain ranking and the response

Ranker combines prefix relevance with popularity, recency, click feedback, locale, and optional user context. Response Builder then returns the Top N suggestions as JSON. Hot results can be written back to the Distributed Response Cache with a TTL, which means they expire after a set time. If the local snapshot has no strong matches or confidence is low, the service can use Popular Suggestions Fallback by locale. Virtual threads can help with concurrent I/O, but backpressure is still needed so outside resources are not overloaded.

4. Explain the background ranking work

Query impressions and clicks go to the Query & Click Event Log without slowing the main response. Suggestion Quality / Ranking Pipeline uses those events to compute popularity, recency, CTR, locale signals, freshness, and other ranking features. It also performs deduplication and unsafe-term filtering. The pipeline builds a validated weighted Trie / FST snapshot and stores it in the Versioned Snapshot Store. The Java replicas poll for newer versions and hot-swap their local snapshot when a valid version is available.

5. Explain scale, failures, and trade-offs

The service scales horizontally by adding more stateless Java replicas behind the gateway. Keeping the weighted Trie / FST in memory lowers lookup latency, but every replica needs memory for its own snapshot. If the Distributed Response Cache is unavailable, the service continues with its local snapshot. If a new snapshot fails validation, replicas keep serving the previous version. Suggestions may be slightly stale until the next snapshot publish. Observability / Monitoring collects metrics, logs, traces, alerts, latency, errors, and cache hit rate so operators can spot problems quickly.

Engineering Considerations / Design Trade-offs

The benefit is fast lookup because every Java replica keeps a weighted Trie or FST in memory. The Distributed Response Cache makes common prefixes even faster. The downside is memory use because each replica keeps its own local snapshot. Cached results and snapshots can also be a little old. We accept that because the heavy ranking work stays outside the user request path. Horizontal scaling is simple because the JVM replicas are stateless. If the cache fails, the local snapshot still works. If a new snapshot is bad, the service keeps the previous version until validation succeeds.

Why Interviewers Ask This

Interviewers use this question to see whether you can separate a very fast user path from slower background work. They want to see how you reason about caching, in-memory indexes, ranking signals, Java replica boundaries, failures, and scaling. They also want to know whether you can explain the trade-off between very low latency and slightly older ranking data in simple terms.

Interviewer may ask next
What would you change if the Distributed Response Cache became unavailable during heavy traffic?

I would keep the same basic design and continue serving suggestions from each replica's local weighted Trie / FST snapshot. Cache Check should fail or time out quickly, then the request can continue to Candidate Generator instead of waiting on the cache. This keeps the main search path working because the local snapshot is already in JVM memory.

I would also keep cache calls bounded. Virtual threads can help with many blocking calls, but they do not make the cache unlimited. Backpressure is still needed so a failing cache cannot consume too many connections or other resources.

Ranker and Response Builder would continue normally after candidates are found. Popular Suggestions Fallback would still help when there are no strong matches. Observability / Monitoring should show the cache failure and the extra local lookup load.

The downside is more work on every Java replica and possibly higher latency until the cache recovers.

What would you change if search suggestions needed to react to click behavior much faster?

I would keep the same online architecture, but I would reduce the delay between new events and snapshot updates. Query and click data would still go to the Query & Click Event Log. Suggestion Quality / Ranking Pipeline would process those signals more often and build validated weighted Trie / FST snapshots more frequently.

The new versions would still be stored in the Versioned Snapshot Store. Java replicas would continue polling for a newer version and hot-swap only after the new snapshot is valid. This keeps the main request path simple and preserves the existing protection against a bad snapshot.

I would also refresh hot entries in the Distributed Response Cache often enough that old cached rankings do not hide the newer snapshot results.

The downside is more background computation, more snapshot publishing, and more cache churn. Faster updates improve freshness, but they increase operational work.

18. How would you design a system for online auction?System DesignHardAmazon

Question Details

Design an online auction system with listings, bidding, winner selection, and concurrency tradeoffs.

Short Interview Answer (30-60 seconds)

At a high level, this system lets sellers create auctions, buyers place bids, and the platform choose one correct winner. The hardest part is handling competing bids without losing history or accepting the wrong highest bid. I would explain three flows: listing and reading auctions, accepting bids safely, and closing auctions with background notifications. The Relational Auction DB keeps the official state, Redis speeds reads, and the outbox handles reliable events. The trade-off is strong bid correctness with slightly delayed cached reads and notifications.

Detailed Explanation

The goal is to run online auctions from listing creation through winner selection. Sellers create auctions, buyers read them and place bids, and the system closes each auction when its time ends. The difficult part is handling bids that arrive almost together. We must keep every accepted bid, maintain the correct highest bid, and choose only one winner. The diagram handles this with a transactional main database, a read cache, careful bid validation, an auction-closing worker, and background event delivery.

Useful Questions to Ask the Interviewer
  1. Can many bidders place bids on the same auction at nearly the same time?
  2. Should a bid equal to the current highest bid be rejected?
  3. How fresh must the displayed highest bid be?
  4. Which notification channels are required for bid and auction events?
How would you design a system for online auction? diagram
How to Explain It in an Interview
1. Start with the request entry path

I would first explain how every client reaches the platform safely. Web App, Mobile App, and Seller / Admin UI send HTTPS requests through the Load Balancer / API Gateway. It handles routing, TLS termination, and request logging.

Auth & Rate Limits checks authentication, authorization, rate limits, and IP or device limits. Authorized requests then reach the Auction Platform. The platform runs as Java 21/25 JVM replicas, and each replica is a separate JVM process. Virtual threads help each replica handle many blocking database, cache, and HTTP calls efficiently.

2. Explain listing creation and auction reads

For listing creation, the Listing API creates or updates the auction in the Relational Auction DB. It stores auction rules and the close time there. This database keeps the official auction state.

For reads, the Auction Query API checks Redis Cache for the listing and CurrentHighestBid. Redis stores this data by auction ID and uses a TTL. On a cache hit, the query can return quickly. On a cache miss, the system queries the Relational Auction DB and returns the database result. Cached data may be slightly behind, so Redis is a speed layer rather than the final source of truth.

3. Explain bid acceptance and concurrency

For bidding, the Bid API sends the request to Bid Validation. It checks bid increments, auction state, and bidder eligibility.

The Relational Auction DB then performs one atomic transaction. This means the related changes succeed or fail together. It inserts the accepted bid into Bid history and uses a version-based compare-and-set on CurrentHighestBid. If another bid changed that version first, the update cannot silently overwrite it.

A bid at or below the current highest bid is rejected. Bid history is not updated or deleted after acceptance. The database returns an ACCEPTED or REJECTED transaction result to the Bid API. The highest bid wins, and the earliest accepted timestamp breaks a tie.

4. Explain auction closing and winner selection

The Auction Close Scheduler / Worker finds auctions whose end time has passed. It closes each auction only once with a conditional database update. It then selects the highest valid bid at close time and saves the Winner.

This work is idempotent, which means retrying it does not create a second winner. The worker can safely retry after a temporary failure. A lease or transaction can prevent two workers from selecting duplicate winners.

5. Explain events, retries, and operations

The Relational Auction DB also stores Outbox records. The Outbox Publisher reads pending records and publishes BidAccepted, AuctionClosed, and Outbid events to the Message Broker.

The Notification Worker consumes those events and sends Email, SMS, or Push notifications. If the broker has a temporary failure, the producer retries from the outbox with exponential backoff. This keeps event publishing reliable without making notifications part of the bid transaction.

Observability collects logs, metrics, and traces from the platform and workers. The main trade-off is strong consistency for bids and winner selection, while cached reads and background notifications can be slightly delayed.

Engineering Considerations / Design Trade-offs

The benefit is strong correctness where it matters most. Bid history is preserved, CurrentHighestBid is protected by an atomic version check, and the closing worker creates only one winner. The downside is that a very busy auction can cause more database contention. Redis makes reads faster, but cached data can be slightly old. Background notifications keep bidding fast, but notifications may arrive later. The outbox protects events during broker failures, but it adds storage, a publisher, and retry logic. Virtual threads help with many blocking calls, but database connections and other resources still need limits.

Why Interviewers Ask This

Interviewers ask this question to see whether you can separate fast reads from correctness-sensitive writes. They want to know how you handle two bids arriving together, preserve bid history, and choose one winner safely. They also look for good judgment around caching, background events, retries, rate limits, and failure handling. The important skill is explaining why some paths need strong correctness while others can tolerate a short delay.

Interviewer may ask next
What would you change if one very popular auction receives a huge burst of bids at the same time?

I would keep the same basic architecture, because the Relational Auction DB still needs to decide which bid is accepted. The main pressure point would be CurrentHighestBid. Many bidders could read the same version and then race to update it.

Bid Validation would continue rejecting obviously invalid requests before the database. Auth & Rate Limits could also reduce abusive traffic. For valid bids, the database would keep the version-based compare-and-set shown in the diagram. Only the update using the current version should succeed. A competing update with an old version must retry or return a rejected result instead of overwriting the winner.

The Java replicas can use virtual threads to handle many blocked requests efficiently. That helps application concurrency, but it does not create unlimited database capacity. Connection limits and database contention still matter.

Redis would remain only a read cache. It must never decide the accepted highest bid. The downside is higher bid latency and more retries when one auction becomes extremely hot.

What happens if the Message Broker is temporarily unavailable after an auction closes?

I would not change winner selection. The Auction Close Scheduler / Worker still marks the auction CLOSED once and saves the Winner in the Relational Auction DB. The related event remains recorded in the Outbox table, so the database result does not depend on the broker being available at that moment.

The Outbox Publisher reads pending outbox records and tries to publish them to the Message Broker. If the broker has a temporary failure, the producer retries from the outbox with exponential backoff. That means it waits progressively longer between failed attempts instead of retrying continuously.

The Notification Worker cannot consume that event until publication succeeds. Won, lost, or outbid notifications may therefore arrive later. That delay does not change the stored winner or accepted bid history.

Observability should expose failed publish attempts, retry activity, and pending outbox work through logs, metrics, and traces. The downside is delayed notifications and extra retry work. The benefit is that a temporary broker outage does not lose the auction result or its event.

19. How would you design a certificate distribution system?System DesignHardAmazon

Question Details

Design a certificate distribution system with issuing, lookup, delivery, and caching considerations.

Short Interview Answer (30-60 seconds)

At a high level, this system must issue certificates safely and make lookup and delivery fast. The main challenge is keeping certificate status correct while serving common reads quickly. I would explain three flows: issuance, lookup, and delivery, with notifications handled in the background. Requests pass through the Edge/CDN and API Gateway to stateless Java services. PostgreSQL keeps the main records, Redis speeds lookups, and Object Storage keeps certificate files. The trade-off is faster reads with more cache and background-processing complexity.

Detailed Explanation

The system needs to create certificates, let people find them later, and deliver the certificate file when requested. The difficult part is keeping certificate ownership, metadata, and revocation status correct while making frequent lookups fast. Delivery may also involve signing, rendering, email, or SMS. Those slower tasks should not make every user wait. The diagram separates the solution into issuance, lookup, delivery, and background work. PostgreSQL keeps the main certificate records, Redis speeds common reads, Object Storage keeps files, and Kafka carries work that can happen later.

Useful Questions to Ask the Interviewer
  1. How often are certificates issued compared with lookups?
  2. How quickly must a revocation become visible to users?
  3. Which certificate file formats must be delivered?
  4. Are email and SMS notifications required for every issuance?
How would you design a certificate distribution system? diagram
How to Explain It in an Interview
1. Start with request entry and security

I would start by showing how a request safely reaches the certificate service. Web, mobile, partner, and admin clients send HTTPS requests through the Edge/CDN and API Gateway. The edge provides DNS, CDN, DDoS protection, and WAF filtering. The API Gateway handles routing, TLS termination, rate limiting, and authentication. Identity & Access Management validates OAuth2 or OIDC tokens, JWTs, API keys, and RBAC or ABAC permissions before protected operations continue.

2. Walk through certificate issuance

For issuance, the Certificate Issuance API creates a certificate after validation and business-rule checks. The Application Services provide validation, templates, signing, notification support, and auditing. Certificate information is written to the Primary Data Store, which is the PostgreSQL cluster. Certificate files are written to S3-compatible Object Storage. After that main work, the service can publish events such as certificate.created, email.send, or audit.log to Kafka. This keeps later notification and audit work away from the main response.

3. Explain lookup and caching

For lookup, the Certificate Lookup API searches by ID or code and verifies status. It checks the Redis Cache Layer first. Redis stores certificate metadata, status or revocation information, templates, and short-lived tokens. On a cache hit, the service can answer without reading PostgreSQL. On a miss, it reads the needed record from the Primary Data Store and returns the result. PostgreSQL remains the main stored record. Redis is only the faster lookup layer, so cache invalidation must be handled carefully when certificate state changes.

4. Explain delivery and background processing

For delivery, the Certificate Delivery API generates or renders the result, uses the signing service when needed, and reads the certificate file from Object Storage. It then returns the file or link to the client. The Java Certificate Service is stateless and runs as multiple replicas. Virtual threads inside each JVM support many I/O-bound tasks, but they do not replace Kafka. Kafka carries background events to separate JVM workers. Those workers send email or SMS, process audits, generate reports, and perform cleanup. Scheduled Jobs handle certificate expiry, old-data archiving, report recomputation, and cache warmup.

5. Explain scaling, failures, and trade-offs

Stateless replicas make horizontal scaling easier. Redis and the CDN reduce repeated work on common reads and file delivery. Background workers can retry failed work and safely handle repeated events. Failed events can move to a dead-letter queue, which stores work that could not be processed normally. The Email / SMS Service also uses retry and backoff. Logs, metrics, tracing, and alerts show failures. Security includes TLS 1.3, encryption at rest, secrets in Vault or KMS, least privilege, and audit records. The main downside is more operational complexity from caches, queues, workers, and several storage systems.

Engineering Considerations / Design Trade-offs

The benefit is that Redis and the CDN make common reads and file delivery faster. The downside is that cached data can become old, so the cache needs a clear invalidation strategy. PostgreSQL keeps the main certificate records, while Object Storage is a better place for certificate files and templates. Kafka and Background Workers keep notifications, audits, reports, and cleanup away from the main request. This improves response time, but adds retries, failed-event handling, and more services to operate. Stateless Java replicas make scaling easier. We accept the extra complexity because the main user paths stay fast and background failures can be handled separately.

Why Interviewers Ask This

Interviewers want to see whether you can break a broad problem into clear flows and choose the right place for each kind of data. They also want to see whether you understand caching, background work, security, scaling, and failure handling. A strong answer shows good judgment about what must stay correct, what can happen later, and which trade-offs are worth the added complexity.

Interviewer may ask next
How would the design change if a revoked certificate must stop appearing as valid almost immediately?

I would keep the same basic architecture, but I would make the revocation path stricter. The main parts affected are the Certificate Lookup API, Redis Cache Layer, and Primary Data Store. PostgreSQL would still keep the main certificate status because that is the durable record.

When a certificate is revoked, the service should update PostgreSQL first and then invalidate the related Redis status entry. The next lookup can either receive the new value from a refreshed cache entry or read PostgreSQL after a cache miss. I would also keep the certificate.revoked event path for background work if that event is used by the system, but I would not depend on background processing to make the lookup status correct.

This keeps revocation correctness on the main data path while still using Redis for speed. The downside is more cache invalidation work and potentially more PostgreSQL reads. We accept that cost because showing a revoked certificate as valid is more serious than making one lookup slightly slower.

What happens if the Email / SMS Service is temporarily unavailable?

I would keep certificate issuance separate from notification delivery. The Certificate Issuance API can complete its main work by saving certificate information in the Primary Data Store and the certificate file in Object Storage. It can then publish the notification-related event to Kafka.

A Background Worker consumes that event and calls the Email / SMS Service. If the external service is unavailable, the worker uses the retry and backoff behavior shown in the diagram. The worker must safely handle the same event again, so a retry does not create incorrect repeated work. If processing keeps failing, the failed event can move to the dead-letter queue shown in the reliability notes. Logs, metrics, tracing, and alerts help operators notice the problem and investigate it.

The certificate does not need to be issued again just because notification delivery failed. The main downside is that the user may receive the email or SMS later, even though the certificate already exists and can be looked up or delivered.

20. How would you design a web crawler detector?System DesignHardAmazon

Question Details

Design a crawler-detection system that can identify suspicious access patterns and differentiate bots from normal traffic.

Short Interview Answer (30-60 seconds)

At a high level, I would treat this as a read-heavy system. The main challenge is that crawlers and real users can look similar, so the detector must stay fast and accurate. I would explain the design in three parts: edge checks, the Java detection service, and the background scoring and training pipeline. The trade-off is that stronger detection can add a little latency and may challenge some good traffic.

Detailed Explanation

This question asks how to tell whether incoming visits are from real people or from crawlers. A crawler can copy pages, scrape data, or hit the site too often. The hard part is that bad traffic and normal traffic can look alike at first. Some checks must happen right away so the site stays fast. Other checks can run later in the background. The diagram solves this by separating edge protection, the Java decision service, and the async learning pipeline.

Useful Questions to Ask the Interviewer
  1. Should suspicious traffic be blocked right away, or challenged first?
  2. Do we want to protect every endpoint, or mainly pages that are easy to scrape?
How would you design a web crawler detector? diagram
How to Explain It in an Interview
1. Explain the goal and the main idea

At a high level, the goal is to tell crawlers from normal traffic quickly. The system does that by checking traffic at the edge, scoring it in the Java service, and then learning from new events in the background. The Java layer can run on Java 21 or Java 25 and stays stateless, so many replicas can make the same decision. Fast checks protect the site first. Deeper checks improve accuracy without slowing every request.

2. Explain the first main flow

For the request path, traffic starts with clients such as web browsers, mobile apps, and bad bots or crawlers. It passes DNS, then WAF / DDoS protection, and then the CDN for static content. After that, the API Gateway / Reverse Proxy forwards allowed requests into the Java application layer. That layer does request validation, reputation checks, feature extraction, and risk scoring before it returns allow, challenge, or block.

3. Explain the decision path

The Crawler Detection Service is the part that makes the bot decision. It reads from the Feature Store / Cache, which is the fast place for recent counters and sketches. It also reads the Operational Database for IP, session, and user profile data. The service can call the ML Inference Service when a score needs a deeper check. This is where the system separates a normal user from a crawler in a simple and explainable way.

4. Explain background work

Not every check should block the request path. The diagram sends events to Kafka or Pulsar, then a stream processor like Flink or Kafka Streams enriches and aggregates them. The same flow also feeds offline analytics and model training. The Data Lake / Warehouse stores raw events and training data, while the Model Registry keeps trained models and versions. This background work helps the detector improve over time without slowing the live request.

5. Explain scale, failures, and trade-offs

The Java service uses virtual threads for many blocking requests, but it still keeps bounded thread pools where needed. That keeps the service responsive without pretending threads are free. Observability is also important here. Metrics, logs, traces, dashboards, and alerts show when a rule is too strict or too weak. The main trade-off is accuracy versus speed. More checks improve bot detection, but they can add latency and may challenge some real users.

Engineering Considerations / Design Trade-offs

The benefit is that the system can stop bad crawlers early and protect the origin. It also keeps the main Java service stateless, which makes scaling easier. The edge layer, the cache, and the async pipeline each handle a different kind of work, so the live path stays small. The downside is that stronger checks can slow some requests a little, and challenge pages can annoy real users. Background training also means rules and models may improve with a delay. We accept that because it keeps the fast path simple and lets the detector get better from real traffic.

Why Interviewers Ask This

Interviewers ask this to see if you can separate fast checks from background work. They also want to know whether you can use the right source of truth, keep the service stateless, and explain trade-offs in plain words. For this problem, they are looking for judgment about false positives, latency, scaling, and how the system learns from new traffic.

Interviewer may ask next
How would you reduce false positives for good users that look a little bot-like?

I would keep the same basic design, but I would make the decision path more careful. The Crawler Detection Service would use more signals from the Feature Store / Cache, the Operational Database, and the ML Inference Service before it blocks anyone. For weaker cases, I would prefer challenge instead of block. That keeps real users moving while still slowing suspicious traffic. The background pipeline would also learn from allow, challenge, and block outcomes, so future scores get better. I would also watch the metrics and alerts closely to find rules that are too strict or too broad. If needed, I would add clearer allow rules for trusted traffic first. The main downside is that this softer approach may let some crawlers through for a short time.

What would you change if bot traffic suddenly spiked during an attack?

I would keep the same flow, but I would push more work to the edge and to the async pipeline. WAF / DDoS protection, rate limiting, and the API Gateway / Reverse Proxy would reject more traffic before it reaches the Java service. Because the Crawler Detection Service is stateless, I could scale out more replicas quickly. Kafka or Pulsar would keep the event stream moving even if analysis runs behind for a while. The Java side would still use virtual threads and bounded pools, but the edge would do more of the first filtering. I would also relax some deeper checks during the peak and rely on faster rules first. That keeps the service useful even when the attack is very noisy. The main downside is that under heavy attack, some deeper scoring may lag, so the system may rely more on coarse rules for a short time.

More questions load as you scroll

Disclaimer: This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.

Company Notice: This guide is an independent educational resource and is not affiliated with, endorsed by, sponsored by, or approved by the company named in this guide. Company names are used only to identify interview experiences commonly reported by candidates. Interview practices can change without notice, and inclusion of company-specific content does not mean these questions are official, complete, or guaranteed to be asked. To the fullest extent permitted by law, the author, contributors, and publisher are not responsible for outcomes related to use of this material.