All Resources
Guide
ArchitectureDevOpsScalability
June 14, 2024

Microservices Architecture Patterns

Design scalable systems with microservices - services, communication, and deployment.

Overview

Microservices architecture breaks applications into independent, scalable services. Learn patterns for design, communication, and deployment.

Key Patterns

  • API Gateway: Single entry point for all services
  • Service Discovery: Dynamic service location
  • Event-Driven: Async communication between services
  • Circuit Breaker: Handle failures gracefully
  • Saga Pattern: Distributed transactions

Service Structure

services/
├── auth-service/
│   └── src/
│       ├── routes.ts
│       ├── controllers/
│       └── models/
├── user-service/
├── product-service/
└── order-service/

API Gateway Pattern

// gateway.ts
import express from 'express'
import { createProxyMiddleware } from 'express-http-proxy'

const app = express()

// Route to services
app.use('/auth', createProxyMiddleware({
  target: 'http://auth-service:3001'
}))

app.use('/users', createProxyMiddleware({
  target: 'http://user-service:3002'
}))

app.use('/products', createProxyMiddleware({
  target: 'http://product-service:3003'
}))

Event-Driven Communication

import amqp from 'amqplib'

// Publish event
async function publishEvent(channel: any, event: string, data: any) {
  const exchange = 'events'
  await channel.assertExchange(exchange, 'topic', { durable: true })
  channel.publish(exchange, event, Buffer.from(JSON.stringify(data)))
}

// Subscribe to events
async function subscribeToEvent(channel: any, event: string, handler: Function) {
  const exchange = 'events'
  const queue = await channel.assertQueue('', { exclusive: true })
  
  await channel.bindQueue(queue.queue, exchange, event)
  
  channel.consume(queue.queue, (msg) => {
    if (msg) {
      handler(JSON.parse(msg.content.toString()))
      channel.ack(msg)
    }
  })
}

Circuit Breaker Pattern

class CircuitBreaker {
  private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED'
  private failureCount = 0
  private threshold = 5

  async call(fn: () => Promise<any>) {
    if (this.state === 'OPEN') {
      throw new Error('Circuit breaker is open')
    }

    try {
      const result = await fn()
      this.failureCount = 0
      this.state = 'CLOSED'
      return result
    } catch (error) {
      this.failureCount++
      if (this.failureCount >= this.threshold) {
        this.state = 'OPEN'
        setTimeout(() => this.state = 'HALF_OPEN', 30000)
      }
      throw error
    }
  }
}

Microservices enable teams to deploy changes independently, reducing time-to-market by 50%.

Curated by

Shyam