Skip to content

Tác Động Của Sự Cố Vùng (Regional Failure) Lên Pub/Sub

Why this matters in production

Trong kỹ thuật độ tin cậy hệ thống (Site Reliability Engineering - SRE), chúng ta luôn hoạt động dưới triết lý: "Mọi thứ đều có thể vỡ, và sẽ vỡ tại một thời điểm nào đó" (Werner Vogels). Mặc dù các nhà cung cấp đám mây như Google Cloud cam kết mức độ sẵn sàng cực cao cho dịch vụ Pub/Sub thông qua các bản thỏa thuận dịch vụ (SLA), thực tế lịch sử ngành điện toán đám mây đã chứng minh rằng các sự cố vùng (regional outages) do thiên tai, đứt cáp quang huyết mạch hoặc lỗi cấu hình phần mềm hệ thống diện rộng vẫn xảy ra.

Khi một region sập hoàn toàn:

  • Mọi hoạt động kết nối mạng đến các máy chủ vật lý tại region đó bị cắt đứt.
  • Nếu hệ thống của bạn không được thiết kế để nhận biết và xử lý các sự cố này, nó sẽ rơi vào trạng thái tê liệt dây chuyền (cascading failure): Publisher bị nghẽn do đầy bộ nhớ đệm (buffer overflow), Subscriber liên tục gặp lỗi timeout, và luồng dữ liệu nghiệp vụ bị đứt đoạn.
  • Khi region hồi phục, một lượng lớn dữ liệu cũ tràn về kết hợp với dữ liệu mới tạo ra một đỉnh tải (traffic spike) khổng lồ, thường được gọi là bão gửi lại (redelivery storm), có thể đánh sập các database và microservices phía sau nếu không có cơ chế chuẩn bị trước.

Internal Model: Phân Tích Cơ Chế Hoạt Động Khi Xảy Ra Lỗi Vùng

Để reason được về hệ thống khi gặp thảm họa, chúng ta cần phân biệt rõ ràng hành vi của hai mặt phẳng: Control Plane (Mặt phẳng điều khiển) và Data Plane (Mặt phẳng dữ liệu) của Pub/Sub.

mermaid
sequenceDiagram
    autonumber
    actor Publisher
    participant GlobalAPI as Pub/Sub Global Gateway
    participant RegionA as Region A (Sập vật lý)
    participant RegionB as Region B (Hoạt động)
    participant Subscriber

    Publisher->>GlobalAPI: Gửi message (Global Endpoint)
    Note over GlobalAPI: Phát hiện Region A mất liên lạc
    GlobalAPI->>RegionB: Tự động định tuyến sang Region B
    RegionB-->>GlobalAPI: Ghi thành công
    GlobalAPI-->>Publisher: Trả về HTTP 200 OK
    
    Note over Subscriber: Subscriber kéo dữ liệu từ Region B
    Subscriber->>RegionB: Pull Messages
    RegionB-->>Subscriber: Phân phối messages mới
    
    Note over RegionA: Message cũ nằm ở Region A bị kẹt!<br/>Không thể đọc/ACK cho đến khi Region A sống lại.

1. Control Plane vs Data Plane Behavior

Control Plane (Mặt phẳng điều khiển):

  • Control plane của Pub/Sub là hệ thống quản lý cấu hình: tạo, xóa, cập nhật Topic, Subscription, cấu hình IAM, v.v.
  • Hệ thống metadata này được lưu trữ phân tán toàn cầu và được nhân bản (replicated) trên nhiều vùng địa lý sử dụng cơ sở dữ liệu có tính nhất quán cao (như Google Spanner).
  • Khi một region đơn lẻ bị sập, bạn vẫn có thể thực hiện các API call để tạo hoặc xóa Topic/Subscription ở các region khác. Tuy nhiên, các lệnh thay đổi cấu hình liên quan trực tiếp đến region bị lỗi có thể bị chậm trễ hoặc trả về lỗi do hệ thống cần thời gian để đạt được đồng thuận (consensus) mới và cô lập vùng lỗi.

Data Plane (Mặt phẳng dữ liệu):

  • Data plane đảm nhận luồng lưu thông thực tế của thông điệp: Publish (xuất bản) và Pull/Push (tiêu thụ).
  • Do dữ liệu thông điệp vật lý chỉ nằm tại region được chọn khi xuất bản, data plane tại vùng bị lỗi sẽ ngừng hoạt động hoàn toàn.
  • Tuy nhiên, nhờ kiến trúc định tuyến toàn cầu qua GFE, nếu Publisher sử dụng global endpoint (pubsub.googleapis.com), Pub/Sub sẽ tự động phát hiện region bị lỗi và định tuyến các request xuất bản mới đến các region lành lặn khác (nằm trong Message Storage Policy).
  • Do đó, luồng ghi mới (ingress data plane) vẫn được duy trì chéo vùng, nhưng luồng đọc các tin nhắn cũ đã lưu tại vùng lỗi (egress data plane) sẽ bị chặn lại.

2. Số Phận Của Các Message Chưa Xác Nhận (Un-ACKed Backlog)

Điều gì xảy ra với những thông điệp đã nằm trong hàng đợi (backlog) của region bị sập?

  • Các message đã được ghi thành công vào Colossus tại region bị lỗi sẽ nằm an toàn tại đó nhờ cơ chế sao chép đa zone (zonal replication). Chúng không bị mất.
  • Tuy nhiên, chúng sẽ trở nên không khả dụng (unavailable) đối với tất cả Subscriber. Mọi request pull hoặc push liên quan đến các message này sẽ bị timeout hoặc trả về lỗi 5xx.
  • Khi region hồi phục, các message này sẽ lập tức khả dụng trở lại.

3. Cơ Chế Bão Gửi Lại (Redelivery Storm) Sau Khi Hồi Phục

Đây là một trong những hiệu ứng phụ nguy hiểm nhất của sự cố vùng. Khi một region sập và sau đó phục hồi:

  1. Hết Hạn Xác Nhận (ACK Deadline Expiry): Trong thời gian region bị sập, các message đang được xử lý dở dang bởi Subscriber sẽ hết hạn ACK deadline (do Subscriber không thể gửi request ACK về region bị lỗi, hoặc có gửi nhưng không được ghi nhận).
  2. Đánh Dấu Phân Phối Lại: Pub/Sub server coi tất cả các message chưa được ACK này là "xử lý thất bại" và đưa chúng trở lại hàng đợi để sẵn sàng phân phối lại.
  3. Hiện Tượng Bão (The Storm): Ngay khi kết nối mạng được khôi phục, Pub/Sub sẽ đẩy đồng loạt toàn bộ lượng message backlog cũ này cộng với các message mới tích tụ trong thời gian sập vùng về phía các Subscriber.
  4. Hệ Quả: Subscriber bị quá tải bộ nhớ, CPU tăng vọt 100%, kết nối đến Database bị nghẽn (connection pool exhaustion), dẫn đến sập toàn bộ hệ thống tiêu thụ.

4. Cơ Chế Khôi Phục Thứ Tự (Ordering Resumption)

Đối với các luồng dữ liệu sử dụng Ordering Keys, khi một region bị sập:

  • Luồng gửi tin nhắn của key bị lỗi sẽ bị khóa trên client (như đã phân tích ở Chương 36.02).
  • Khi region hồi phục hoặc sau khi ứng dụng gọi ResumePublish, client library sẽ thiết lập lại trạng thái kết nối và bắt đầu gửi các thông điệp tiếp theo.
  • Pub/Sub sẽ tiếp tục duy trì thứ tự cho các thông điệp mới gửi sau đó, nhưng ứng dụng cần lưu ý rằng sự đứt gãy giữa chuỗi tin nhắn cũ (bị kẹt ở region lỗi) và chuỗi tin nhắn mới (gửi sau khi phục hồi) có thể đã xảy ra ở tầng Subscriber nếu Subscriber đọc từ nhiều phân mảnh ở các thời điểm khác nhau.

Constraints, Trade-offs & Failure Modes

1. Giới Hạn Của Thỏa Thuận Dịch Vụ (SLA vs Actual Outage)

Pub/Sub cam kết SLA hàng tháng là 99.9% đến 99.99%. Tuy nhiên, bạn cần hiểu định nghĩa kỹ thuật của SLA:

  • SLA được tính toán dựa trên tỷ lệ lỗi trung bình trên toàn cầu hoặc trong một khoảng thời gian dài (thường là một tháng).
  • Một sự cố sập hoàn toàn một region trong vòng 30 phút có thể chỉ làm giảm nhẹ con số phần trăm SLA của cả tháng, nhưng đối với doanh nghiệp của bạn, 30 phút ngừng hoạt động vào giờ cao điểm có thể gây thiệt hại hàng triệu USD.
  • Do đó, bạn không thể coi SLA là tấm lá chắn kỹ thuật. Bạn phải thiết kế kiến trúc chịu lỗi chủ động ở tầng ứng dụng.

2. Sự Khác Biệt Giữa Lỗi Timeout và Lỗi Xác Nhận Ghi (Ack Failures)

Khi xảy ra lỗi vùng, Publisher có thể nhận được các mã lỗi khác nhau từ client library:

  • DEADLINE_EXCEEDED (Timeout): Client gửi request ghi nhưng không nhận được phản hồi trong khoảng thời gian quy định. Trong trường hợp này, trạng thái của message là không xác định (undetermined). Message có thể đã được ghi thành công vào Storage Node nhưng kết nối mạng bị đứt trước khi phản hồi kịp truyền về. Nếu Publisher thử lại (retry), message đó sẽ bị nhân đôi (duplicate) trong hệ thống.
  • UNAVAILABLE (503): Region đã hoàn toàn mất khả năng phục vụ. Client có thể an tâm định tuyến request sang region khác vì chắc chắn message chưa được ghi vào region cũ.

Production Patterns & Operational Runbooks

Để vận hành an toàn qua các sự cố vùng của Pub/Sub, các đội ngũ vận hành hệ thống (Operations/SRE) cần chuẩn bị sẵn các kịch bản ứng phó (runbooks) sau:

1. Runbook: Xử Lý Tải Tăng Vọt (Backlog Buildup) Sau Sự Cố

Khi một region hồi phục và chuẩn bị xả bão tin nhắn, hãy thực hiện các bước sau để bảo vệ hệ thống tiêu thụ:

[Phục Hồi Kết Nối]


1. Tạm thời scale-down Subscriber Pods (hoặc stop consumers)


2. Tăng ACK Deadline của Subscription lên mức tối đa (600s)


3. Cấu hình Flow Control trên Subscriber (Giới hạn max outstanding messages)


4. Scale-up Subscriber Pods dần dần để tiêu thụ từ từ (Rate Limiting)
  1. Bước 1: Tạm thời hạ tải hệ thống tiêu thụ bằng cách scale-down số lượng bản sao (replicas) của Subscriber Pods trong Kubernetes xuống mức tối thiểu (hoặc tắt tạm thời ứng dụng tiêu thụ).
  2. Bước 2: Tăng thời gian ACK deadline của Subscription lên mức tối đa cho phép (600 giây). Điều này giúp giảm thiểu việc Pub/Sub liên tục gửi lại các message đang được xử lý chậm do quá tải.
  3. Bước 3: Cấu hình giới hạn luồng (Flow Control) trên cấu hình client của Subscriber (ví dụ đặt MaxOutstandingMessages xuống mức thấp, khoảng 10-50 messages per instance thay vì mặc định hàng ngàn).
  4. Bước 4: Bật lại Subscriber và tăng dần số lượng replicas để tiêu thụ từ từ lượng backlog tích tụ, tránh tạo ra đỉnh tải đột ngột lên Database phía sau.

2. Chiến Lược Tua Ngược Thời Gian (Seeking) Để Bỏ Qua Backlog Lỗi

Nếu lượng tin nhắn kẹt quá lớn hoặc chứa các dữ liệu đã hết giá trị thời gian (stale data) và bạn không muốn xử lý chúng nữa để ưu tiên cho các tin nhắn mới:

  • Pub/Sub hỗ trợ tính năng Seek to Timestamp. Bạn có thể tua nhanh trạng thái của Subscription đến thời điểm hiện tại.
  • Lệnh này sẽ tự động đánh dấu xác nhận (ACK) cho toàn bộ các message được xuất bản trước mốc thời gian chỉ định, lập tức xóa sạch backlog và giải phóng hàng đợi để Subscriber chỉ tập trung xử lý các tin nhắn mới phát sinh.
bash
# Tua nhanh Subscription đến thời điểm hiện tại để bỏ qua toàn bộ backlog cũ
gcloud pubsub subscriptions seek my-subscription \
    --time=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
    --project=my-production-project

References