System Design Interview Questions: Microservices Architecture
Reviewed by Mark Dickie · Last updated
7 questions on this page you can answer and see marked on the spot. Go to the first one
Microservices architecture is a way of building a system as small services that each own their data and deploy on their own. In a system design interview, the question is rarely whether to use microservices. It is where to draw the service boundaries and what breaks when one call fails. Expect to defend a split, choose between synchronous calls and events, and explain how a multi-step write stays consistent without one shared transaction.
Which microservices topics does a system design interview test?
| Topic | What the interviewer probes |
|---|---|
| Service boundaries | Splitting an order flow by bounded context, and why a shared orders table undoes the split |
| Sync vs async calls | REST or gRPC for a checkout call versus Kafka events for inventory updates |
| Data ownership | One database per service, and how a cross-service report gets built without joins |
| Saga pattern | Compensating steps when payment succeeds but shipping fails |
| API gateway and BFF | Where auth, rate limiting, and routing live, and what a backend-for-frontend adds |
| Failure handling | Timeouts, retries with jittered backoff, and circuit breakers such as Resilience4j or Envoy |
| Service discovery | Kubernetes Services and DNS versus client-side registries such as Consul |
Work through these exercises before you start the quiz:
- Split a monolithic order service into three services, and list which tables each one owns.
- Draw the saga for a refund that must reverse a card charge and return stock to inventory.
- Set a timeout budget for a call chain four services deep, and explain how the budget shrinks at each hop.
- Describe what happens to in-flight requests when one instance of a service is killed during a rolling deploy.
Key facts
- Tarmac has 37 System Design interview questions on this topic, 10 of them on this page, at difficulty 1–5 of 5.
- Tarmac tracked 3,204 job postings asking for System Design in October 2026.
- Roles asking for System Design advertise a median base salary of £87,500, across 827 job postings as of October 2026.
- Tarmac last reviewed these System Design interview questions on 2 November 2026.
At a glance
| Questions | 10 shown · 37 in the bank |
|---|---|
| Difficulty | 1–5 of 5 |
| Formats | Multiple choice, True / false, Ordering, Multiple answer, Short answer, Flashcard, Design exercise |
What you'll review
- microservices
Practice questions
Try one before you open the answer. Pick an option and press Check; it's marked on the spot.
Which of the following best describes the core principle of a microservices architecture?#
Options
Show answer
A microservices architecture breaks the application into small, independently deployable services, each owning a specific business capability. This is the defining characteristic of microservices — as opposed to a monolith, which packages everything into one unit. Services communicate over a network (e.g., HTTP/gRPC) and each manages its own data store.
Microservices architecture decomposes an application into small, loosely coupled services, each responsible for a distinct business capability and deployable independently. This contrasts with a monolith, which packages everything together. Microservices typically avoid shared databases and shared memory in favor of well-defined network APIs.
In a microservices architecture, it is considered a best practice for multiple services to share a single, centralized database so they can easily query each other's data.#
Options
Show answer
False — sharing a single centralized database across microservices is an anti-pattern. It creates tight coupling between services, making independent deployment and schema evolution very difficult. The recommended practice is for each microservice to own its own dedicated data store and expose data to other services only through well-defined APIs.
Sharing a single database across multiple microservices is an anti-pattern known as the 'shared database' anti-pattern. It creates tight coupling between services, making it hard to evolve schemas independently or scale services separately. Best practice dictates that each microservice owns its own data store, and services access each other's data through well-defined APIs.
A development team is building a new feature using microservices. Arrange the following steps in the correct order for decomposing a monolith into microservices:#
Put these in order
Show answer
The correct order is: (1) Identify bounded contexts and business capabilities, (2) Define API contracts, (3) Extract the service with its own data store, (4) Deploy independently behind an API gateway. You must understand domain boundaries first, agree on interfaces before coding, isolate data, and finally route live traffic — each step depends on the previous one.
The standard approach to decomposing a monolith starts with identifying bounded contexts — logical groupings of related business capabilities (domain-driven design). Next, you design API contracts so other services know how to interact with the new service before writing any code. Then you extract the service along with its own database, eliminating shared-database coupling. Finally, you deploy the service independently and route traffic through an API gateway, validating the decomposition in production.
In a microservices architecture, Service A needs to call Service B to complete a user request. Service B is temporarily unavailable. Which pattern is most appropriate to prevent Service A from exhausting its own resources (e.g., thread pools) while Service B is down?#
Options
Show answer
The Circuit Breaker pattern is the most appropriate choice. It tracks failure rates to Service B and, once a threshold is exceeded, 'opens' the circuit so subsequent calls fail fast instead of blocking. This prevents Service A's thread pools from being exhausted waiting for a slow or unreachable dependency, allowing the system to degrade gracefully rather than cascade-fail.
The Circuit Breaker pattern monitors call failures to a downstream service and, after a threshold is crossed, 'opens' the circuit so that further calls fail immediately rather than waiting for a timeout. This prevents thread pools and other resources in the calling service from being exhausted while the dependency is down. Retries alone worsen the situation by consuming more resources. The Saga and Sidecar patterns address different concerns (distributed transactions and cross-cutting concerns, respectively).
In a microservices architecture, each microservice should share a single centralized database with all other microservices so that data consistency is easier to enforce.#
Options
Show answer
This is false. A core microservices principle is that each service should own its own dedicated database ('Database per Service' pattern). Sharing a centralized database tightly couples services together — schema changes in one can break others, it creates a single point of failure, and it defeats independent deployability. Cross-service data consistency is handled through eventual consistency and patterns like Sagas.
One of the core principles of microservices architecture is that each service owns its own data store (the 'Database per Service' pattern). Sharing a single database creates tight coupling between services — a schema change in one service can break others, and the database becomes a single point of failure and a scaling bottleneck. Data consistency across services is instead handled through eventual consistency, events, or the Saga pattern.
A client request arrives at a microservices system that uses client-side service discovery (e.g., Netflix Eureka + Ribbon / Spring Cloud). In this pattern the service consumer itself queries the registry and picks an instance. Place the following components in the order the request passes through, from the external entry point to business logic execution:#
Put these in order
Show answer
The correct order is: Load Balancer / Ingress → API Gateway → Service Registry lookup → Target Microservice. In client-side service discovery (e.g., Netflix Eureka + Ribbon), the API Gateway itself queries the Service Registry to find a healthy instance before forwarding the request, making the registry lookup a distinct step that occurs after the gateway and before the microservice.
In a client-side service discovery architecture (exemplified by Netflix Eureka + Ribbon or Spring Cloud LoadBalancer), the component that wants to call a downstream service is responsible for querying the Service Registry directly before forwarding the request. The canonical flow is: (1) The external Load Balancer / Ingress is the first hop — it terminates TLS and spreads traffic across gateway instances. (2) The API Gateway applies cross-cutting concerns such as authentication, rate-limiting, and routing logic. (3) The Gateway, acting as the service consumer, performs a Service Registry lookup (e.g., queries Eureka) to discover healthy instances of the target service and selects one (usually via a client-side load-balancing algorithm like round-robin). (4) The request is forwarded directly to the chosen Target Microservice instance, which executes the business logic. This four-step ordering is unambiguous for client-side discovery because the registry lookup is an explicit, runtime step performed by the gateway/consumer before it can forward the call — unlike server-side discovery (ALB + ECS) where the registry resolution is handled internally by the load balancer and is not a discrete step visible to the gateway.
You are evaluating whether to decompose a monolith into microservices. Which of the following are genuine signals that a decomposition is warranted?#
Options
Pick every one that applies.
Show answer
The genuine signals are that different parts need to scale independently at very different rates, that teams are stepping on each other because ownership boundaries are unclear, and that one module needs a completely different technology stack (such as a GPU inference service). A small, simple app one team can own comfortably, or a team with no operational maturity — no service discovery, tracing, or on-call culture — are anti-signals: start with a modular monolith.
Microservices are a tool for specific organisational and scaling problems, not a default. Independent scaling needs are the original scalability motivator — you add replicas of the hot service without touching the rest. Ownership boundaries that reduce team friction address the Conway's Law argument: independent deploy trains let teams ship without waiting for each other. Polyglot technology requirements are a genuine boundary — a GPU inference workload doesn't belong in the same process as a CRUD API. The remaining two are anti-signals. A small team with a cohesive codebase takes on network overhead, distributed debugging, and operational complexity for no gain; start with a modular monolith. And a team with no real operational maturity — no service discovery, no distributed tracing, no on-call culture — will struggle with microservices: the operational primitives — service discovery, distributed tracing, on-call runbooks — must exist before the network boundaries do, or incidents become un-debuggable.
When you split a monolith into microservices, how should you draw the service boundaries, and why does each service owning its own database matter?#
Show answer
Draw boundaries around business capabilities (or DDD bounded contexts) so that each service owns a cohesive area — orders, payments, inventory — rather than splitting by technical layer. A good boundary minimizes cross-service calls for a single operation and keeps a team able to ship that service independently. Each service owning its own database matters because it enforces loose coupling: no other service can reach into its tables, so the service is free to change its schema, and you avoid a shared database becoming a hidden coupling point and a single bottleneck. The cost is that data is now distributed, so a query spanning services needs an API call or an event, and a transaction across services needs a saga instead of a single ACID commit.
Good boundaries follow business capabilities / DDD bounded contexts, not technical layers, so each service is cohesive and a team can ship it independently with minimal cross-service chatter per operation. Database-per-service is the structural rule that makes this real: private data means no service can couple to another's schema, so each evolves freely and there's no shared-DB bottleneck. The trade-off is distributed data — cross-service reads become API calls or events, and cross-service writes need a saga rather than one ACID transaction. A shared database silently re-couples services and is the classic anti-pattern.
What are the core trade-offs of splitting a monolith into microservices?#
Show answer
Microservices gain independent deployability (teams ship without coordinating a full release), targeted scalability (scale only the hot service), technology flexibility (choose the right tool per service), and fault isolation (one service crash doesn't bring down everything). The costs are network latency and failure modes that were formerly in-process function calls, distributed data consistency (no single ACID transaction across services), operational complexity (container orchestration, service discovery, distributed tracing), and testing overhead (you must test contracts between services, not just units). Microservices are usually the right call once team size and deployment frequency justify the coordination tax, not as a default starting point.
Interviewers look for candidates who can articulate the costs alongside the benefits. The biggest practical pitfalls are premature decomposition (splitting before you know the domain boundaries) and neglecting the distributed systems failure modes that appear once calls cross a network boundary.
An e-commerce company runs a single large monolith (catalog, cart, checkout, payments, orders, inventory, shipping all in one deployable, one database). Deploys are slow and risky, one team's bug takes the whole site down, and they can't scale checkout independently of browsing. Design the decomposition into microservices and the platform that supports it.#
Show answer
Goals & when to split. The pains are concrete: coupled deploys, no fault isolation, and an inability to scale checkout independently of browsing (which is ~50× the traffic). Those justify splitting. But microservices aren't free — they trade in-process calls and ACID transactions for network hops, partial failure, and distributed-transaction headaches. So I split deliberately, by business value, not everywhere at once.
Service boundaries. I decompose by bounded context / business capability: catalog, cart, orders, payments, inventory, shipping. Each is high-cohesion and owns its domain logic and its data. I avoid the anti-pattern of slicing along database tables into chatty anaemic services — boundaries follow how the business reasons about the domain, so services stay loosely coupled.
Database decomposition. Each service gets its own datastore (database-per-service) — this is what actually breaks the shared-DB scaling ceiling and SPOF. Services no longer cross-join each other's tables; instead they expose APIs and emit events. The orders service stores the product id (and denormalises the few fields it needs) and fetches the rest from the catalog API, or subscribes to catalog change events. What we give up is the convenient cross-table join and strong cross-entity consistency — replaced by API calls and eventual consistency.
Communication & gateway. An API gateway fronts everything: it authenticates, routes to the right service, rate-limits, and can fan out/aggregate. Between services I pick per interaction: synchronous REST/gRPC for a read I need right now (get product), asynchronous events for 'order placed' / 'inventory changed' so producers don't block on consumers. Every synchronous call is wrapped with timeouts, retries (idempotent), and a circuit breaker so a slow dependency fails fast instead of hanging the caller.
Cross-service correctness (place order). Placing an order spans orders + inventory + payments — three databases, so no single ACID transaction. I use a saga: a sequence of local transactions with compensating actions. Orchestrated, an order orchestrator does: reserve inventory → charge payment → confirm order; if payment fails after the reservation, it fires the compensation release inventory. The order sits in a PENDING state until the saga completes, and the user sees pending → confirmed (or failed). This is eventually consistent but never permanently leaks reserved stock.
Migration & new failure modes. No big-bang. I use the strangler-fig pattern: keep the monolith running behind the gateway, peel out one service plus its data at a time, route that capability's traffic to the new service (feature-flagged), dual-write / shadow-read to validate, then cut over and delete the monolith's copy. New failure modes — partial failure (one service down), cascading failure (a slow dependency dragging callers down), and added latency from hops — are contained with circuit breakers, bulkheads (isolate resource pools per dependency), idempotent retries with backoff, and distributed tracing so a request can be followed across services.
Decomposing a monolith tests judgement, not just diagram-drawing. The two decisions that define the answer are where the boundaries go — by bounded context / business capability so services are loosely coupled and own their data, never by slicing a shared table into chatty anaemic services — and how to break the shared database, the actual scaling ceiling, via database-per-service reached incrementally with the strangler-fig pattern (peel out one service plus its data at a time, no big-bang). Once data is split, cross-service flows like 'place order' can't use a single ACID transaction, so the correct tool is a saga with compensating actions (reserve → charge → confirm, release on failure), accepting eventual consistency. The strong candidate also names the costs microservices add — partial and cascading failure, network latency — and contains them with an API gateway, circuit breakers, bulkheads, idempotent retries, and distributed tracing, rather than treating 'microservices' as an unqualified win.
Related interview questions
Job market
See system-design salaries and hiring demand from live job postings.
The other 27 questions
This page shows 10 and marks what you pick. That's as far as a page can go. A free account opens the other 27 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.
Free · the whole bank · 100 answers per 30 days, each marked with written feedback