High Availability: SPOF, failover, DR và quan sát hệ thống

4 câu hỏi~35 phútTừ khóa: SPOF, redundancy, failover, active-passive, active-active, liveness, readiness, availability zone, DR, RTO, RPO, logs, metrics, traces, p95, p99, alert fatigue

Tiếp theo: High Availability cho shop-app.

shop-app giờ có gateway, LB, nhiều instance, Redis, DB. Bài này hỏi một câu duy nhất cho mọi box: "Box này chết thì sao?"

1. Bài toán

         Clients
            │
       API Gateway
            │
      Load Balancer
       /    |    \
      A1    A2    A3      A1 💀 → không sao, LB chuyển sang A2/A3
       \    |    /
          Redis
            │
         Database 💀      → A1, A2, A3 đều lỗi. 100 instance cũng vô dụng.

2. Vấn đề: Single Point of Failure

SPOF là thành phần mà khi nó chết thì cả hệ thống, hoặc một chức năng quan trọng, ngừng hoạt động. 1 LB, 1 gateway, 1 Redis, 1 DB, 1 Kafka broker đều có thể là SPOF. Và còn SPOF ẩn: 3 instance nhưng cùng nằm trên một máy vật lý → máy chết là cả 3 chết.

3. Giải pháp

Redundancy: có thành phần dự phòng (A1/A2/A3, Primary + Replica, Gateway ×3).

Failover: chuyển sang thành phần dự phòng khi cần. Có DB2 mà app vẫn trỏ vào DB1 đã chết thì DB2 vô ích. Cần: phát hiện DB1 chết → promote DB2 → chuyển traffic.

Redundancy = có đồ dự phòng
Failover   = biết chuyển sang đồ dự phòng

Active-passive vs active-active:

Active-passive:  Primary (nhận traffic) ── replicate ──► Standby (chờ)
                 Primary chết → promote Standby (mất vài giây–phút)

Active-active:   Node A ◄── traffic ──► Node B   (cùng phục vụ)
                 A chết → B gánh hết (phải đủ capacity dư, khó với write)

Health check: process còn sống chưa chắc phục vụ được (connection pool cạn, cache chưa load). Tách 2 loại:

Failure domain / Availability Zone: rải instance ra nhiều AZ trong region; Zone A chết, B và C vẫn phục vụ.

Disaster Recovery: cả region chết → backup/restore, replication sang region B. Hai con số:

4. Code từng bước: health check trong Spring Boot

Bước 1: dependency spring-boot-starter-actuator (và micrometer-registry-prometheus cho metrics).

Bước 2: config probe. Readiness gồm DB; liveness không gồm DB (DB chết mà restart hết app thì chỉ làm tệ hơn).

management:
  endpoint:
    health:
      probes:
        enabled: true
      group:
        readiness:
          include: readinessState, db, redis
        liveness:
          include: livenessState
  endpoints:
    web:
      exposure:
        include: health, prometheus

Bước 3: Kubernetes dùng probe.

livenessProbe:
  httpGet: { path: /actuator/health/liveness, port: 8080 }
  periodSeconds: 10
readinessProbe:
  httpGet: { path: /actuator/health/readiness, port: 8080 }
  periodSeconds: 5
topologySpreadConstraints:              # rải pod qua nhiều zone
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway
    labelSelector: { matchLabels: { app: order-service } }

Bước 4: test.

curl localhost:8080/actuator/health/readiness    # {"status":"UP"}
# tắt DB
curl localhost:8080/actuator/health/readiness    # {"status":"OUT_OF_SERVICE"} → LB bỏ instance
curl localhost:8080/actuator/health/liveness     # vẫn UP → không bị restart vô ích

5. Cách hoạt động: biết hệ thống đang ra sao (observability)

HA không chỉ là dự phòng; phải phát hiện được lỗi. User báo "checkout mất 8 giây". Log mỗi service đều có, nhưng 10,000 req/s thì log nào của request đó?

METRICS  "Có gì đó sai"       Payment error rate 0.1% → 15% 🔥
   ↓
TRACES   "Sai ở đâu"          Order 50ms → Payment 8s → Bank 7.8s 🔥
   ↓
LOGS     "Chính xác chuyện gì" [traceId=abc123] Bank returned 503, timeout

6. So sánh

Khái niệmMục tiêuVí dụ
High AvailabilityGiảm downtime, có thể gián đoạn ngắnPrimary chết, 10 giây failover rồi chạy lại
Fault ToleranceLỗi xảy ra mà gần như không gián đoạnNode1 chết, Node2/Node3 gánh, user không thấy
Disaster RecoveryPhục hồi sau thảm họa lớn (cả region)Restore từ backup sang region B, theo RTO/RPO
Active-passiveActive-active
FailoverCó khoảng gián đoạnGần như tức thì
Chi phíStandby ngồi khôngDùng hết tài nguyên, phải dư capacity
Độ khóDễ hơn, hợp DB writeKhó với write (xung đột dữ liệu)
Health checkMonitoring
HỏiInstance này nhận traffic được không?Hệ thống đang chạy thế nào?
Ai dùngLB, KubernetesCon người, dashboard, alert

7. Khi nào nên / không nên

High availability với fault tolerance khác nhau thật không? Hay chỉ là hai cách gọi của cùng một thứ?

Hai từ hay được dùng gần nhau, nhưng để phỏng vấn nên phân biệt theo mục tiêu:

HA              : failure → gián đoạn ngắn → failover → chạy lại
                  (minimize downtime)
Fault tolerance : failure → hệ thống tiếp tục chạy, user hầu như không thấy
                  (no meaningful interruption)

Ví dụ: PostgreSQL primary chết, mất 10–30 giây để promote replica → HA. Ba app instance stateless sau LB, một cái chết, request tiếp theo vào cái còn lại → gần với fault tolerance. Không nên nói mọi hệ thống HA đều fault tolerant; fault tolerance thường đắt hơn nhiều.

Load balancer đã có health check rồi, vậy mình còn cần monitoring và alert làm gì nữa?

Cần, vì hai thứ trả lời hai câu hỏi khác nhau. Health check tự động loại một instance hỏng. Nhưng nếu cả Payment chậm vì Bank chậm, mọi instance vẫn "healthy" mà p95 checkout tăng từ 300 ms lên 8 s. Health check không thấy; metrics và alert mới thấy.

Bank chậm
  → Tomcat threads 190/200 🔥   (metrics)
  → p95 checkout 8s 🔥           (alert)
  → circuit breaker OPEN         (metrics)
  → trace abc123: Bank 7.8s      (trace)
  → log: Bank timeout after 2s   (log)

Observability giúp bạn nhìn thấy cascading failure đang hình thành trước khi cả hệ thống sập.

Phỏng vấn hỏi "làm sao tăng availability" và "monitor microservices thế nào" thì trả lời sao?

Q1. How would you improve the availability of a system?

🇻🇳 Tiếng Việt:

Đầu tiên em tìm các single point of failure. Với thành phần quan trọng, em thêm redundancy và cơ chế failover: app stateless chạy nhiều instance sau load balancer có health check liveness và readiness, database có replica và failover tự động. Em rải instance qua nhiều availability zone để một máy hay một zone chết không kéo sập hệ thống. Với thảm họa lớn hơn, em dùng backup và phục hồi cross-region, đặt RTO và RPO theo yêu cầu business.

🇬🇧 English:

First I identify single points of failure. For critical components I add redundancy and failover: stateless application instances behind a load balancer with liveness and readiness checks, and a database with replicas and automatic failover. I spread instances across availability zones so a single machine or zone failure doesn't take the system down. For larger disasters I use backups and cross-region recovery, with RTO and RPO defined by business requirements.

Q2. RTO và RPO là gì?

🇻🇳 Tiếng Việt:

RTO là thời gian tối đa chấp nhận để hệ thống phục hồi sau sự cố. RPO là lượng dữ liệu tối đa chấp nhận mất, tính bằng thời gian, ví dụ backup mỗi 5 phút thì RPO khoảng 5 phút. RTO và RPO càng nhỏ thì giải pháp càng đắt, như replication liên tục hay active-active.

🇬🇧 English:

RTO is the maximum acceptable time to restore the service after an incident. RPO is the maximum acceptable data loss measured in time; for example, backups every 5 minutes give an RPO of about 5 minutes. The smaller the RTO and RPO, the more expensive the solution, such as continuous replication or active-active.

Q3. How would you monitor a microservices system?

🇻🇳 Tiếng Việt:

Em dùng metrics, logs và distributed tracing. Metrics theo dõi request rate, error rate, latency theo percentile p95, p99, cùng tài nguyên như thread pool, DB pool, Kafka lag, có dashboard và alert theo SLO, tránh alert vụn gây alert fatigue. Logs có cấu trúc, chứa trace ID. Tracing propagate trace ID qua HTTP và message để thấy request chậm ở service nào.

🇬🇧 English:

I use metrics, logs and distributed tracing. Metrics cover request rate, error rate and latency percentiles such as p95 and p99, plus resources like thread pools, DB pools and Kafka lag, with dashboards and SLO-based alerts, avoiding noisy alerts that cause alert fatigue. Logs are structured and include the trace ID. Tracing propagates the trace ID across HTTP calls and messages so we can see which service makes a request slow.

Cách nhớ ngắn gọn


Tự kiểm tra

Có 2 DB nhưng app vẫn lỗi khi DB1 chết. Thiếu gì?

Thiếu failover: phát hiện lỗi, promote DB2, chuyển kết nối sang DB2. Redundancy thôi chưa đủ.

Vì sao không đưa DB vào liveness probe?

DB chết thì mọi pod fail liveness và bị restart liên tục, không giúp gì mà còn tệ hơn. DB nên thuộc readiness.

Backup 09:55, sự cố 10:00, phục hồi xong 10:30. RTO và RPO thực tế?

RTO ≈ 30 phút (thời gian phục hồi), RPO ≈ 5 phút (dữ liệu mất).

Vì sao nhìn p99 thay vì average latency?

Average che giấu tail latency; 1% request rất chậm vẫn là hàng nghìn user mỗi ngày.

Alert fatigue là gì, tránh thế nào?

Quá nhiều alert vô nghĩa khiến người trực bỏ qua alert. Chỉ alert khi actionable, theo triệu chứng user thấy (SLO), có ngưỡng thời gian.