Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là DevOps engineer trực ca đêm. 2 giờ sáng, điện thoại rung liên hồi. Bạn choàng dậy, mở laptop, tim đập thình thịch — chỉ để phát hiện đó là cảnh báo "CPU đạt 82%" trên một server batch job đang chạy đúng như thiết kế. Bạn tắt cảnh báo, nằm xuống, và 40 phút sau lại một cái nữa. Đến sáng, bạn kiệt sức, cáu kỉnh, và tệ hơn: bạn bắt đầu bỏ qua mọi cảnh báo — kể cả cái thực sự quan trọng.
Đây chính là "alert fatigue" (mệt mỏi vì cảnh báo), và nó là kẻ giết chết độ tin cậy của hệ thống theo cách âm thầm nhất. Một hệ thống monitoring hoàn hảo với hàng nghìn metric đẹp đẽ trở nên vô dụng nếu cảnh báo của nó khiến con người mất niềm tin. Nghịch lý là: càng nhiều cảnh báo, hệ thống thường càng kém an toàn, bởi vì tín hiệu quan trọng bị chôn vùi trong đống nhiễu.
Ở các bài trước, chúng ta đã học cách thu thập metrics (Prometheus), vẽ dashboard (Grafana), và đặt mục tiêu độ tin cậy (SLI/SLO). Bài này giải quyết câu hỏi tiếp theo và cực kỳ thực tế: khi nào thì đánh thức một con người dậy? Alerting tốt không phải là kỹ thuật cấu hình — nó là một triết lý về sự tôn trọng thời gian và sự tỉnh táo của đội ngũ. Viết đúng, đội của bạn ngủ ngon và phản ứng nhanh khi cần. Viết sai, bạn đốt cháy con người trước khi hệ thống kịp sập.
Khái niệm cốt lõi
Nguyên tắc vàng: chỉ alert khi cần hành động của con người NGAY
Đây là câu thần chú bạn phải khắc cốt ghi tâm: mỗi cảnh báo gửi đến con người phải tương ứng với một hành động cần thực hiện ngay, mà nếu không làm sẽ gây hậu quả cho người dùng. Nếu một cảnh báo bật lên mà phản ứng hợp lý là "à, để mai xem", thì đó không phải cảnh báo — đó là một ticket, hoặc một dashboard cần review, hoặc chỉ đơn giản là nhiễu cần xóa.
Hãy phân biệt rõ ví dụ kinh điển:
- Cảnh báo tồi: "CPU > 80%". Hành động là gì? Có thể chẳng cần gì. CPU cao có thể hoàn toàn bình thường — hệ thống đang làm việc hiệu quả. Đây là cảnh báo dựa trên nguyên nhân (cause-based) mà không quan tâm đến hậu quả.
- Cảnh báo tốt: "Tỷ lệ lỗi 5xx > 5% trong 5 phút liên tục trên API checkout". Cái này nói lên rằng người dùng đang thực sự không thanh toán được. Nó dựa trên triệu chứng (symptom-based) — thứ mà khách hàng cảm nhận.
Symptom-based vs cause-based alerting
Trường phái Google SRE khuyến nghị mạnh mẽ: alert dựa trên triệu chứng, không dựa trên nguyên nhân. Lý do rất đơn giản — có vô số nguyên nhân có thể khiến hệ thống hỏng, nhưng chỉ có một số ít triệu chứng mà người dùng thực sự cảm nhận: chậm, lỗi, không truy cập được.
Nếu bạn alert vào từng nguyên nhân (disk đầy, connection pool cạn, memory cao...), bạn sẽ có một rừng cảnh báo mà đa số là false positive. Thay vào đó, hãy alert khi triệu chứng xuất hiện (người dùng gặp lỗi), rồi dùng dashboard và log để tìm nguyên nhân sau. Nguyên nhân đi vào dashboard để debug; triệu chứng đi vào cảnh báo để đánh thức người.
Bốn tín hiệu vàng (Four Golden Signals)
Google đề xuất bốn nhóm tín hiệu đáng để cảnh báo cho hầu hết dịch vụ:
- Latency — độ trễ. Đặc biệt chú ý latency của các request lỗi, đừng gộp chung với request thành công.
- Traffic — lưu lượng. Ví dụ requests/giây.
- Errors — tỷ lệ lỗi.
- Saturation — mức độ bão hòa tài nguyên (còn bao nhiêu "room").
Ba mức độ ưu tiên
Không phải mọi thứ đều đáng gọi điện lúc 2 giờ sáng. Hãy phân tầng:
- Page (đánh thức ngay): ảnh hưởng người dùng đang diễn ra, cần người can thiệp trong vài phút. Gửi qua điện thoại/PagerDuty.
- Ticket (xử lý trong giờ làm việc): vấn đề quan trọng nhưng không khẩn cấp, ví dụ disk sẽ đầy trong 4 ngày nữa. Tạo ticket, không gọi điện.
- Log/Info (chỉ ghi lại): thông tin để tham khảo, không gửi cho ai cả.
Các thuộc tính của một cảnh báo tốt
Một alert rule chất lượng cần: actionable (có hành động rõ ràng), relevant (đúng người nhận), có runbook đính kèm (hướng dẫn xử lý), có ngưỡng dựa trên khoảng thời gian (for: 5m) để tránh nhiễu tức thời, và có ngữ cảnh đầy đủ trong nội dung (service nào, môi trường nào, mức độ nghiêm trọng, link tới dashboard/runbook).
Tình huống thực tế
Ví dụ 1: Ví điện tử ở TP.HCM và cơn ác mộng "CPU > 70%"
Một công ty fintech ví điện tử tại TP.HCM (gọi là VíNhanh) có đội SRE 5 người. Ban đầu, để "an toàn", họ cấu hình cảnh báo cho mọi thứ: CPU > 70%, RAM > 75%, disk I/O cao, mỗi lần một pod restart... Kết quả sau 2 tháng: trung bình 340 cảnh báo/tuần, trong đó khoảng 6 cái là sự cố thật.
Hậu quả đến đúng vào một tối thứ Sáu cao điểm. Hệ thống thanh toán QR bị nghẽn thật — latency thanh toán tăng vọt lên 8 giây. Nhưng cảnh báo đó lọt thỏm giữa 22 cảnh báo "CPU cao" cùng lúc (vì traffic tăng khiến CPU cũng tăng). Engineer trực ca đã quen tay "ack rồi bỏ qua", nên phải mất 25 phút mới nhận ra đây là sự cố thật. Trong 25 phút đó, hàng nghìn giao dịch thất bại.
Bài học: Sau sự cố, đội VíNhanh làm một cuộc "thanh lọc cảnh báo". Họ xóa toàn bộ alert dựa trên tài nguyên đơn thuần, thay bằng đúng bốn tín hiệu vàng gắn với SLO: tỷ lệ giao dịch thành công < 99.5% trong 5 phút, và latency p95 của flow thanh toán > 3 giây. Số cảnh báo tuần giảm từ 340 xuống còn khoảng 4-8. Quan trọng hơn: mỗi cảnh báo còn lại đều đáng tin, nên đội phản ứng ngay lập tức thay vì hoài nghi.
Ví dụ 2: Sàn thương mại điện tử và alert thiếu ngữ cảnh
Một sàn TMĐT khu vực Đông Nam Á có cảnh báo bật lên lúc 3 giờ sáng với đúng một dòng: HighErrorRate firing. Engineer trực ca mở máy, không biết service nào lỗi, môi trường production hay staging, lỗi nghiêm trọng đến đâu, phải làm gì. Anh mất 20 phút chỉ để lần mò từ Grafana sang log để hiểu chuyện gì đang xảy ra — hóa ra chỉ là môi trường staging đang chạy test tải.
Bài học: Một cảnh báo không có ngữ cảnh cũng tệ như không có cảnh báo. Sau đó họ chuẩn hóa mọi nội dung cảnh báo phải chứa: tên service, môi trường (loại trừ staging khỏi kênh page), giá trị hiện tại vs ngưỡng, mức severity, và link trực tiếp đến runbook + dashboard. Riêng việc lọc bỏ môi trường không phải production khỏi kênh đánh thức người đã cắt được 30% cảnh báo đêm.
Ví dụ 3: Startup SaaS và bài toán "flapping"
Một startup SaaS B2B ở Hà Nội gặp hiện tượng cảnh báo "nhấp nháy" (flapping): dịch vụ dao động quanh ngưỡng, khiến cảnh báo bật-tắt-bật-tắt liên tục — 15 lần trong một giờ. Điện thoại engineer rung như trống trận dù thực tế hệ thống chỉ chạm ngưỡng thoáng qua.
Bài học: Họ áp dụng ba kỹ thuật: (1) thêm điều kiện thời gian for: 5m để cảnh báo chỉ bật khi tình trạng kéo dài liên tục 5 phút; (2) dùng ngưỡng khác nhau để bật và tắt cảnh báo (hysteresis); và (3) gom nhóm (grouping) các cảnh báo liên quan thành một thông báo duy nhất qua Alertmanager. Số lần rung điện thoại giảm hơn 90%, và điều quan trọng là không bỏ sót sự cố thật nào.
Hướng dẫn từng bước
Đây là quy trình thực dụng để xây dựng hệ thống alerting lành mạnh:
Bước 1 — Bắt đầu từ SLO, không phải từ metric. Hỏi: người dùng cảm nhận điều gì khi hệ thống hỏng? Từ đó xác định SLI cần bảo vệ (tỷ lệ thành công, latency). Đây là nền tảng cho mọi cảnh báo có ý nghĩa.
Bước 2 — Với mỗi cảnh báo dự định, đặt câu hỏi kiểm định. "Nếu cảnh báo này bật lúc 3 giờ sáng, tôi có cần dậy làm gì ngay không?" Nếu câu trả lời là không, hạ nó xuống mức ticket hoặc xóa.
Bước 3 — Viết alert rule dựa trên triệu chứng với điều kiện thời gian. Ví dụ trong Prometheus:
groups:
- name: checkout-slo
rules:
- alert: CheckoutHighErrorRate
expr: |
sum(rate(http_requests_total{job="checkout",code=~"5.."}[5m]))
/
sum(rate(http_requests_total{job="checkout"}[5m])) > 0.05
for: 5m
labels:
severity: page
annotations:
summary: "Checkout error rate {{ $value | humanizePercentage }} (>5%)"
runbook: "https://wiki.company.vn/runbooks/checkout-errors"
dashboard: "https://grafana.company.vn/d/checkout"
Lưu ý: for: 5m chống nhiễu tức thời, severity để định tuyến, annotations cung cấp ngữ cảnh và runbook.
Bước 4 — Định tuyến bằng Alertmanager theo severity. Cảnh báo page đi PagerDuty/điện thoại; ticket đi Jira/email; info chỉ vào Slack. Cấu hình group_by, group_wait, và repeat_interval để gom nhóm và tránh spam.
Bước 5 — Đính kèm runbook cho MỌI cảnh báo page. Runbook trả lời: cảnh báo này nghĩa là gì, kiểm tra ở đâu, các bước xử lý phổ biến, khi nào leo thang. Không có runbook, cảnh báo lúc 3 giờ sáng biến thành cuộc điều tra từ con số 0.
Bước 6 — Định tuyến đúng người (relevant). Cảnh báo của service nào đến đội sở hữu service đó, không broadcast cho tất cả. Dùng label để routing.
Bước 7 — Đo lường và lặp lại. Định kỳ review: cảnh báo nào bật nhiều nhất, cái nào actionable, cái nào là nhiễu. Đây là vòng lặp cải tiến liên tục, không phải cấu hình một lần rồi quên.
Lỗi thường gặp & mẹo
Lỗi 1 — Alert cho mọi metric "cho chắc". Đây là con đường nhanh nhất đến alert fatigue. Mỗi cảnh báo thêm vào phải "trả giá" bằng sự tin cậy của toàn hệ thống. Ít mà tinh, đừng nhiều mà nhiễu.
Lỗi 2 — Alert dựa trên nguyên nhân thay vì triệu chứng. "Disk 90%" không đáng đánh thức người nếu người dùng vẫn dùng tốt; hãy để nó ở mức ticket. Chỉ khi disk đầy gây lỗi thực sự mới page.
Lỗi 3 — Không có điều kiện thời gian. Thiếu for: khiến mọi gai nhiễu (spike) tức thời đều bật cảnh báo. Gần như mọi alert page nên có ngưỡng thời gian.
Lỗi 4 — Nội dung cảnh báo trống rỗng. SomethingBroke firing là ác mộng. Luôn kèm: service, môi trường, giá trị hiện tại, severity, link runbook + dashboard.
Lỗi 5 — Không lọc môi trường non-production. Đừng bao giờ để cảnh báo staging/dev đánh thức người trực ca production.
Lỗi 6 — Ngưỡng tĩnh cho tải biến thiên. Với dịch vụ có tính mùa vụ (traffic ngày/đêm khác nhau), ngưỡng tĩnh gây false positive. Cân nhắc alert theo tỷ lệ (error rate) thay vì con số tuyệt đối, hoặc burn-rate.
Mẹo hay:
- Áp dụng multi-window burn-rate alerting của Google SRE: kết hợp cửa sổ ngắn (bắt sự cố nhanh) và cửa sổ dài (giảm false positive).
- Đặt quy tắc "mọi cảnh báo page phải có runbook" như một tiêu chuẩn bắt buộc khi review.
- Định kỳ chạy "alert audit" hàng quý: cảnh báo nào chưa từng bật trong 90 ngày có thể đã lỗi thời; cảnh báo bật nhiều mà không ai làm gì cần bị hạ cấp.
- Dùng silence/maintenance window khi bảo trì có kế hoạch để không tạo nhiễu.
Bài tập thực hành
- Kiểm toán cảnh báo hiện có. Lấy danh sách toàn bộ alert rule của một dịch vụ bạn đang vận hành (hoặc một dự án mẫu). Với mỗi cái, trả lời câu hỏi: "Nếu bật lúc 3 giờ sáng, tôi cần làm gì ngay?" Phân loại từng cảnh báo vào ba nhóm: page / ticket / xóa. Đếm tỷ lệ actionable.
- Viết lại một cảnh báo cause-based thành symptom-based. Lấy cảnh báo "CPU > 80%" hoặc "Memory > 85%", chuyển nó thành một cảnh báo dựa trên triệu chứng gắn với trải nghiệm người dùng (ví dụ error rate hoặc latency p95 vượt SLO). Viết đầy đủ rule Prometheus có
for:vàannotations.
- Thiết kế nội dung cảnh báo chuẩn. Soạn một template annotation gồm: summary có giá trị động, môi trường, severity, link runbook, link dashboard. So sánh với cảnh báo một-dòng và tự đánh giá thời gian phản ứng tiết kiệm được.
- (Nâng cao) Cấu hình routing trong Alertmanager. Viết cấu hình định tuyến
page→ một receiver,ticket→ receiver khác, và loại trừ hoàn toàn môi trường staging khỏi kênh page. Thêmgroup_byđể gom nhóm cảnh báo liên quan.
Tóm tắt
Alerting tốt không phải là cấu hình được nhiều cảnh báo — mà là kỷ luật gửi ít cảnh báo nhưng mỗi cảnh báo đều đáng tin và đáng hành động. Hãy ghi nhớ những nguyên tắc cốt lõi:
- Chỉ đánh thức con người khi cần hành động ngay và có hậu quả cho người dùng nếu không làm.
- Alert dựa trên triệu chứng (symptom), không dựa trên nguyên nhân (cause) — người dùng cảm nhận điều gì thì cảnh báo điều đó; nguyên nhân để dashboard debug.
- Xoay quanh bốn tín hiệu vàng (latency, traffic, errors, saturation) và tốt nhất gắn với SLO/error budget burn-rate.
- Phân tầng ba mức: page / ticket / info — không phải mọi thứ đều đáng gọi điện lúc 2 giờ sáng.
- Mọi cảnh báo phải: actionable, relevant, có ngữ cảnh đầy đủ, có runbook, và có điều kiện thời gian
for:để chống nhiễu. - Kẻ thù lớn nhất là alert fatigue — càng nhiều nhiễu, con người càng mất niềm tin, và tín hiệu thật càng dễ bị bỏ lỡ.