Challenges Introduced or Amplified by Microservices
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
Microservices make process and ownership boundaries routine, so distributed-system problems become part of normal feature work. A request can cross several services and experience latency, timeouts, partial failure, retries, or duplicate delivery. One local transaction becomes a consistency and recovery workflow across separate data owners.
For example, an order can be saved while a payment call times out. The system must decide whether to retry idempotently, compensate, mark the order pending, or reconcile later. A trace ID must connect logs and spans across services, and API/event schemas must evolve without forcing every service to deploy together.
There is also operational cost: discovery, service authentication, secrets, deployments, alerts, capacity, and on-call ownership for many units. Some of these concerns can exist in a monolith, but network and independent-deployment boundaries amplify them. That is why microservices should buy a clear autonomy, isolation, or scaling benefit.
Challenges Introduced or Amplified by Microservices
Direct Answer
Microservices amplify distributed-system concerns: network latency and partial failure, cross-service consistency, API/event compatibility, service discovery, authentication between services, observability across hops, and operating many deployable units. Monoliths can also face several of these issues, but crossing process and ownership boundaries makes them routine.
Code Example
// Monolith: atomic transaction
@Transactional
public void placeOrder(Order order) {
orderRepository.save(order);
inventoryRepository.decrementStock(order.productId());
// Both succeed or both rollback automatically
}
// Microservices: no shared transaction
public void placeOrder(Order order) {
var savedOrder = orderService.createOrder(order); // HTTP call to OrderService
try {
inventoryService.reserveStock(order.productId()); // HTTP call to InventoryService
} catch (Exception e) {
// Inventory failed, but order is already saved!
// Need compensating transaction to cancel order
orderService.cancelOrder(savedOrder.id());
throw new OrderFailedException("Could not reserve inventory");
}
// What if cancelOrder fails? Need Saga pattern or outbox pattern
}
Common Mistakes & Pitfalls
- Assuming network is reliable: Freshers write code that calls another service without handling timeouts, retries, or circuit breakers. In production, networks are flaky—services go down, pods restart, DNS fails. Code that doesn't expect failures will crash.
- Ignoring eventual consistency: Expecting data to be immediately consistent across services like in a monolith. If UserService updates a username, it might take seconds for OrderService to see the new name if it caches user data. Freshers don't design for stale reads.
- Skipping distributed tracing setup: When a bug happens, freshers grep through logs from five services manually. Correlation IDs and distributed tracing make a request path far easier to reconstruct. Production systems generate thousands of logs per second—manual correlation becomes slow and unreliable at scale.
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.