⚙️ Software✍️ Khoa📅 20/04/2026☕ 6 phút đọc

System Design: Resilience, Interview và Big Picture

14. Circuit Breaker & Resilience Patterns

14.1 Circuit Breaker

Vấn đề: Service B down → Service A tiếp tục gửi requests
  → A bị block chờ timeout (e.g., 30s mỗi request)
  → Thread pool của A exhausted → A cũng down → cascade failure!

Circuit Breaker pattern:

  CLOSED (bình thường):
    → Forward requests đến B
    → Count failures
    → Nếu failure_rate > threshold trong window
      → Open circuit

  OPEN (B đang down):
    → NGAY LẬP TỨC fail fast (không gửi đến B)
    → Return error hoặc fallback
    → After timeout → Half-Open

  HALF-OPEN (test recovery):
    → Allow một số requests đến B
    → Nếu success → Close circuit
    → Nếu fail → Open lại

  States:
  CLOSED ──(failure threshold)──► OPEN
    ▲                               │
    │                               │ (after timeout)
    └───── success ─── HALF-OPEN ◄──┘

Metrics cho Circuit Breaker:
  Failure rate (% failures trong sliding window)
  Slow call rate (% calls slower than threshold)
  Number of failures in time window

Libraries: Hystrix (Netflix, deprecated), Resilience4j, go-circuit-breaker

14.2 Bulkhead Pattern

Isolate failures để không lan rộng (như bulkhead trong tàu)

Thread Pool Isolation:
  Service A gọi B và C
  Thay vì dùng chung thread pool:
    B_thread_pool: 10 threads (max)
    C_thread_pool: 5 threads (max)

  Nếu B slow → chỉ B_thread_pool bị block
  C_thread_pool không bị ảnh hưởng → C vẫn hoạt động bình thường

Semaphore Isolation:
  Lightweight hơn thread pool
  Giới hạn concurrent calls đến service
  Không cần thread switching overhead

Connection Pool Isolation:
  Separate DB connection pools per database/service
  Slow query đến DB A không ảnh hưởng đến DB B

14.3 Retry Pattern

Exponential Backoff với Jitter:

attempt 1: wait 1s
attempt 2: wait 2s
attempt 3: wait 4s
attempt 4: wait 8s
attempt 5: wait 16s → give up

Jitter (quan trọng!):
  Không có jitter: tất cả clients retry cùng lúc → thundering herd
  Full jitter: wait = random(0, base × 2^attempt)
  Equal jitter: wait = base × 2^attempt / 2 + random(0, base × 2^attempt / 2)

Retry chỉ cho:
  Network errors (connection refused, timeout)
  5xx errors (server errors)
  429 Too Many Requests (với Retry-After header)

KHÔNG retry:
  4xx errors (client errors: 400, 401, 403, 404)
  Business logic errors

Idempotent operations only:
  Retry POST /payments → charge twice!
  Cần idempotency key để safe retry

15. Câu hỏi phỏng vấn Senior hay gặp

Q: CAP theorem — tại sao thực tế không chọn CA?

Trong distributed system, network partition không phải "if" mà là "when". Bạn không thể chọn "không có partition" vì network không đáng tin cậy. Do đó P là bắt buộc, và trade-off thực sự chỉ là C vs A khi partition xảy ra. "CA" chỉ có nghĩa với single-node system (không distributed). Thực tế nhiều systems chọn điểm trên spectrum: Cassandra cho phép tuning từ AP đến CP per-operation qua consistency levels.

Q: Eventual consistency và ACID consistency khác nhau như thế nào?

ACID Consistency nghĩa là data luôn thỏa mãn constraints và business rules (foreign keys, unique constraints, invariants) — đây là trách nhiệm của application và DB. CAP/Eventual Consistency nghĩa là tất cả replicas cuối cùng sẽ converge về cùng giá trị — đây là property của distributed replication. Chúng là hai chiều khác nhau hoàn toàn: có thể có eventually consistent system tuân thủ ACID trên từng node.

Q: CQRS có phải lúc nào cũng cần Event Sourcing không?

Không. CQRS và Event Sourcing là hai patterns độc lập, thường được kết hợp nhưng không bắt buộc. CQRS chỉ tách read/write models — read store có thể được update bằng trigger, CDC, hoặc synchronous projection. Event Sourcing là cách store state dưới dạng events. Có thể dùng CQRS với traditional state storage, hoặc Event Sourcing mà không cần CQRS (dù ít phổ biến hơn). Kết hợp cả hai thường phức tạp — chỉ dùng khi thực sự cần.

Q: Choreography vs Orchestration Saga — khi nào dùng gì?

Choreography phù hợp khi: ít services tham gia (2-3), flow đơn giản, muốn loose coupling tối đa, services có thể owned bởi teams khác nhau. Orchestration phù hợp khi: nhiều services, flow phức tạp với nhiều nhánh điều kiện, cần visibility và monitoring, cần retry/timeout management, cần compensate nhiều steps. Trong thực tế enterprise: orchestration thường được ưa hơn vì dễ debug và maintain dù tight coupling hơn.

Q: Outbox pattern giải quyết vấn đề gì mà Saga không giải quyết được?

Saga giải quyết multi-service transaction consistency. Outbox giải quyết dual write problem: đảm bảo DB update và message publish xảy ra atomically. Outbox thường được dùng BÊN TRONG Saga: mỗi Saga step update DB và ghi event vào outbox table trong cùng transaction → Message Relay publish event → bước tiếp theo trigger. Hai patterns bổ sung cho nhau, không thay thế nhau.

Q: Tại sao Redlock bị Martin Kleppmann phê phán?

Kleppmann chỉ ra rằng Redlock không an toàn nếu mục đích là "correctness" (chỉ một process chạy critical section). Vấn đề: GC pause, disk flush delay, clock jump có thể khiến lock TTL expire trong khi holder vẫn nghĩ lock valid → hai processes cùng "hold" lock. Giải pháp: Fencing Token — lock service cấp monotonic token, resource server reject outdated tokens. Kleppmann kết luận: Redlock phù hợp cho "efficiency" (tránh duplicate work, okay nếu đôi khi fail) nhưng không phù hợp cho "correctness" (cần ZooKeeper/etcd với fencing).

Q: Làm sao implement idempotency cho payment service?

  1. Client tạo UUID idempotency key trước khi gọi API. 2. Server nhận request → lookup key trong DB/Redis. 3. Nếu tìm thấy với status COMPLETED → return cached response ngay. 4. Nếu tìm thấy với status PROCESSING → chờ (client đang retry concurrent request). 5. Nếu không tìm thấy → INSERT key với status PROCESSING (với unique constraint để tránh race condition) → process payment → update status COMPLETED và store response → return. Quan trọng: store và return CÙNG response (kể cả error), không phải chỉ success.

🗺️ Bức tranh tổng thể

Distributed System Challenges
         │
         ├── Consistency vs Availability
         │      └── CAP / PACELC → chọn điểm phù hợp
         │          └── Consistency Models: Linear → Sequential → Causal → Eventual
         │
         ├── Data Architecture
         │      ├── CQRS: tách read/write → scale độc lập
         │      └── Event Sourcing: store events → replay → time travel
         │              └── CQRS + ES: Event Store → Projections → Read Models
         │
         ├── Cross-Service Transactions
         │      ├── 2PC: strong consistency, blocking, SPOF
         │      ├── Saga: eventual consistency, compensations
         │      │      ├── Choreography: events, loose coupling
         │      │      └── Orchestration: central coordinator, visibility
         │      └── Outbox + CDC: reliable event publishing
         │
         ├── Reliability Primitives
         │      ├── Idempotency: safe retries
         │      ├── Distributed Locking: coordination
         │      ├── Rate Limiting: protection
         │      └── Circuit Breaker + Bulkhead + Retry: resilience
         │
         └── Conflict Resolution (Eventual Consistency)
                ├── LWW, Multi-value, CRDTs
                └── Read Repair, Hinted Handoff, Anti-entropy

Tài liệu dành cho Senior Backend / Distributed Systems Engineer Interview Preparation Covers: CAP · PACELC · Consistency Models · CQRS · Event Sourcing · Saga · 2PC · Outbox · Idempotency · Distributed Locks · Rate Limiting · Circuit Breaker