System Design Examples
Use Cases and System Design Examples
As we've seen so far, the Circuit Breaker pattern can be a powerful strategy for building resilient systems. But where and how can it be used effectively? In this section, we'll explore some common use cases for the Circuit Breaker pattern and provide some system design examples that illustrate the pattern in action.
Use Case 1: Microservices Architecture
Microservices architectures have gained popularity due to their ability to create loosely coupled, independently deployable components. But they also introduce more points of communication, and consequently, more points of failure.
Consider a typical e-commerce application split into microservices such as user management, product catalog, shopping cart, and order processing. Each service might depend on others to fulfill requests. For example, the order processing service might rely on the product catalog to validate product availability and the user management service to validate user credentials.
Now, what happens if the product catalog service starts failing? Without any safeguards in place, the failures would start impacting the order processing service, leading to a degraded user experience or even a total outage.
Here, the Circuit Breaker pattern can be invaluable. By placing a Circuit Breaker in front of the product catalog service, the order processing service can detect failures quickly and stop sending requests to the failing service. It can instead fall back to a cached product list or even fail gracefully by providing a relevant error message to the user.
This is just one instance of how the Circuit Breaker pattern can be used effectively in a microservices architecture. By isolating faults and preventing them from cascading, it can significantly enhance the system's resilience and ensure high availability.
Use Case 2: External API Integration
Integrating external APIs into your system is another scenario where the Circuit Breaker pattern can shine. External APIs are outside of your control and can be unpredictable. They can have downtime, latency spikes, or rate limiting policies that can impact your system.
Imagine a weather forecasting application that pulls data from several external weather APIs. If one of these APIs starts to fail or becomes slow, it could degrade the overall performance of the application or even cause it to fail.
By implementing a Circuit Breaker for each external API, the application can detect and isolate the problematic API, ensuring that its issues do not affect the overall system. The application could then either switch to another API or provide a degraded service until the faulty API recovers.
Use Case 3: Database Access
Database access is a crucial part of most applications, and database issues can quickly lead to severe system problems. Whether it's due to network issues, resource contention, or database server failures, these problems can cause slow responses or errors in your application.
A Circuit Breaker can help here too. For instance, in a system with a read-heavy database load, a Circuit Breaker can monitor the database's health. If it detects an increasing error rate or latency, it can trip and redirect read operations to a read replica or a cache, ensuring continuous service availability.
The same can be applied for write operations, albeit with more caution. In the case of increased errors or latency, a Circuit Breaker could trip and temporarily buffer write operations. However, it's crucial to handle this carefully, as data consistency can be at risk, and the buffer could become a bottleneck.
Real-world Use Cases
The Circuit Breaker pattern is commonly used in large-scale systems and has been proven in real-world scenarios:
-
Netflix Microservices: Netflix famously implemented the circuit breaker pattern through their open-source library Hystrix. In Netflix’s streaming service (which is a complex web of microservices), if one backend service becomes slow or fails, Hystrix isolates that failing endpoint. This stops the failure from cascading to other services and returns fallback responses so that the user experience is only minimally affected. For example, if the recommendations service is down, Netflix can still stream videos to users; the app might just omit the recommendations section or show a default message, rather than failing entirely.
-
E-commerce and APIs: Consider a large e-commerce site with many microservices (product info, inventory, pricing, reviews, etc.). If the reviews service starts failing, a circuit breaker on that service’s API calls will trip and open, so that the product page can skip showing reviews rather than slowing down the entire page. The rest of the page (product details, pricing) loads normally, and perhaps a message like “Reviews are unavailable at the moment” is shown. This is a graceful degradation. Without the circuit breaker, the product page might hang or crash while trying endlessly to fetch reviews. Similar strategies are used for payment gateways, shipping rate calculators, and other third-party integrations – if the dependent service is down, the app quickly falls back (e.g., “Sorry, we can’t process payments right now, please try again later”) instead of making users wait and wonder.
-
Cloud & Distributed Systems: Many cloud architecture solutions incorporate circuit breakers. For instance, many cloud applications encourage this pattern in order to improve stability when calling remote services. Likewise, various cloud solutions and service mesh technologies often have circuit breaker mechanisms at the infrastructure level, automatically preventing one overloaded microservice from overloading others. In an API Gateway, you might configure circuit breaker rules for each backend route so that if a backend is throwing errors, the gateway will start rejecting new requests to that backend for a short period. This protects the backend and frees the gateway to handle other routes.
-
Enterprise Integration: Even in non-microservice architectures, anytime you integrate with an external system (a SOAP/REST API, a database, a messaging system), a circuit breaker can be a lifesaver. For example, a middleware system calling a slow legacy SOAP service might use a circuit breaker to avoid tying up all its worker threads on that slow service. In reactive/streams processing, backpressure itself is handled by demand signalling (the consumer requests what it can absorb — Reactive Streams
request(n)); a circuit-breaker-style trip is a complementary guard for a consumer that is failing rather than merely slow, cutting the feed entirely so the stream can drain and recover.
These examples highlight a common theme: using circuit breakers to isolate and contain failures in one part of a system so that the whole system doesn’t collapse. In practice, many libraries and frameworks provide ready-made circuit breaker implementations. For Java, aside from Netflix Hystrix (now in maintenance mode), there’s Resilience4j, and for .NET there’s Polly, among others. Cloud platforms and service meshes have them built-in. But regardless of the implementation, the concept remains the same. Engineers designing large-scale systems routinely include circuit breakers in their toolkit for resilience.
System Design Example: Distributed Social Media Platform
Now let's imagine a distributed social media platform. The platform comprises several services: User Management, Post Management, Feed Generation, and more. Each of these services might be running on multiple nodes for high availability and load balancing.
In this scenario, the Circuit Breaker pattern can be applied in several places. For instance, Circuit Breakers could be placed in front of the User Management service. This would allow services relying on it, such as the Post Management and Feed Generation, to quickly detect when the User Management service is struggling. They could then reduce the load on the User Management service by providing a degraded service, such as displaying cached user information or providing simplified post feeds.
Similarly, a Circuit Breaker could be applied to the interaction between the Post Management service and the database storing the posts. If the database starts experiencing problems, the Circuit Breaker could trip and the Post Management service could start serving cached posts or stop accepting new posts temporarily.
Even external services, like an email service used for notifications, could have a Circuit Breaker. If the email service starts failing, the Circuit Breaker would prevent the notification feature from impacting the rest of the system.
In a distributed setting like this, we could also consider using a shared Circuit Breaker for each service, stored in a distributed cache. This would help maintain consistency across all nodes, ensuring that if a Circuit Breaker trips on one node, it trips on all nodes. However, this would need to be balanced against the additional complexity and potential performance impact.
To complement the Circuit Breakers, the system should also have a comprehensive monitoring and alerting setup. It should monitor the state of all Circuit Breakers and alert developers or system administrators when a Circuit Breaker trips. This would ensure quick detection and remediation of issues.
Remember, the goal is not to eliminate failures - they are inevitable in any system. Instead, the objective is to manage failures effectively, preventing them from cascading and causing system-wide outages. The Circuit Breaker pattern, when used judiciously and in conjunction with other resiliency patterns, can play a key role in achieving this goal.
The circuit-breaker state machine
A circuit breaker is not just a "try again later" wrapper; it is a state machine with three states and two knobs. The two knobs are the failure threshold (how many failures trip it) and the open timeout (how long it stays open before allowing a trial call). The three states are:
- CLOSED — requests flow through normally. Failures are counted; when the count reaches the threshold, the breaker snaps OPEN.
- OPEN — every call fails fast for the configured timeout, giving the downstream service room to recover.
- HALF_OPEN — after the timeout, the next call (or a small configured probe budget) is allowed through as a probe. If it succeeds, the breaker closes; if it fails, it opens again.
Worked example: payment-gateway breaker
Imagine an order service calling a payment gateway. We configure the breaker with failureThreshold = 5 failures within a rolling 10-second window and an openTimeout = 30 seconds. The gateway starts timing out:
- Calls 1–5 time out. On the fifth timeout the breaker trips to OPEN.
- Call 6, 50 ms later, fails fast with a fallback to "pay later / retry checkout."
- 30 seconds later the breaker moves to HALF_OPEN and call 7 is allowed through as a probe.
- If call 7 succeeds, the breaker closes and normal traffic resumes. If it fails, the breaker opens for another 30 seconds.
This example makes the operational point concrete: the breaker is not a retry policy; it is a load-shedding policy that protects both caller and callee.
When NOT to use a circuit breaker
Breakers are not free and not universal:
- Latency-sensitive synchronous flows. If the caller must have an answer to proceed (e.g., "did the card charge succeed?"), failing fast is still a failure. You need a retry or a different design, not a breaker that hides the problem.
- In-process calls. Inside a single process, an exception should usually propagate and be handled by normal error handling, not masked by a breaker.
- When the fallback is worse than the timeout. Returning stale inventory during a flash sale can cause overselling; sometimes it is better to degrade the whole page than to show wrong data.
- Single-threaded callers that cannot benefit from bulkheading. A breaker still helps, but without resource isolation a slow call can still consume the caller's only thread.
Operational knobs and monitoring
In production you monitor:
- Trip rate — frequent trips mean the threshold is too low or the dependency is chronically unhealthy.
- Time spent OPEN — if the breaker never closes, the downstream service is not recovering.
- Fallback success rate — a fallback that also fails is not a fallback.
- Half-open probe success — probes that repeatedly fail tell you recovery is not real.
Tune the threshold against the baseline error rate, not against zero. If the downstream normally returns 0.5% errors, a threshold of 3 failures in 10 seconds will trip constantly; a threshold of 20 in 60 seconds is closer to "real outage."
Takeaways
- A circuit breaker is a state machine: CLOSED → OPEN after failures, OPEN → HALF_OPEN after timeout, HALF_OPEN → CLOSED on probe success.
- It fails fast to give the downstream service room to recover and to preserve the caller's resources.
- Use it for cross-service / cross-process calls with a meaningful fallback; avoid it when the caller must know the result or when wrong fallback data is dangerous.
- Tune thresholds against normal error rates and monitor trip rate, open time, and fallback success.
- Scope one breaker per dependency, never one shared breaker per caller: in the checkout example a single global breaker would let a flaky shipping-quote service trip the counter and start fast-failing the healthy payment call too. Per-dependency scoping also lets each fallback and each alert be tuned to that dependency's real business cost (page on payment-open, only ticket on shipping-open).
End-to-end: which tool for the brownout — breaker, retry-budget, or load-shed?
The examples above show where to place a breaker. The harder, more interview-relevant question is which resilience tool is the right primary defense for a given failure — because a breaker, a retry-budget, and load-shedding all "handle" a struggling dependency, but they fix different problems and the wrong pick makes the outage worse. Work one concrete system end-to-end.
The system. A product-search API at the edge serves 1,000 req/s. To render each result page it calls a pricing service (a fleet of nodes behind discovery) for live prices. Normal pricing latency is 15 ms; the search API runs a bounded worker pool. Now pricing starts erroring. Let f = the fraction of pricing calls that fail.
- Retry-budget wins when the failure is a small, independent fraction. Say
f = 2%— a couple of pricing nodes are flaky, the rest are healthy, so a retry lands on a good node. One extra attempt lifts success from1 − fto1 − f² = 1 − 0.0004 = 99.96%, and the added load is only ~f = 2%more calls — well inside a Google-SRE-style retry budget capped at ~10% of request volume. A breaker here would be harmful: it might trip on the flaky minority and fast-fail requests that a single retry would have rescued. - The breaker wins when the failure is large and correlated. Say
f = 40%— pricing is broadly overloaded, every node is sick, so retries don't find a healthy target; they just pile on. Retrying now costs ~40%extra calls, which blows the 10% budget four times over and accelerates pricing's meltdown, while success limps to1 − 0.16 = 84%only in theory. The correct move is to stop calling: trip the breaker, serve a fallback (last-known price, or hide the price and show "price at checkout"), and let pricing drain. - Load-shedding is the answer to a different question. A breaker and a retry-budget both protect the caller from a bad callee. If instead the search API's own worker pool is saturating — pricing is fine, you are simply over capacity — the fix points the other way: shed low-priority requests at admission (drop crawler/prefetch traffic first) to protect the paid-user SLO. Reaching for a breaker on a healthy dependency here fixes nothing.
The crossover, derived. Retry and breaker are the same-direction tools (protect caller from callee); the switch between them is a number. A retry-once policy adds roughly f extra calls (one retry per failed call), which must stay within the retry budget b. So retry-first is safe only while
f ≤ b → with b = 10%, f* = 0.10
Below f* = 10% failure rate, a bounded retry-budget delivers higher availability at trivial added load and the breaker should stay closed. Above f* = 10%, the budget is exhausted, retries become pure amplification, and the breaker must take over and shed the dependency. That is exactly why the two compose in production — retry inside, breaker outside: the retry-budget handles the small-f regime, the breaker catches the large-f regime the budget can no longer absorb, and load-shedding sits orthogonally at admission for the self-overload case. A senior answer names all three and the ~10% crossover; a junior answer reaches for whichever one they learned first.
🤖 Don't fully get this? Learn it with Claude
Stuck on System Design Examples? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **System Design Examples** (System Design) and want to truly understand it. Explain System Design Examples from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **System Design Examples** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **System Design Examples** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **System Design Examples** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.