One of the biggest challenges in building microservices is dealing with failures. In a monolithic application, most components run within the same process. When one component calls another, the communication usually happens through a function call. If something goes wrong, the application can often detect the failure immediately.
Microservices work differently. Each service runs independently, often on different machines, and communicates with other services over a network. A single user request might pass through several services, databases, caches, and message brokers before it completes.
This creates many opportunities for things to go wrong. A service might crash. A network connection might fail. A database might become unavailable. A downstream service might respond too slowly. Sometimes, a request might succeed, but the response never reaches the caller.
These situations are normal in distributed systems.
The goal of building a resilient microservices architecture is not to eliminate failures. It is to design systems that can handle failures without bringing down the entire application.
Before exploring resilience patterns such as circuit breakers, retries, and bulkheads, we need to understand the different types of failures that can occur in distributed systems.