Monolith Migration, Communication & Spring Cloud — Interview Questions
Microservices' real disadvantages and mitigations, calling other services (sync REST/gRPC vs async messaging), key design patterns, converting a monolith step by step (strangler fig, bounded contexts, data split), SOA vs microservices, how Spring Cloud helps (Gateway, Config, discovery, LoadBalancer, OpenFeign/HTTP interfaces, Resilience4j) and today's replacements for Netflix OSS, integrating Kafka, and real challenges you've faced and solved.
Published September 25, 2026
How to use this lesson
At 5–8 years, interviewers want experience-backed trade-offs, not a list of buzzwords. Do three things:
Admit the costs of microservices.
Explain how you'd migrate incrementally (the strangler fig).
Know which Spring Cloud components are current. Zuul 1, Ribbon and Hystrix are in maintenance or removed. Their replacements are Spring Cloud Gateway, Spring Cloud LoadBalancer and Resilience4j.
Q1. What are the disadvantages of microservices, and how do you address them?
Short answer:
Disadvantage
How to address it
Operational complexity: many deployables, environments and pipelines
Automation: CI/CD per service, containers + Kubernetes, IaC, templates/golden paths (a platform team)
Q2. How would you call another service in a microservice architecture?
Short answer:
Synchronous request/response, when you need the answer now:
REST over HTTP: Spring's RestClient, declarative HTTP interface clients (@HttpExchange), OpenFeign, or WebClient for reactive code.
gRPC, for low-latency, strongly typed internal calls.
Asynchronous messaging, when the caller doesn't need an immediate result: publish events or commands to Kafka or RabbitMQ. It decouples services in time and availability.
Every synchronous call needs:
service discovery (or Kubernetes DNS) and load balancing;
timeouts, retries (for idempotent calls only), a circuit breaker;
authentication (a propagated token or client credentials);
Q3. Explain a few microservices design patterns you know.
Short answer:
API Gateway: a single entry point for routing, authentication, rate limiting and aggregation. BFF is a gateway per client type.
Service discovery: services register themselves, and clients look them up (Eureka, Consul, Kubernetes DNS).
Circuit breaker: stop calling a failing dependency, and fail fast with a fallback (Resilience4j).
Database per service, and Saga (choreography or orchestration) for cross-service workflows.
Transactional outbox: publish events reliably with the database change.
CQRS, and event sourcing.
Strangler fig: migrate a monolith piece by piece.
Bulkhead, retry and timeout for resilience; sidecar/service mesh for cross-cutting network concerns.
Externalised configuration.
Observability patterns: log aggregation, distributed tracing, health checks.
(Each is covered in depth in the Microservice Patterns chapter of this course.)
Q4. You're converting a monolith into microservices with Spring Boot. Describe the steps and the challenges.
Short answer:
Understand the domain first. Use domain-driven design (event storming) to find bounded contexts. Also look at change frequency, team ownership and scaling needs, to decide what's worth extracting.
Modularise the monolith. Enforce module boundaries inside it (packages, Spring Modulith, ArchUnit tests), and remove cross-module database joins. That's often the hardest and most valuable step.
Put a gateway or routing layer in front of the monolith. This is the strangler fig.
Extract one service at a time, starting with an edge capability that's low-risk and high-value (notifications, catalogue search):
build it as a Spring Boot service with its own pipeline;
route traffic to it gradually (a feature flag or canary);
the monolith calls it through an API, or reacts to its events.
Split the data:
The new service owns its tables. Sync them during the transition with CDC (Debezium) or dual writes plus reconciliation.
Then remove the monolith's direct access.
Build the platform along the way: CI/CD, containers, observability, configuration, service-to-service security.
Repeat, and retire the code in the monolith as each piece moves.
Challenges:
Data decomposition: shared tables, joins and transactions.
Distributed consistency: sagas instead of ACID.
Latency and chattiness.
Operational overhead and skills.
Testing across services.
Organisational alignment.
The "distributed monolith" trap: services that must be deployed together, or share a database.
Q5. How does Spring Cloud enhance microservices development with Spring Boot?
Short answer: Spring Cloud provides ready-made implementations of the distributed-system patterns, configured the Boot way:
Spring Cloud Gateway: routing, filters, rate limiting, token relay.
Spring Cloud Config (or Consul/Vault configuration): centralised, versioned configuration with refresh.
Service discovery: Eureka or Consul clients, or Kubernetes discovery.
Spring Cloud LoadBalancer: client-side load balancing, integrated with @LoadBalancedRestClient/WebClient.
Spring Cloud OpenFeign: declarative HTTP clients. It's now feature-complete, and Spring recommends HTTP interface clients for new code.
Spring Cloud CircuitBreaker with Resilience4j.
Spring Cloud Stream: a binder abstraction over Kafka and RabbitMQ, with functional programming.
Spring Cloud Contract: consumer-driven contract testing.
Spring Cloud Kubernetes: ConfigMaps and Secrets as property sources.
Key points to cover:
On Kubernetes, the platform (DNS, Services, ConfigMaps, a mesh) often replaces Eureka, Config Server and client-side load balancing. Choose deliberately, and avoid running both.
Tracing moved from Spring Cloud Sleuth (now retired) to Micrometer Tracing in Boot 3.
Q6. You need an architecture with service-to-service communication. How would Spring Cloud help?
Short answer:
Discovery: each service registers (Eureka or Consul), or relies on Kubernetes DNS.
Client-side load balancing: a @LoadBalanced RestClient.Builder resolves http://inventory-service, and balances across healthy instances.
Declarative clients: HTTP interface clients or OpenFeign turn a Java interface into HTTP calls.
Resilience: Spring Cloud CircuitBreaker with Resilience4j (circuit breaker, retry, time limiter, bulkhead) around the clients.
Asynchronous paths: Spring Cloud Stream bindings to Kafka or RabbitMQ.
Edge: Spring Cloud Gateway in front of everything.
Configuration and security: Config Server or Vault; OAuth2 client credentials for service identity.
Observability: Micrometer Tracing propagates trace headers across all of these automatically.
Q7. What are the components of a typical Spring Cloud architecture?
Short answer (the current stack):
Edge: Spring Cloud Gateway.
Configuration: Spring Cloud Config Server (Git-backed), or Vault/Consul.
Discovery: Eureka or Consul, or Kubernetes.
Load balancing: Spring Cloud LoadBalancer.
Clients: OpenFeign, or HTTP interfaces.
Resilience: Resilience4j.
Messaging: Spring Cloud Stream, or Spring Kafka.
Observability: Micrometer, with Prometheus/Grafana, OpenTelemetry tracing (Zipkin, Jaeger or Tempo), and centralised logs (ELK or Loki).
Security: an OAuth2 authorization server (Keycloak, or Spring Authorization Server), with resource servers.
Common trap: the source's answer lists Zuul, Ribbon and Hystrix. Those Netflix components were put into maintenance and removed from Spring Cloud (since the 2020.0 release train). Name the replacements: Gateway, LoadBalancer, Resilience4j.
Key points to cover:
Data consistency across the services is handled with the Saga pattern: local transactions plus events, and compensating transactions on failure. There's no shared database, and no 2PC. (The source attaches this to the same question. Lesson 2 of this chapter covers it in depth.)
Q9. What challenges have you faced developing or managing microservices, and how did you address them?
Short answer: Use the STAR structure, with concrete examples. Typical, credible stories:
Cascading failures: a slow payment provider exhausted the order service's threads. The fix: timeouts + circuit breaker + bulkhead, a fallback of "payment pending", and asynchronous confirmation.
Data inconsistency: an order was marked paid but the event was lost. The fix: the transactional outbox, idempotent consumers, and a nightly reconciliation job.
Debugging a cross-service latency spike: the fix was distributed tracing, which found an N+1 of HTTP calls. It was replaced with a batch endpoint.
Breaking API changes: the fix was consumer-driven contract tests in CI, plus additive versioning.
Deployment coupling (a "distributed monolith"): the fix was removing the shared database, and backward-compatible releases.
Configuration sprawl and secrets: the fix was centralised configuration and a secrets vault.
Quantify the outcome where you can ("p99 from 2.1 s to 300 ms", "zero lost orders since").
Q10. What is service-oriented architecture (SOA)?
Short answer: SOA is an architectural style in which applications are built from reusable, network-accessible services with well-defined contracts, often enterprise-wide. It's typically integrated through an Enterprise Service Bus (ESB) that performs routing, transformation and orchestration, using SOAP/WSDL and shared canonical data models.
Key points to cover:
SOA vs microservices:
Microservices are a finer-grained, decentralised evolution of SOA.
They follow "smart endpoints, dumb pipes" (no heavy ESB logic).
Each service owns its data; there are no shared canonical databases.
They're independently deployable, and typically owned by one team.
They use lightweight protocols (REST, gRPC, events).
SOA emphasised reuse across the enterprise; microservices emphasise autonomy and speed of change.
Q11. What are some challenges you've faced while working with microservices? (The team and technology angle)
Short answer:
Polyglot sprawl: too many languages and frameworks made on-call and upgrades hard. We standardised on a paved road (Spring Boot starters, shared libraries, templates), and allowed exceptions only with justification.
Communication reliability: we moved non-critical paths to async events, and added resilience patterns to the synchronous calls.
Monitoring gaps: we rolled out golden signals per service (latency, traffic, errors, saturation), SLOs, and tracing.
Local development: we used Docker Compose/Testcontainers, and stubbed dependencies.
Ownership: we kept a clear service catalogue (Backstage), with owners and runbooks.
Follow-up questions this topic invites — and their answers
Q: What is a distributed monolith, and how do you detect one?
A: Services that are physically separate, but tightly coupled: they share a database, need lock-step deployments, make chatty synchronous chains, or require coordinated releases. Detect it by the co-change frequency between services, deployment dependencies, and failure cascades.
Q: When would you not use microservices?
A: With small teams, an early-stage product with an unclear domain, low scale requirements, or no platform or DevOps maturity. A modular monolith gives most of the benefits (boundaries, modularity) with far lower operational cost, and can be split later.
Q: gRPC or REST between internal services?
A: gRPC: binary Protobuf, HTTP/2 streaming, strong contracts, lower latency. It's good for internal high-throughput calls. REST/JSON: universal tooling, easy debugging, and browser-friendly. It's good at the edges and for simpler services.
Q: Why is Spring Cloud OpenFeign less recommended now?
A: It's in feature-complete mode. Spring Framework 6 has HTTP interface clients (@HttpExchange), backed by RestClient or WebClient, which provide the same declarative style natively, with better integration.