Giám Sát Vận Hành và Các Mẫu Khôi Phục Dữ Liệu Sau Sự Cố Vùng
Why this matters in production
Trong vận hành thực tế sản xuất, điều tồi tệ nhất không phải là hệ thống bị lỗi, mà là hệ thống bị lỗi nhưng không ai hay biết (silent failures). Khi một vùng địa lý của Pub/Sub gặp sự cố hoặc xảy ra hiện tượng kẹt hàng đợi do chuyển vùng dự phòng, ứng dụng của bạn có thể âm thầm từ chối các yêu cầu ghi dữ liệu hoặc dừng xử lý tin nhắn mà không đưa ra cảnh báo rõ ràng nếu bạn không thiết lập hệ thống giám sát (observability) đúng cách.
Khi phát hiện ra lỗi muộn mằn sau vài giờ:
- Lượng backlog tích tụ đã vượt quá khả năng xử lý của các máy chủ hiện tại.
- Bạn không biết chính xác thời điểm lỗi xảy ra để xác định ranh giới dữ liệu bị ảnh hưởng.
- Không có quy trình khôi phục dữ liệu chuẩn hóa dẫn đến việc sửa đổi thủ công trực tiếp trên cơ sở dữ liệu production, dễ gây ra các lỗi trùng lặp hoặc mất mát dữ liệu nghiêm trọng hơn.
Việc thiết lập các Dashboard giám sát chỉ số sức khỏe của Pub/Sub và chuẩn bị sẵn các mẫu khôi phục (recovery patterns) như Seek to Timestamp hay Reprocessing là chốt chặn cuối cùng của một kỹ sư Platform/SRE để đảm bảo hệ thống có thể hồi sinh nhanh chóng sau thảm họa.
Internal Model: Các Chỉ Số Giám Sát Cốt Lõi Để Phát Hiện Lỗi Vùng
Cloud Monitoring cung cấp một loạt các chỉ số (metrics) chi tiết cho Pub/Sub. Để phát hiện sự cố vùng, ta cần tập trung vào các metrics đo lường hiệu năng của cả luồng xuất bản (Publish) và tiêu thụ (Subscribe).
graph LR
subgraph Publisher Metrics
PubErrors[topic/send_request_count - Group by Response Code]
PubLatency[topic/publish_latencies]
end
subgraph Subscriber Metrics
BacklogCount[subscription/num_undelivered_messages]
BacklogAge[subscription/oldest_unacked_message_age]
AckNack[subscription/ack_message_count / nack_message_count]
end
PubErrors --> AlertEngine[Cloud Monitoring Alerting Engine]
BacklogAge --> AlertEngine
AlertEngine --> PagerDuty[SRE On-Call Alert]1. Chỉ Số Phía Publisher (Ingress Metrics)
topic/send_request_count (Số lượng request gửi lên Topic):
- Chỉ số này cần được phân nhóm (grouped by) theo mã phản hồi (
response_code). - Dấu hiệu lỗi vùng: Xuất hiện đột biến các mã lỗi dạng
5xx(như503 Service Unavailable,504 Gateway Timeout) hoặc các mã lỗi gRPC nhưUNAVAILABLEhayDEADLINE_EXCEEDEDtại các regional endpoints cụ thể.
topic/publish_latencies (Độ trễ ghi dữ liệu):
- Đo lường thời gian thực hiện một request publish thành công.
- Dấu hiệu lỗi vùng: Độ trễ tăng vọt từ mức bình thường (~10-20ms) lên hàng trăm mili-giây hoặc chạm ngưỡng timeout của client. Điều này cho thấy Forwarder đang gặp khó khăn trong việc ghi dữ liệu đồng bộ vào các zone hoặc đang phải chuyển tiếp dữ liệu chéo vùng do Message Storage Policy.
2. Chỉ Số Phía Subscriber (Egress Metrics)
subscription/num_undelivered_messages (Số lượng tin nhắn chưa phân phối - Backlog size):
- Đo lường quy mô của hàng đợi hiện tại.
- Dấu hiệu lỗi vùng: Lượng backlog tăng vọt theo chiều thẳng đứng do Subscriber ở vùng lỗi bị sập không thể tiêu thụ tin nhắn, trong khi Publisher ở các vùng khác vẫn liên tục đẩy tin nhắn mới vào.
subscription/oldest_unacked_message_age (Tuổi của tin nhắn chưa xác nhận lớn nhất):
- Đây là chỉ số quan trọng nhất để đo lường độ trễ xử lý (processing lag) của hệ thống. Nó phản ánh khoảng thời gian (giây) tính từ lúc tin nhắn cũ nhất trong hàng đợi được xuất bản mà chưa được ACK thành công.
- Dấu hiệu lỗi vùng: Tuổi tin nhắn tăng liên tục theo đường tuyến tính. Khi region bị sập, tin nhắn cũ nằm kẹt tại vùng đó không thể được ACK, khiến chỉ số này tăng đều mỗi giây, ngay cả khi Subscriber vẫn đang xử lý các tin nhắn mới từ vùng dự phòng khác.
Recovery Patterns: Các Mẫu Khôi Phục Dữ Liệu Sau Sự Cố
Khi sự cố vùng đã được khắc phục hoặc khi bạn cần sửa chữa các dữ liệu bị lỗi logic trong quá trình failover, GCP Pub/Sub cung cấp hai cơ chế khôi phục mạnh mẽ:
1. Mẫu Khôi Phục Tua Ngược Thời Gian (Seek to Timestamp)
Tính năng Seek cho phép bạn tua ngược (replay) hoặc tua nhanh (skip) trạng thái của một Subscription đến một thời điểm cụ thể trong quá khứ hoặc tương lai.
[Thực hiện Seek to T1]
│
▼
───(T1: Tin nhắn cũ)───────(T2: Sự cố xảy ra)────────(T3: Hiện tại)───
▲ │
└─────────────────[Tua ngược trạng thái]─────────┘
(Phát lại toàn bộ từ T1 đến T3)Cơ chế hoạt động bên trong:
- Pub/Sub duy trì một bản đồ theo dõi trạng thái ACK của từng thông điệp.
- Khi bạn thực hiện lệnh Seek đến thời điểm
T1, Pub/Sub server sẽ tìm kiếm tất cả các thông điệp có nhãn xuất bản (publish time) lớn hơnT1và đặt lại trạng thái của chúng thành chưa xác nhận (unacknowledged), bất kể trước đó chúng đã được Subscriber ACK thành công hay chưa. - Ngay sau đó, Pub/Sub sẽ bắt đầu phân phối lại toàn bộ chuỗi thông điệp này cho các Subscriber đang kết nối.
Ràng buộc và Đánh đổi:
- Thời gian giữ tin nhắn (Message Retention): Bạn chỉ có thể tua ngược về quá khứ trong phạm vi thời gian giữ tin nhắn được cấu hình trên Subscription (mặc định là 7 ngày). Nếu bạn không bật tính năng
retain_acked_messagestrên Subscription, các tin nhắn đã được ACK trước đó sẽ bị xóa vĩnh viễn khỏi Colossus và bạn không thể dùng Seek để phát lại chúng được nữa. - Trùng lặp diện rộng (Massive Redelivery): Khi tua ngược về
T1, toàn bộ Subscriber sẽ nhận lại một lượng lớn dữ liệu cũ mà họ đã từng xử lý. Do đó, ứng dụng tiêu thụ bắt buộc phải có khả năng xử lý idempotent để tránh làm sai lệch dữ liệu hiện tại trong database.
2. Mẫu Xử Lý Lại Tin Nhắn Lỗi (Reprocessing via Dead Letter Topic - DLT)
Đối với các thông điệp bị lỗi logic hoặc bị hỏng cấu trúc do quá trình chuyển đổi vùng đột ngột (poison pills):
- Cấu hình Dead Letter Topic (DLT) trên Subscription để tự động cô lập các tin nhắn lỗi sau một số lần thử phân phối lại thất bại (ví dụ:
max_delivery_attempts = 5). - Khi một tin nhắn bị lỗi vượt quá số lần quy định, Pub/Sub sẽ tự động chuyển hướng nó sang một Topic phụ chuyên biệt (Dead Letter Topic) và ACK nó trên Subscription chính để giải phóng hàng đợi.
- Đội ngũ vận hành có thể viết một worker phụ để đọc từ DLT, thực hiện phân tích lỗi (forensics), sửa chữa payload nếu cần, và xuất bản ngược trở lại Topic chính để xử lý lại sau khi hệ thống đã ổn định.
Production Patterns & Implementation Guidance
1. Định Nghĩa Cloud Monitoring Alerting Policy Bằng Terraform
Để tự động phát hiện sớm sự cố vùng dựa trên tuổi thọ tin nhắn kẹt trong hàng đợi (oldest_unacked_message_age), bạn có thể cấu hình Alerting Policy bằng Terraform dưới đây. Chính sách này sẽ kích hoạt cảnh báo nếu có một tin nhắn chưa được xử lý tồn tại quá 15 phút (900 giây) trong Subscription:
resource "google_monitoring_alert_policy" "pubsub_lag_alert" {
display_name = "Pub/Sub Subscription Lag Alert - Over 15m"
combinator = "OR"
project = "my-production-project"
conditions {
display_name = "Oldest Unacked Message Age > 900s"
condition_threshold {
# Định nghĩa metric cần theo dõi
filter = "resource.type = \"pubsub_subscription\" AND metric.type = \"pubsub.googleapis.com/subscription/oldest_unacked_message_age\""
duration = "60s" # Điều kiện phải duy trì trong ít nhất 1 phút
comparison = "COMPARISON_GT"
threshold_value = 900 # Ngưỡng 900 giây (15 phút)
trigger {
count = 1
}
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_MAX"
cross_series_reducer = "REDUCE_NONE"
}
}
}
# Cấu hình kênh thông báo (Email, Slack, PagerDuty...)
notification_channels = [
"projects/my-production-project/notificationChannels/sre-team-pagerduty"
]
user_labels = {
severity = "critical"
}
}2. Script Thực Hiện Seek Để Khôi Phục Dữ Liệu Sau Sự Cố
Khi cần tua ngược luồng dữ liệu của một subscription về thời điểm trước khi vùng gặp sự cố (ví dụ sập vùng lúc 14:00 giờ UTC ngày 23/06/2026, ta muốn tua ngược về 13:55 để đảm bảo không sót tin nhắn nào):
# Thực hiện Seek to Timestamp bằng gcloud CLI
gcloud pubsub subscriptions seek my-production-subscription \
--time="2026-06-23T13:55:00Z" \
--project="my-production-project"Sau khi chạy lệnh này, bạn sẽ quan sát thấy chỉ số num_undelivered_messages trên Dashboard tăng vọt lên tương ứng với số lượng tin nhắn được hồi sinh từ thời điểm 13:55, và các Subscriber sẽ bắt đầu kéo và xử lý lại lượng dữ liệu này.