RSRobince Studio

Top 50 Microservices interview questions and answers

The 50 questions interviewers ask most about Microservices, with short, clear answers and code where it helps. The first 25 are the most common; the rest go deeper. Free, no sign-up.

All 50 questions

  1. What are microservices?
  2. What is the difference between a monolith and microservices?
  3. What are the main benefits of microservices?
  4. What are the drawbacks and challenges of microservices?
  5. How do microservices communicate with each other?
  6. What is the difference between synchronous and asynchronous communication?
  7. What is an API Gateway and why is it used?
  8. What is service discovery?
  9. What is the database per service pattern?
  10. How do you maintain data consistency across microservices?
  11. What is the saga pattern?
  12. What is the difference between choreography and orchestration?
  13. What is the circuit breaker pattern?
  14. How do you make microservices resilient?
  15. What is a bulkhead pattern?
  16. What is the role of Docker in microservices?
  17. Why is Kubernetes used with microservices?
  18. How do you handle centralized logging in microservices?
  19. What is distributed tracing?
  20. How do you monitor microservices?
  21. How does CI/CD work for microservices?
  22. What is event-driven architecture in microservices?
  23. How do you version APIs in microservices?
  24. How do you secure communication between microservices?
  25. How do you handle authentication and authorization in a microservices architecture?
  26. What is the outbox pattern and what problem does it solve?
  27. What is CQRS and when would you use it?
  28. What is event sourcing and how does it relate to microservices?
  29. What does idempotency mean and how do you implement it for a payment API?
  30. Why are timeouts and retries with backoff dangerous if used carelessly?
  31. How would you break down a monolith into microservices?
  32. What is the strangler fig pattern?
  33. What is domain-driven design and what is a bounded context?
  34. How do you decide the right size for a microservice?
  35. What is a distributed monolith and how do you avoid it?
  36. What is consumer-driven contract testing?
  37. How do you test microservices effectively?
  38. What is the sidecar pattern and what is a service mesh?
  39. When would you choose gRPC over REST for service-to-service calls?
  40. What is the BFF (Backend for Frontend) pattern?
  41. How do you handle configuration and secrets in microservices?
  42. How do you perform zero-downtime deployments of microservices?
  43. How do you handle database schema changes across independently deployed services?
  44. How do you handle a query that needs data from several microservices?
  45. What is the difference between horizontal scaling and vertical scaling, and how do microservices scale?
  46. What is rate limiting and how do you implement it in a microservices system?
  47. What is the difference between a message queue and an event stream, such as RabbitMQ versus Kafka?
  48. How do you guarantee message ordering and handle duplicates in an event-driven system?
  49. What is a dead letter queue and how do you use it?
  50. A request through five microservices is suddenly slow. How would you troubleshoot it?

1. What are microservices?

Microservices are an architectural style in which an application is built as a set of small, independently deployable services, each focused on one business capability. Each service owns its code and data, runs in its own process, and communicates with others over the network through APIs or messages. This lets teams build, deploy, and scale services independently of one another.

2. What is the difference between a monolith and microservices?

A monolith packages all functionality into one deployable unit, while microservices split it into many independently deployable services. A monolith is simpler to develop, test, and deploy at first, but it becomes harder to scale and change as it grows. Microservices allow independent scaling, technology choice, and team ownership, but add distributed-system complexity such as network failures, data consistency, and operational overhead.

3. What are the main benefits of microservices?

The main benefits are independent deployment, independent scaling, fault isolation, and team autonomy. Each service can be released on its own schedule, scaled according to its own load, and written with the technology best suited to it. A failure in one service does not necessarily bring down the whole system, and small teams can own a service end to end.

4. What are the drawbacks and challenges of microservices?

Microservices trade code complexity for distributed-system complexity. You must handle network latency and partial failures, data consistency across services, harder debugging and testing, service versioning, and a much heavier operational burden (deployment, monitoring, tracing). For small teams or simple domains, a well-structured monolith is often the better choice.

5. How do microservices communicate with each other?

Microservices communicate either synchronously, using request/response protocols like REST or gRPC, or asynchronously, using messages or events through a broker such as Kafka or RabbitMQ. Synchronous calls are simple but couple services in time, so a slow dependency slows the caller. Asynchronous messaging decouples services and improves resilience, but makes flows harder to trace and reason about.

6. What is the difference between synchronous and asynchronous communication?

In synchronous communication the caller sends a request and waits for the response, while in asynchronous communication the caller sends a message and continues without waiting. Synchronous calls (HTTP, gRPC) are easy to understand but create temporal coupling and cascading failures. Asynchronous messaging via a queue or event stream absorbs traffic spikes and lets the receiver be down temporarily, at the cost of eventual consistency and more complex error handling.

7. What is an API Gateway and why is it used?

An API Gateway is a single entry point that sits between clients and the backend services and routes requests to the right service. It also handles cross-cutting concerns such as authentication, rate limiting, TLS termination, caching, request aggregation, and logging. This keeps clients simple and hides the internal service layout. Common examples are Kong, NGINX, Spring Cloud Gateway, and AWS API Gateway.

8. What is service discovery?

Service discovery is the mechanism that lets services find each other's network locations dynamically, because instances start, stop, and change addresses all the time. Instances register themselves with a registry such as Consul, Eureka, or etcd, and callers look them up. In client-side discovery the caller queries the registry, while in server-side discovery a load balancer or platform does it. Kubernetes provides this built in through Services and DNS.

9. What is the database per service pattern?

Database per service means each microservice owns its private data store, and no other service accesses that database directly. Other services must go through the owning service's API or consume its events. This keeps services loosely coupled and lets each choose the best storage technology, but it makes cross-service queries and transactions harder, which is why patterns like saga and CQRS are needed.

10. How do you maintain data consistency across microservices?

Since distributed ACID transactions are impractical across services, you usually accept eventual consistency and use patterns such as saga, the outbox pattern, and event-driven updates. Each service commits its own local transaction and publishes an event so others can react. Operations must be idempotent so retries and duplicate messages are safe, and compensating actions undo earlier steps when a later step fails.

11. What is the saga pattern?

The saga pattern manages a business transaction that spans multiple services as a sequence of local transactions, each followed by an event or command that triggers the next step. If a step fails, the saga runs compensating transactions to undo the earlier steps, for example refunding a payment. Sagas come in two styles: choreography, where services react to each other's events, and orchestration, where a central coordinator directs the steps.

Order saga (orchestration):
1. Order Service   -> create order (PENDING)
2. Payment Service -> charge card
3. Inventory       -> reserve stock
   if step 3 fails:
     Payment Service -> refund (compensation)
     Order Service   -> mark order CANCELLED
4. Order Service   -> mark order CONFIRMED

12. What is the difference between choreography and orchestration?

In choreography, services coordinate by publishing and subscribing to events with no central controller, while in orchestration a central orchestrator tells each service what to do and tracks the workflow state. Choreography is more decoupled but harder to follow and debug as flows grow. Orchestration gives clear visibility and error handling in one place, but the orchestrator can become a point of added coupling.

13. What is the circuit breaker pattern?

The circuit breaker pattern stops a service from repeatedly calling a failing dependency, so failures do not cascade. It has three states: closed (calls pass through), open (calls fail immediately after a failure threshold is hit), and half-open (a few trial calls test whether the dependency has recovered). It is typically combined with timeouts and fallbacks, and implemented by libraries like Resilience4j or by a service mesh.

14. How do you make microservices resilient?

You make microservices resilient by assuming that dependencies will fail and designing for it. Key techniques are timeouts on every remote call, retries with exponential backoff and jitter, circuit breakers, bulkheads to isolate resource pools, fallbacks, rate limiting, and health checks. Retried operations must be idempotent. Asynchronous messaging and redundancy across instances and zones further reduce the impact of failures.

15. What is a bulkhead pattern?

The bulkhead pattern isolates resources, such as thread pools or connection pools, per dependency or per client so that one failing or slow part cannot exhaust resources for the rest of the system. The name comes from ship compartments that contain flooding. For example, giving the payment client its own limited thread pool means a slow payment service cannot block calls to the catalog service.

16. What is the role of Docker in microservices?

Docker packages a service and all its dependencies into a lightweight container image that runs identically on any environment. This gives each microservice an isolated, reproducible runtime, fast startup, and an easy way to ship the same artifact from development to production. Containers are lighter than virtual machines because they share the host kernel, which makes running many services per host practical.

FROM eclipse-temurin:21-jre
COPY app.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

17. Why is Kubernetes used with microservices?

Kubernetes is a container orchestrator that automates deploying, scaling, healing, and networking containers across a cluster. It restarts failed containers, performs rolling updates and rollbacks, scales pods based on load, provides service discovery and load balancing through Services, and manages configuration and secrets. This removes much of the operational work of running many services at once.

18. How do you handle centralized logging in microservices?

You ship logs from every service instance to a central store where they can be searched together, instead of reading logs on individual hosts. Services write structured logs (usually JSON) to stdout, and an agent such as Fluent Bit or Filebeat forwards them to a system like the ELK/EFK stack, Loki, or a cloud logging service. Including a correlation or trace ID in every log line lets you follow one request across services.

19. What is distributed tracing?

Distributed tracing tracks a single request as it travels through multiple services, recording each step as a span with timing data. A trace ID is generated at the entry point and propagated in headers (for example the W3C traceparent header) to every downstream call. Tools like OpenTelemetry, Jaeger, and Zipkin collect and visualize traces, which helps find latency bottlenecks and failing services.

20. How do you monitor microservices?

You monitor microservices through the three pillars of observability: metrics, logs, and traces. Metrics such as request rate, error rate, and latency (and saturation) are collected with tools like Prometheus and shown in Grafana, with alerts on service level objectives. Health endpoints support liveness and readiness probes, while logs and traces help diagnose the cause of an alert. OpenTelemetry is the common standard for instrumentation.

21. How does CI/CD work for microservices?

Each microservice has its own independent pipeline that builds, tests, packages, and deploys it without requiring a release of the others. A typical pipeline runs unit tests, builds a container image, runs integration and contract tests, pushes the image to a registry, and deploys to Kubernetes using strategies like rolling, blue-green, or canary releases. GitOps tools such as Argo CD can keep the cluster in sync with Git.

22. What is event-driven architecture in microservices?

Event-driven architecture is a design in which services communicate by publishing events that describe something that happened, and other services subscribe and react to them. The publisher does not know who consumes the events, so services stay loosely coupled and are easy to extend. It is usually built on a broker like Kafka or RabbitMQ, and it requires handling duplicates, ordering, and eventual consistency.

23. How do you version APIs in microservices?

You version APIs so that changes do not break existing consumers, most commonly by putting the version in the URL path (/v1/orders), in a header, or in a media type. The best practice is to prefer backward-compatible changes such as adding optional fields, and to introduce a new version only for breaking changes. Old versions are supported for a deprecation period, and consumer-driven contract tests help catch accidental breaks.

24. How do you secure communication between microservices?

You secure service-to-service communication by encrypting traffic with TLS, authenticating each service, and authorizing every request. Mutual TLS (mTLS) verifies both sides and is often provided automatically by a service mesh like Istio or Linkerd. For user identity, the gateway validates a token such as a JWT from OAuth 2.0/OpenID Connect and passes it on. Follow zero trust principles, apply least privilege, and keep secrets in a secret manager.

25. How do you handle authentication and authorization in a microservices architecture?

Authentication is typically centralized at an identity provider and the API Gateway, while authorization is enforced in each service. The user logs in through OAuth 2.0 / OpenID Connect and receives a signed JWT access token. The gateway validates it, and services verify the signature and check claims such as roles or scopes before acting. Service-to-service calls use their own credentials, for example client-credentials tokens or mTLS identities.

26. What is the outbox pattern and what problem does it solve?

The outbox pattern guarantees that a database change and the event announcing it are never out of sync, solving the dual-write problem. Instead of writing to the database and publishing to a broker separately, the service writes the event into an outbox table in the same local transaction as the business data. A separate relay process, or change data capture such as Debezium, then publishes those rows to the broker. Delivery is at-least-once, so consumers must be idempotent.

BEGIN;
INSERT INTO orders (id, status) VALUES (42, 'CREATED');
INSERT INTO outbox (id, topic, payload)
VALUES (gen_random_uuid(), 'order.created', '{"orderId":42}');
COMMIT;

27. What is CQRS and when would you use it?

CQRS (Command Query Responsibility Segregation) separates the model that changes data (commands) from the model that reads it (queries). The read side can be a denormalized store, such as Elasticsearch or a materialized view, kept up to date by events from the write side. Use it when read and write workloads differ greatly or when queries span several services. The cost is extra complexity and eventual consistency between the two sides.

28. What is event sourcing and how does it relate to microservices?

Event sourcing stores the state of an entity as an append-only sequence of events rather than as its current row. Current state is rebuilt by replaying events, which gives a full audit trail and lets you build new read models later. It pairs naturally with CQRS and event-driven services. The trade-offs are a steeper learning curve, event schema evolution, and the need for snapshots so replay stays fast.

29. What does idempotency mean and how do you implement it for a payment API?

An idempotent operation produces the same result no matter how many times it is applied, which makes retries safe. For a payment API, the client sends a unique Idempotency-Key header with each request. The server stores the key together with the result, and if the same key arrives again it returns the saved response instead of charging twice. Consumers of messages do the same by recording processed message IDs.

30. Why are timeouts and retries with backoff dangerous if used carelessly?

Naive retries can turn a small slowdown into an outage by multiplying load on a struggling service, known as a retry storm. In a call chain of several services, retries at every layer multiply exponentially. Mitigate this with exponential backoff plus jitter, a retry budget, retries only at one layer, and circuit breakers. Only retry idempotent operations, and always set a timeout shorter than the caller's own deadline.

31. How would you break down a monolith into microservices?

Break a monolith apart gradually with the strangler fig pattern rather than a big-bang rewrite. First identify bounded contexts using domain-driven design, then put a routing layer in front of the monolith and extract one capability at a time, starting with a low-risk, loosely coupled module. Route traffic to the new service, split its data out of the shared database, and retire the old code. Each step should be deployable and reversible.

32. What is the strangler fig pattern?

The strangler fig pattern incrementally replaces a legacy system by building new services around it and redirecting functionality piece by piece until the old system can be removed. A facade, usually an API Gateway or reverse proxy, routes each request either to the legacy code or to the new service. It lowers risk because you can migrate, test, and roll back one feature at a time, and the system stays live throughout.

33. What is domain-driven design and what is a bounded context?

Domain-driven design (DDD) models software around the business domain using a shared language between developers and domain experts. A bounded context is an explicit boundary within which a model and its terms have one consistent meaning, for example "Customer" means something different in billing than in shipping. Bounded contexts are the best guide for service boundaries, because each service then owns a cohesive model and communicates with others through well-defined contracts.

34. How do you decide the right size for a microservice?

There is no fixed size; a service should be sized by business capability and team ownership, not by lines of code. A good service is one a single team can own, change and deploy independently, and that rarely needs a coordinated release with others. Warning signs of wrong boundaries are chatty synchronous calls between two services, shared databases, and changes that always touch several services together. Start larger and split later when needed.

35. What is a distributed monolith and how do you avoid it?

A distributed monolith is a system split into separate services that are still tightly coupled, so they must be deployed and changed together. It combines the downsides of both styles: network overhead and operational complexity without independent releases. Common causes are a shared database, long synchronous call chains, and shared libraries containing domain logic. Avoid it with proper bounded contexts, data ownership per service, asynchronous events, and versioned contracts.

36. What is consumer-driven contract testing?

Consumer-driven contract testing verifies that a provider service satisfies exactly what its consumers expect, without running a full integration environment. Each consumer publishes a contract describing the requests it makes and the responses it needs, and the provider's pipeline checks that it still honors every contract. Tools like Pact implement this. It catches breaking API changes early, keeps tests fast, and replaces many slow end-to-end tests.

37. How do you test microservices effectively?

Use a testing pyramid with many fast unit tests, fewer component and integration tests, contract tests between services, and only a small number of end-to-end tests. Test a service in isolation by stubbing neighbors with tools like WireMock, and use Testcontainers to run real databases and brokers in tests. End-to-end tests are slow and flaky, so reserve them for a few critical user journeys. Production checks such as canary releases and synthetic monitoring complete the picture.

38. What is the sidecar pattern and what is a service mesh?

The sidecar pattern deploys a helper container next to each service instance to handle cross-cutting concerns like networking, logging, or security. A service mesh such as Istio or Linkerd uses a sidecar proxy, commonly Envoy, beside every service to provide mTLS, retries, timeouts, traffic splitting, and metrics without changing application code. The cost is extra resource usage, added latency per hop, and operational complexity. Newer sidecarless modes, like Istio ambient, reduce that overhead.

39. When would you choose gRPC over REST for service-to-service calls?

Choose gRPC when you need low latency, high throughput, strongly typed contracts, or streaming between internal services. It uses HTTP/2 and compact binary Protocol Buffers, and generates client and server code from a .proto file. REST with JSON remains better for public APIs, browser clients, and easy debugging, because it is human-readable and universally supported. Many systems use REST at the edge and gRPC internally.

service OrderService {
  rpc GetOrder (OrderRequest) returns (Order);
  rpc WatchOrders (OrderRequest) returns (stream Order);
}

40. What is the BFF (Backend for Frontend) pattern?

The Backend for Frontend pattern creates a separate backend tailored to each type of client, such as web, mobile, or partner API, instead of one general-purpose gateway. Each BFF aggregates calls to downstream services and shapes responses for its client's needs, reducing over-fetching and round trips. It lets frontend teams evolve their API independently. The downside is duplicated logic across BFFs, so keep business rules in the core services.

41. How do you handle configuration and secrets in microservices?

Keep configuration outside the code and the image, following the twelve-factor approach, so the same artifact runs in every environment. Use environment variables, Kubernetes ConfigMaps, or a central config service for settings, and a secret manager such as HashiCorp Vault, AWS Secrets Manager, or Kubernetes Secrets with encryption for credentials. Never commit secrets to Git, rotate them regularly, grant each service access only to its own secrets, and reload configuration without full redeploys where possible.

42. How do you perform zero-downtime deployments of microservices?

Use deployment strategies that keep old instances serving traffic while new ones start. Rolling updates replace instances gradually, blue-green switches traffic between two identical environments, and canary releases send a small percentage of traffic to the new version first. Readiness probes ensure traffic only reaches healthy pods, and graceful shutdown lets in-flight requests finish. Database changes must follow the expand-and-contract approach so old and new code both work during the rollout.

43. How do you handle database schema changes across independently deployed services?

Make schema changes backward compatible using the expand-and-contract (parallel change) approach, because old and new versions of the service run side by side during a rollout. First add the new column or table without removing anything, then deploy code that writes to both and reads the new one, backfill the data, and only later drop the old structure. Use migration tools such as Flyway or Liquibase, and never share one schema between services.

44. How do you handle a query that needs data from several microservices?

Avoid joining across service databases; instead use API composition, a read model, or events. With API composition, a gateway or aggregator service calls each owner in parallel and merges the results, which is simple but adds latency and failure points. For heavy or frequent queries, build a CQRS read model that subscribes to events from the services and keeps a denormalized copy. Choose by how fresh the data must be.

45. What is the difference between horizontal scaling and vertical scaling, and how do microservices scale?

Vertical scaling adds more CPU or memory to one instance, while horizontal scaling adds more instances behind a load balancer. Microservices rely mainly on horizontal scaling, so each service scales independently according to its own load, for example with the Kubernetes Horizontal Pod Autoscaler using CPU or custom metrics. This requires services to be stateless, with session and cache data kept in an external store such as Redis, and databases scaled separately.

46. What is rate limiting and how do you implement it in a microservices system?

Rate limiting caps how many requests a client can make in a time window, protecting services from abuse and overload. It is commonly applied at the API Gateway, keyed by user, API key, or IP, and uses algorithms such as token bucket, leaky bucket, or sliding window. In a multi-instance setup the counters need a shared store like Redis. Return HTTP 429 Too Many Requests with a Retry-After header.

47. What is the difference between a message queue and an event stream, such as RabbitMQ versus Kafka?

A message queue like RabbitMQ delivers each message to one consumer and typically removes it once acknowledged, while an event stream like Kafka keeps an ordered, replayable log that many consumers read independently. Queues suit task distribution and flexible routing. Kafka suits high throughput, event sourcing, and reprocessing history, with ordering guaranteed only within a partition. Pick based on whether you need replay and many independent readers.

48. How do you guarantee message ordering and handle duplicates in an event-driven system?

Ordering is usually guaranteed only within a partition or queue, so route all events for the same entity, such as an order ID, to the same partition using a message key. Brokers generally provide at-least-once delivery, so duplicates will occur and consumers must be idempotent. Store processed event IDs or use natural idempotent updates like version checks. Failed messages should go to a dead letter queue after limited retries.

49. What is a dead letter queue and how do you use it?

A dead letter queue (DLQ) is a separate queue where messages are sent when they cannot be processed successfully after a set number of retries. It prevents one poison message from blocking the consumer or being retried forever. Messages in the DLQ keep their original payload and error details, so you can alert on them, inspect the cause, fix the bug, and replay them. Monitor DLQ depth as a key health signal.

50. A request through five microservices is suddenly slow. How would you troubleshoot it?

Start with distributed tracing: find a slow trace by its ID and look at the span timings to see which service or call contributes the most latency. Then check that service's metrics for saturation, such as CPU, thread pool, connection pool, and garbage collection, and its dependencies like the database or a downstream timeout. Correlate with logs using the trace ID, and check for recent deployments, retry storms, or cold caches. Fix the bottleneck, then add alerts and timeouts.

More Design & Architecture interview questions

OOP · Data Structures · Project Architecture · System Design · All interview questions