Microservices Patterns

saurabh mittalsaurabh mittal
5 min read

Table of contents

  1. Decomposition Patterns : breaking down a complex system or application into smaller, more manageable, and independent components or services.

    1. Domain-Driven Design (DDD):Divides services based on business domains, ensuring each service represents a distinct bounded context.

      1. Example: An e-commerce system might have separate services for Inventory, Orders, and Payments.
    2. Subdomain Decomposition: Breaks down a complex domain into smaller, more manageable subdomains.

    3. Example: The Orders service could be further divided into Order Management, Shipping, and Billing subdomains.

  2. Communication Patterns

    1. 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.

      1. Example: An API Gateway routes requests to Order Service, Payment Service, and User Service depending on the endpoint.
    2. 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.

      1. Example: Istio is a popular service mesh that provides observability and security for microservices.
    3. Synchronous Communication (REST/GraphQL):Services communicate via HTTP using REST or GraphQL APIs. This is common but introduces tight coupling and potential latency issues.

      1. Example: A frontend makes a REST call to User Service to fetch user data.
    4. 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.

      1. Example: An Order Service publishes an event when an order is placed, which the Inventory Service listens to and updates stock accordingly.

      2. Fan-out is a messaging pattern where messages are broadcast in a one-to-many arrangement

  3. Database Patterns

    1. 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.

      1. Example: User Service uses a PostgreSQL database, while Product Service uses MongoDB.
    2. Shared Database: Multiple services share a single database. Easier to maintain consistency but can lead to tight coupling and complex migrations.

      1. Example: Both Order Service and Payment Service use the same relational database.
    3. 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.

      1. Example: When an order is placed, Order Service, Payment Service, and Shipping Service each perform part of the transaction. If payment fails, the order is canceled.
    4. 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.

      1. Example: Order Service uses a relational database for writes and an in-memory cache like Redis for reads.
    5. Event Sourcing: Instead of storing the current state, events that represent state changes are stored. The current state is derived by replaying these events.

      1. 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.
  4. Deployment Patterns

    1. 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.

      1. Example: Each microservice runs in its own Docker container on separate virtual machines.
    2. Multiple Services per Host: Multiple services are deployed on the same host. This reduces costs but can lead to resource contention.

      1. Example: Multiple microservices share the same Kubernetes pod or EC2 instance.
    3. Service Instance per Container: Each instance of a service runs in its own container, allowing for better resource isolation and management.

      1. Example: Using Docker, each service instance runs in its own container, scaled across multiple nodes in a Kubernetes cluster.
  5. Observability Patterns

    1. Health Check Pattern: Regularly checks the health of services and their dependencies to ensure they are running correctly.

      1. Example: A /health endpoint in each service returns the status of the service and its database connections.
    2. Log Aggregation: Collects and centralizes logs from all services to make it easier to monitor and debug the system.

      1. Example: ELK (Elasticsearch, Logstash, Kibana) stack aggregates logs from various microservices for centralized viewing.
    3. Distributed Tracing: Traces requests as they propagate through various microservices, helping to identify performance bottlenecks and errors.

      1. Example: Using tools like Jaeger or Zipkin to trace the lifecycle of a request across multiple services.
    4. Metrics Collection: Collects metrics from services to monitor performance, such as response times, error rates, and resource utilization.

      1. Example: Prometheus collects metrics from microservices, and Grafana visualizes them.
  6. Security Patterns

    1. Access Token Pattern (OAuth2):Uses tokens to secure API calls between services, ensuring only authorized services can interact.

      1. Example: A client uses OAuth2 to get a token, which it then uses to authenticate with microservices.
    2. Circuit Breaker Pattern: Prevents a service from repeatedly trying to call a failing service, reducing the risk of cascading failures.

      1. Example: If the Payment Service fails, the circuit breaker trips and subsequent calls are automatically failed until the service is healthy again.
    3. Bulkhead Pattern: Isolates resources into pools so that a failure in one part of the system doesn’t overload other parts.

      1. Example: Separate thread pools for different services to prevent a slow Inventory Service from impacting the responsiveness of Order Service.
  7. Resilience Patterns

    1. Retry Pattern: Automatically retries failed operations with a delay between attempts, handling transient failures.

      1. Example: If a call to Payment Gateway Service fails due to a network glitch, it is retried after a short delay.
    2. Timeout Pattern: Sets timeouts for requests between services to avoid waiting indefinitely for a response.

      1. Example: A request to External Payment Service is set to timeout after 5 seconds if no response is received.
  8. Anti-Patterns

    1. Distributed Monolith: A microservices architecture in name only, where services are tightly coupled and deployed together, negating the benefits of microservices.

      1. Example: Every microservice depends on a single, shared database schema, making independent deployment difficult.
    2. God Service: A service that has too many responsibilities, becoming a bottleneck and source of complexity.

      1. Example: A User Service that handles authentication, authorization, profile management, and billing, rather than delegating these responsibilities to separate services.
0
Subscribe to my newsletter

Read articles from saurabh mittal directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

saurabh mittal
saurabh mittal