Microservices Architecture

Back to Software Development Index

What is a Service?

Service คือซอฟต์แวร์ ที่ทำงานโดยไม่ขึ้นกับกัน (independently deployable) มีขอบเขตการทำงานที่ชัดเจน

Key Characteristics:

  • Independently deployable - Deploy ได้โดยไม่กระทบระบบอื่น
  • Loosely coupled - ไม่ผูกติดกันมาก สามารถเปลี่ยนแปลงได้
  • Business capability focused - แต่ละ service ทำงานตาม business function
  • Owns its data - แต่ละ service มี database ของตัวเอง

Why Microservices?

✅ Benefits

1. Independent Deployment

  • Deploy service ใด service หนึ่งโดยไม่ต้อง deploy ทั้งระบบ
  • ลด downtime และ risk

2. Technology Diversity

  • แต่ละ service เลือกเทคโนโลยีที่เหมาะสมได้
  • ง่ายต่อการทดลองเทคโนโลยีใหม่

3. Scalability

  • Scale เฉพาะ service ที่มี load สูง
  • ประหยัดทรัพยากร

4. Team Autonomy

  • แต่ละทีมดูแล service ของตัวเอง
  • ทำงานได้เร็วขึ้น ลดการรอคอย

5. Resilience

  • Service หนึ่งล่มไม่กระทบทั้งระบบ
  • Isolate failures

6. Easier to Understand

  • แต่ละ service เล็ก เข้าใจง่าย
  • Onboard developer ใหม่เร็วขึ้น

❌ Challenges

1. Increased Complexity

  • Distributed system ซับซ้อนกว่า monolith
  • ต้องจัดการ inter-service communication

2. Operational Overhead

  • ต้อง deploy, monitor หลาย services
  • ต้องการ DevOps, automation

3. Data Consistency

  • ไม่มี transaction ข้าม services
  • ต้องใช้ eventual consistency

4. Testing Complexity

  • Integration testing ยากขึ้น
  • ต้อง test การทำงานร่วมกันของหลาย services

5. Network Latency

  • การเรียกผ่าน network ช้ากว่า in-memory
  • ต้อง optimize communication

6. Debugging Difficulty

  • Error อาจเกิดจากหลาย services
  • ต้องมี distributed tracing

When to Use Microservices?

Use Microservices When: ✅

  • Large, complex applications
  • Multiple teams working on different areas
  • Need independent deployment cycles
  • Different scalability requirements per module
  • Long-term project (years)
  • Team has DevOps expertise

Stick with Monolith When: ❌

  • Small applications
  • Small team (< 10 developers)
  • Tight deadlines
  • Limited DevOps resources
  • Unclear requirements
  • Startup/MVP phase

Remember: Start with monolith, move to microservices when needed

Domain-Driven Design & Bounded Context

ใช้ DDD ในการแบ่ง microservices:

Bounded Context:

  • แต่ละ context คือ 1 service (โดยทั่วไป)
  • มี ubiquitous language ของตัวเอง
  • มี database ของตัวเอง

Example: E-commerce

┌─────────────────┐  ┌─────────────────┐
│  Order Service  │  │ Payment Service │
│                 │  │                 │
│ - Order         │  │ - Transaction   │
│ - OrderItem     │  │ - PaymentMethod │
│ - Customer      │  │ - Receipt       │
└─────────────────┘  └─────────────────┘

┌─────────────────┐  ┌─────────────────┐
│ Product Service │  │ Shipping Service│
│                 │  │                 │
│ - Product       │  │ - Shipment      │
│ - Category      │  │ - Tracking      │
│ - Inventory     │  │ - Carrier       │
└─────────────────┘  └─────────────────┘

Same Entity, Different Context:

  • “Customer” in Order Service → Order history, preferences
  • “Customer” in Payment Service → Payment methods, billing address
  • “Customer” in Shipping Service → Delivery addresses

Microservices Patterns

1. Load Balancer Pattern

         ┌─────────────┐
         │Load Balancer│
         └──────┬──────┘
        ┌───────┼───────┐
        │       │       │
    ┌───▼──┐ ┌──▼──┐ ┌─▼───┐
    │Srv 1 │ │Srv 2│ │Srv 3│
    └──────┘ └─────┘ └─────┘
  • กระจาย traffic ไปยังหลาย instances
  • เพิ่ม availability และ throughput
  • Tools: Nginx, HAProxy, AWS ELB

2. API Composition Pattern

    ┌─────────┐
    │ Client  │
    └────┬────┘
         │
    ┌────▼────────┐
    │ API Gateway │
    └────┬────────┘
         │
   ┌─────┼─────┐
   │     │     │
┌──▼─┐ ┌─▼─┐ ┌▼──┐
│Srv1│ │Sv2│ │Sv3│
└────┘ └───┘ └───┘
  • API Gateway รวม data จากหลาย services
  • Client ติดต่อจุดเดียว
  • Examples: User profile = User Service + Order Service + Review Service

3. SAGA Pattern

จัดการ distributed transactions โดยไม่ใช้ 2-phase commit

Choreography-based SAGA:

Order → Payment → Inventory → Shipping
  ↓       ↓          ↓           ↓
 Events  Events    Events     Events
  • แต่ละ service publish event
  • Service อื่นๆ subscribe และทำงานต่อ
  • ถ้าล้ม ทำ compensating transaction

Orchestration-based SAGA:

        ┌──────────────┐
        │ SAGA Manager │
        └──────┬───────┘
       ┌───────┼───────┐
       │       │       │
    ┌──▼─┐  ┌─▼──┐  ┌─▼──┐
    │Ord │  │Pay │  │Inv │
    └────┘  └────┘  └────┘
  • Central orchestrator จัดการ flow
  • ง่ายต่อการ monitor และ debug

4. Event Sourcing

เก็บทุก event ที่เกิดขึ้นในระบบ แทนที่จะเก็บแค่ state ปัจจุบัน

Benefits:

  • Audit trail เต็มรูปแบบ
  • Time travel - ย้อนดู state ในอดีต
  • Event replay - Rebuild state ใหม่ได้

Example:

Events:
1. AccountCreated(userId: 1, balance: 0)
2. MoneyDeposited(userId: 1, amount: 1000)
3. MoneyWithdrawn(userId: 1, amount: 500)

Current State: balance = 500

5. CQRS (Command Query Responsibility Segregation)

แยก model สำหรับ read และ write

┌──────────────────┐
│  Command Side    │ Write Model
│  (Write DB)      │ Optimized for updates
└────────┬─────────┘
         │ Events
         ▼
┌──────────────────┐
│   Query Side     │ Read Model
│   (Read DB)      │ Optimized for queries
└──────────────────┘

Benefits:

  • Optimize แยกกันได้
  • Scale read/write แยกกัน
  • ใช้ database ต่างกันได้

When to Use:

  • Read และ write patterns ต่างกันมาก
  • ต้องการ scale read/write แยกกัน
  • ต้องการ read model หลายแบบ

Handling Failures

Circuit Breaker Pattern

┌──────────┐
│  Closed  │ ──fail──> ┌──────────┐
│ (Normal) │           │   Open   │
└────┬─────┘           │(Blocking)│
     │                 └────┬─────┘
     │                      │
     │                   timeout
     │                      │
     │                 ┌────▼─────┐
     └────success─────│Half-Open │
                      │ (Testing)│
                      └──────────┘

States:

  • Closed: Normal, requests go through
  • Open: Too many failures, block requests
  • Half-Open: Try again after timeout

Benefits:

  • Prevent cascading failures
  • Fast failure
  • Automatic recovery

Tools: Hystrix, Resilience4j, Polly

Retry with Exponential Backoff

func RetryWithBackoff(fn func() error, maxRetries int) error {
    for i := 0; i < maxRetries; i++ {
        err := fn()
        if err == nil {
            return nil
        }
        
        if i == maxRetries-1 {
            return err
        }
        
        // Exponential backoff: 1s, 2s, 4s, 8s...
        time.Sleep(time.Duration(1<<i) * time.Second)
    }
    return nil
}

Timeout Pattern

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
 
resp, err := client.Get(ctx, "http://service/api")
if err != nil {
    // Handle timeout
}

Scaling Strategies

Horizontal Scaling (Scale Out)

เพิ่มจำนวน instances:

1 instance -> 2 instances -> 4 instances

Pros:

  • Unlimited scaling (theoretically)
  • High availability
  • Easy with cloud

Cons:

  • Need load balancer
  • Stateless design required
  • More complex

Vertical Scaling (Scale Up)

เพิ่ม resources (CPU, RAM):

2 CPU, 4GB -> 4 CPU, 8GB -> 8 CPU, 16GB

Pros:

  • Simple
  • No code changes
  • Works with stateful apps

Cons:

  • Limited by hardware
  • Single point of failure
  • More expensive

Auto Scaling

# Kubernetes HPA example
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-service
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-service
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Database Strategies

1. Database per Service

แต่ละ service มี database ของตัวเอง:

Service A ──> Database A
Service B ──> Database B
Service C ──> Database C

Pros:

  • Loose coupling
  • Independent scaling
  • Technology diversity

Cons:

  • No cross-service transactions
  • Data duplication
  • Complex queries

2. Shared Database (Anti-pattern)

หลาย services ใช้ database เดียวกัน:

Service A ──┐
Service B ──┼──> Shared Database
Service C ──┘

Why Avoid:

  • Tight coupling
  • Schema changes affect all
  • Hard to scale independently
  • Breaks microservices principles

3. Saga Pattern for Consistency

ใช้ distributed transactions แทน ACID:

Order Service: Create Order
  ↓ (success)
Payment Service: Process Payment
  ↓ (success)
Inventory Service: Reserve Items
  ↓ (failure)
Payment Service: Refund
  ↓
Order Service: Cancel Order

Communication Patterns

Synchronous (REST, gRPC)

Client ──request──> Service A ──request──> Service B
       <─response──           <─response──

Pros: ✅ Simple, immediate response Cons: ❌ Tight coupling, cascading failures

Asynchronous (Message Queue)

Service A ──> [Queue] ──> Service B
                ↓
            Service C

Pros: ✅ Loose coupling, resilient Cons: ❌ Complex, eventual consistency

Tools: RabbitMQ, Kafka, AWS SQS

Testing Microservices

Testing pyramid สำหรับ microservices:

        ╱╲
       ╱E2E╲        ← Fewest, most expensive
      ╱──────╲
     ╱Contract╲     ← API contracts between services
    ╱──────────╲
   ╱Integration╲    ← Test service integration
  ╱──────────────╲
 ╱  Unit Tests   ╲ ← Most, cheapest
╱────────────────╲

Contract Testing

ทำให้มั่นใจว่า services พูดคุยกันได้:

Consumer ←─ Contract ─→ Provider
  Test                    Test

Tools: Pact, Spring Cloud Contract


Related:

References: