Mastering Service Branch Mode and Fault‑Tolerance Patterns in Microservices
This article explains service branch mode, its impact on availability, asynchronous messaging, shared‑data anti‑patterns, and essential microservice fault‑tolerance techniques such as compartment isolation, circuit breaking, rate limiting, and failover strategies.
Service Branch Mode
Service branch mode combines service proxy, aggregation, and chain patterns, allowing a branch service to have its own database, invoke multiple backend services or chains, and compose results before returning to the client, or simply proxy a backend service.
The architecture is shown in the diagram below.
In real business platforms, microservice dependencies often form multi‑level tree structures. For example, an e‑commerce payment service integrates two external payment gateways and a balance payment, illustrating a typical branch mode.
When a single instance of a foundational service (e.g., service 6 with 8 machines) fails, the impact on traffic is larger than the expected 1/8 because multiple layers of the call chain may repeatedly invoke the same base service, causing cumulative loss. The following formulas (shown in the diagrams) calculate the correct traffic impact and the required number of machines to keep availability fluctuation below a target value.
Result: at least 9 instances of service 6 are needed so that a single‑machine failure keeps availability fluctuation under 25%.
Service Asynchronous Messaging Mode
Previous composition patterns use synchronous RESTful calls, which block threads and can cause thread‑pool exhaustion. To avoid this, core services remain synchronous while peripheral services communicate via asynchronous message queues.
The architecture is illustrated below.
In the diagram, an aggregation service synchronously calls services 1 and 2; service 2 then pushes asynchronous messages to services 3 and 4. A typical e‑commerce example is sending an order‑completion message to the logistics system.
Service Shared‑Data Mode
This pattern is considered an anti‑pattern; services should interact via well‑defined interfaces without sharing databases. However, two scenarios may still require data sharing:
Unitized architecture: performance‑critical platforms colocate caches or databases with microservices to minimize network overhead.
Legacy monoliths: during migration, tightly coupled tables may be temporarily shared across new services.
Outside these cases, shared‑data mode should be avoided.
Microservice Fault‑Tolerance Patterns
Microservices communicate over unreliable networks, so failures, timeouts, or crashes can cascade and cause avalanche effects. The following patterns mitigate such risks.
1. Compartment Isolation Mode
Analogous to watertight ship compartments, services are grouped into isolated pools (e.g., pre‑production, gray, production) or routed by user importance, preventing failures in one pool from affecting others.
2. Thread‑Pool Isolation
When multiple functions share a single thread pool, a surge in one function can exhaust threads and block others. Isolating thread pools per function prevents this contention.
3. Circuit‑Breaker Mode
Similar to a household fuse, a circuit‑breaker trips when load spikes, protecting the system and allowing operators to address the overloaded component before restoring service.
4. Rate‑Limiting Mode
Rate limiting controls concurrent access to protect service capacity. Common implementations include:
Counter: an atomic variable tracks requests per time window; excess requests are rejected.
Token bucket: a background thread produces tokens at a fixed rate; each request consumes a token.
Semaphore: a semaphore limits the number of concurrent permits.
Example semaphore implementation:
public class SemaphoreExample {
private ExecutorService exec = Executors.newCachedThreadPool();
public static void main(String[] args) {
final Semaphore sem = new Semaphore(5);
for (int index = 0; index < 20; index++) {
Runnable run = new Runnable() {
public void run() {
try {
// acquire permit
sem.acquire();
// simulate work
Thread.sleep((long) (Math.random()));
// release permit
sem.release();
System.out.println("Remaining permits: " + sem.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
exec.shutdown();
}
}5. Failover Mode
When circuit‑breaker or rate‑limiting rejects a request, strategies include fast‑failure with an error response, switching to a backup service, or retrying with idempotent operations.
Microservice Granularity
Services should be split by business functionality until each has a single responsibility and can be independently deployed, scaled, and maintained. Over‑splitting leads to excessive service count and complex dependencies, while under‑splitting creates tightly coupled, monolithic services. The goal is a pragmatic granularity that enables autonomous teams to own and evolve services.
In summary, applying appropriate service composition patterns, fault‑tolerance mechanisms, and sensible granularity leads to robust, maintainable microservice architectures.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
