Microservices Patterns

Table of contents
Decomposition Patterns : breaking down a complex system or application into smaller, more manageable, and independent components or services.
Domain-Driven Design (DDD):Divides services based on business domains, ensuring each service represents a distinct bounded context.
- Example: An e-commerce system might have separate services for
Inventory
,Orders
, andPayments
.
- Example: An e-commerce system might have separate services for
Subdomain Decomposition: Breaks down a complex domain into smaller, more manageable subdomains.
Example: The
Orders
service could be further divided intoOrder Management
,Shipping
, andBilling
subdomains.
Communication Patterns
API Gateway Pattern: A single entry point for all client requests, routing them to the appropriate microservices. It can also handle cross-cutting concerns like authentication, logging, and rate limiting.
- Example: An API Gateway routes requests to
Order Service
,Payment Service
, andUser Service
depending on the endpoint.
- Example: An API Gateway routes requests to
Service Mesh: Manages inter-service communication by providing advanced networking features like load balancing, service discovery, and failure recovery without requiring changes to application code.
- Example: Istio is a popular service mesh that provides observability and security for microservices.
Synchronous Communication (REST/GraphQL):Services communicate via HTTP using REST or GraphQL APIs. This is common but introduces tight coupling and potential latency issues.
- Example: A frontend makes a REST call to
User Service
to fetch user data.
- Example: A frontend makes a REST call to
Asynchronous Communication (Messaging/Event-Driven):Services communicate via message brokers (e.g., RabbitMQ, Kafka) or event-driven architecture. This allows for loose coupling and better scalability.
Example: An
Order Service
publishes an event when an order is placed, which theInventory Service
listens to and updates stock accordingly.Fan-out is a messaging pattern where messages are broadcast in a one-to-many arrangement
Database Patterns
Database per Service: Each micro-service has its own database to avoid tight coupling. This allows services to evolve independently but can lead to data consistency challenges.
- Example:
User Service
uses a PostgreSQL database, whileProduct Service
uses MongoDB.
- Example:
Shared Database: Multiple services share a single database. Easier to maintain consistency but can lead to tight coupling and complex migrations.
- Example: Both
Order Service
andPayment Service
use the same relational database.
- Example: Both
Saga Pattern: Manages distributed transactions across multiple services by coordinating a series of local transactions. If one fails, compensating actions are triggered to roll back changes.
- Example: When an order is placed,
Order Service
,Payment Service
, andShipping Service
each perform part of the transaction. If payment fails, the order is canceled.
- Example: When an order is placed,
CQRS (Command Query Responsibility Segregation):Separates the read and write models, with one handling commands (writes) and another handling queries (reads). This can optimize performance and scalability.
- Example:
Order Service
uses a relational database for writes and an in-memory cache like Redis for reads.
- Example:
Event Sourcing: Instead of storing the current state, events that represent state changes are stored. The current state is derived by replaying these events.
- Example: In a banking system, each transaction (deposit, withdrawal) is an event stored in the event store, and the current account balance is calculated by replaying these events.
Deployment Patterns
Single Service per Host: Each service is deployed on its own host, such as a VM or container. This isolates services but can lead to higher infrastructure costs.
- Example: Each microservice runs in its own Docker container on separate virtual machines.
Multiple Services per Host: Multiple services are deployed on the same host. This reduces costs but can lead to resource contention.
- Example: Multiple microservices share the same Kubernetes pod or EC2 instance.
Service Instance per Container: Each instance of a service runs in its own container, allowing for better resource isolation and management.
- Example: Using Docker, each service instance runs in its own container, scaled across multiple nodes in a Kubernetes cluster.
Observability Patterns
Health Check Pattern: Regularly checks the health of services and their dependencies to ensure they are running correctly.
- Example: A
/health
endpoint in each service returns the status of the service and its database connections.
- Example: A
Log Aggregation: Collects and centralizes logs from all services to make it easier to monitor and debug the system.
- Example: ELK (Elasticsearch, Logstash, Kibana) stack aggregates logs from various microservices for centralized viewing.
Distributed Tracing: Traces requests as they propagate through various microservices, helping to identify performance bottlenecks and errors.
- Example: Using tools like Jaeger or Zipkin to trace the lifecycle of a request across multiple services.
Metrics Collection: Collects metrics from services to monitor performance, such as response times, error rates, and resource utilization.
- Example: Prometheus collects metrics from microservices, and Grafana visualizes them.
Security Patterns
Access Token Pattern (OAuth2):Uses tokens to secure API calls between services, ensuring only authorized services can interact.
- Example: A client uses OAuth2 to get a token, which it then uses to authenticate with microservices.
Circuit Breaker Pattern: Prevents a service from repeatedly trying to call a failing service, reducing the risk of cascading failures.
- Example: If the
Payment Service
fails, the circuit breaker trips and subsequent calls are automatically failed until the service is healthy again.
- Example: If the
Bulkhead Pattern: Isolates resources into pools so that a failure in one part of the system doesn’t overload other parts.
- Example: Separate thread pools for different services to prevent a slow
Inventory Service
from impacting the responsiveness ofOrder Service
.
- Example: Separate thread pools for different services to prevent a slow
Resilience Patterns
Retry Pattern: Automatically retries failed operations with a delay between attempts, handling transient failures.
- Example: If a call to
Payment Gateway Service
fails due to a network glitch, it is retried after a short delay.
- Example: If a call to
Timeout Pattern: Sets timeouts for requests between services to avoid waiting indefinitely for a response.
- Example: A request to
External Payment Service
is set to timeout after 5 seconds if no response is received.
- Example: A request to
Anti-Patterns
Distributed Monolith: A microservices architecture in name only, where services are tightly coupled and deployed together, negating the benefits of microservices.
- Example: Every microservice depends on a single, shared database schema, making independent deployment difficult.
God Service: A service that has too many responsibilities, becoming a bottleneck and source of complexity.
- Example: A
User Service
that handles authentication, authorization, profile management, and billing, rather than delegating these responsibilities to separate services.
- Example: A
Subscribe to my newsletter
Read articles from saurabh mittal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
