Skip to main content

Command Palette

Search for a command to run...

design patterns

Microservices Architecture Patterns

Essential patterns for designing, implementing, and operating microservices-based systems.

Microservices Architecture Patterns

TL;DR

Microservices patterns solve specific distributed systems challenges: decomposition, data management, communication, and reliability. Choose patterns based on your actual problems, not because they're popular. Most systems need only a subset of these patterns.

Key Takeaways

  • Decomposition patterns define service boundaries (by business capability, subdomain, or team)
  • Data patterns address the distributed data challenge (database per service, saga, CQRS)
  • Communication patterns handle service interaction (sync vs async, API gateway)
  • Reliability patterns ensure system resilience (circuit breaker, bulkhead, retry)
  • Start simple: adopt patterns incrementally as complexity demands

Why This Matters

Microservices introduce complexity that monoliths don't have: network failures, distributed transactions, eventual consistency, and operational overhead. Patterns provide proven solutions to these challenges. However, applying patterns prematurely or inappropriately creates unnecessary complexity. Understanding when and why to use each pattern is as important as understanding how.

Pattern Overload

Don't implement all patterns upfront. Start with the simplest architecture that works, then add patterns as specific problems emerge. Every pattern has a cost.


Pattern Categories

MICROSERVICES PATTERNS
├── DECOMPOSITION: How to break down the system
│   ├── By Business Capability
│   ├── By Subdomain (DDD)
│   └── Strangler Fig (migration)
│
├── DATA MANAGEMENT: How to handle distributed data
│   ├── Database per Service
│   ├── Saga Pattern
│   ├── CQRS
│   └── Event Sourcing
│
├── COMMUNICATION: How services talk
│   ├── API Gateway
│   ├── Service Mesh
│   ├── Async Messaging
│   └── Backend for Frontend (BFF)
│
└── RELIABILITY: How to stay resilient
    ├── Circuit Breaker
    ├── Bulkhead
    ├── Retry with Backoff
    └── Health Check

Pattern Landscape

Loading diagram...

Decomposition Patterns

Problem

How do you define service boundaries that are stable and meaningful?

Solution

Identify business capabilities—what the business does—and create services around them.

BUSINESS CAPABILITIES (E-commerce Example)
├── Product Management
│   └── Services: Catalog, Inventory, Pricing
├── Order Management
│   └── Services: Orders, Fulfillment, Returns
├── Customer Management
│   └── Services: Customer Profile, Loyalty, Support
└── Payment Processing
    └── Services: Payments, Invoicing, Refunds

When to Use

  • Business capabilities are well-understood
  • Organizational structure aligns with capabilities
  • Need stable, long-lived service boundaries

Trade-offs

BenefitCost
Stable boundariesMay not match technical concerns
Business alignmentRequires deep domain knowledge
Team ownership clarityCross-cutting concerns span services

Conway's Law

Service boundaries often reflect team structure. Design both together. A service owned by multiple teams will struggle; a team owning multiple services will merge them.


Data Management Patterns

Problem

How do you ensure services are loosely coupled when they share data?

Solution

Each service owns its data exclusively. No direct database access across services.

DATABASE PER SERVICE

✓ CORRECT                    ✗ WRONG
┌─────────┐ ┌─────────┐     ┌─────────┐ ┌─────────┐
│Service A│ │Service B│     │Service A│ │Service B│
└────┬────┘ └────┬────┘     └────┬────┘ └────┬────┘
     │           │               │           │
┌────▼────┐ ┌────▼────┐     ┌────▼───────────▼────┐
│  DB A   │ │  DB B   │     │    Shared Database   │
└─────────┘ └─────────┘     └──────────────────────┘

Implications

AspectApproach
Data accessVia service API only
JoinsDone in application code
TransactionsDistributed (saga pattern)
ConsistencyEventually consistent
Schema changesService controls its own

When to Use

  • True service independence required
  • Teams need autonomy over their data
  • Different data storage needs per service

Polyglot Persistence

Database per service enables polyglot persistence: use PostgreSQL for transactional data, MongoDB for documents, Redis for caching, each where it fits best.


Communication Patterns

Problem

How do clients interact with multiple microservices efficiently?

Solution

Single entry point that routes requests, handles cross-cutting concerns.

API GATEWAY RESPONSIBILITIES

                    ┌───────────────────┐
                    │    API Gateway    │
                    │                   │
Client ────────────→│ • Authentication  │
                    │ • Rate limiting   │
                    │ • Request routing │
                    │ • Response caching│
                    │ • Protocol transl.│
                    │ • Load balancing  │
                    └─────────┬─────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
   ┌─────────┐          ┌─────────┐          ┌─────────┐
   │Service A│          │Service B│          │Service C│
   └─────────┘          └─────────┘          └─────────┘

Gateway Patterns

PatternUse Case
RoutingDirect requests to appropriate service
AggregationCombine multiple service responses
OffloadingHandle auth, SSL, caching centrally
BFFClient-specific gateways (see below)

Implementation Options

AWS API Gateway, Azure API Management, Kong, Nginx, or custom. Cloud-native options reduce operational burden.


Reliability Patterns

Problem

A failing service causes cascading failures across the system.

Solution

Detect failures and stop calling the failing service temporarily.

CIRCUIT BREAKER STATES

     ┌───────────────────────────────────────────────┐
     │                                               │
     ▼                                               │
┌─────────┐  failure threshold  ┌─────────┐         │
│ CLOSED  │ ─────────────────→  │  OPEN   │         │
│(normal) │                     │ (fail)  │         │
└─────────┘                     └────┬────┘         │
     ▲                               │              │
     │         timeout               ▼              │
     │                         ┌──────────┐         │
     │    success              │HALF-OPEN │         │
     └─────────────────────────│ (test)   │─────────┘
                               └──────────┘  failure

Configuration Parameters

CIRCUIT BREAKER CONFIG
├── Failure threshold: 5 failures in 60 seconds
├── Success threshold: 3 successes to close
├── Timeout: 30 seconds before half-open
├── Fallback: Cached response, default value, error
└── Monitoring: Track state changes, failure rates

Implementation Example

// Pseudocode
class CircuitBreaker {
  state = 'CLOSED'
  failures = 0
 
  async call(fn) {
    if (this.state === 'OPEN') {
      if (this.timeoutExpired()) {
        this.state = 'HALF_OPEN'
      } else {
        return this.fallback()
      }
    }
 
    try {
      const result = await fn()
      this.onSuccess()
      return result
    } catch (error) {
      this.onFailure()
      throw error
    }
  }
}

Quick Reference Card

┌─────────────────────────────────────────────────────────────┐
│            MICROSERVICES PATTERNS CHEAT SHEET               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  DECOMPOSITION                                              │
│  ─────────────────────────────────────────────────────────  │
│  By Capability    → Stable business-aligned boundaries      │
│  By Subdomain     → DDD bounded contexts                    │
│  Strangler Fig    → Incremental migration                   │
│                                                             │
│  DATA MANAGEMENT                                            │
│  ─────────────────────────────────────────────────────────  │
│  DB per Service   → Loose coupling, service autonomy        │
│  Saga             → Distributed transactions                │
│  CQRS             → Separate read/write optimization        │
│  Event Sourcing   → Audit trail, temporal queries           │
│                                                             │
│  COMMUNICATION                                              │
│  ─────────────────────────────────────────────────────────  │
│  API Gateway      → Single entry, cross-cutting concerns    │
│  BFF              → Client-specific backends                │
│  Async Messaging  → Loose coupling, resilience              │
│                                                             │
│  RELIABILITY                                                │
│  ─────────────────────────────────────────────────────────  │
│  Circuit Breaker  → Fail fast, prevent cascade              │
│  Bulkhead         → Isolate failures                        │
│  Retry + Backoff  → Handle transient failures               │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│  RULE: Start simple. Add patterns when problems emerge.     │
└─────────────────────────────────────────────────────────────┘


Sources