Thiết kế alert pipeline tránh alert fatigue: từ threshold cứng đến anomaly detection
Hệ thống alert đặt threshold quá nhạy sẽ gửi hàng chục cảnh báo mỗi ngày — team dần bỏ qua, và alert thực sự bị chìm vào noise. Alert đặt quá cao thì phát hiện sự cố khi đã quá muộn. Thiết kế alert pipeline ba tầng: static threshold, dynamic baseline và anomaly detection, kết hợp với routing và escalation policy để cảnh báo đến đúng người vào đúng thời điểm.
Một hệ thống monitoring tốt không phải là hệ thống có nhiều alert nhất — mà là hệ thống phát hiện đúng vấn đề vào đúng thời điểm, và gửi thông báo đến đúng người. Alert fatigue xảy ra khi tỷ lệ signal-to-noise quá thấp: team nhận quá nhiều cảnh báo không quan trọng, dần học cách bỏ qua — và khi incident thực sự xảy ra, nó bị chìm vào cùng luồng noise đó.
Hai failure mode đối lập nhau trong thiết kế alert: threshold quá nhạy (quá nhiều false positive) và threshold quá cao (bỏ sót sự cố thực). Cả hai đều tệ — và không có một con số threshold cố định nào đúng cho mọi bối cảnh. Giải pháp là thiết kế alert theo nhiều tầng, mỗi tầng phù hợp với một loại bất thường khác nhau.
Tại sao threshold cứng không đủ
Threshold cứng — ví dụ "alert khi CPU > 80%" — là điểm khởi đầu hợp lý, nhưng không phản ánh được ngữ cảnh. CPU 80% lúc 3 giờ sáng và CPU 80% lúc 2 giờ chiều có ý nghĩa rất khác nhau trong một hệ thống có traffic theo giờ. Cùng một giá trị metric có thể là bình thường trong peak và bất thường ngoài giờ cao điểm:
- Ngày trong tuần vs cuối tuần: traffic pattern của hầu hết hệ thống B2B thay đổi đáng kể — threshold cứng đặt cho peak weekday sẽ bị vi phạm liên tục trong off-hours
- Seasonality: hệ thống retail có spike theo ngày lễ, hệ thống IoT nông nghiệp có pattern theo mùa. Threshold không adapt với seasonality sẽ false-positive vào mọi peak cycle
- Rate of change: metric tăng chậm từ 60% lên 85% trong 6 tiếng khác với metric tăng đột ngột từ 20% lên 85% trong 5 phút. Cả hai vi phạm cùng threshold nhưng chỉ cái sau cần alert khẩn cấp
Threshold cứng vẫn cần thiết cho absolute limit — disk full là disk full dù là giờ nào. Nhưng đặt toàn bộ alert system dựa vào threshold cứng sẽ dẫn đến alert fatigue hoặc bỏ sót sự cố, không có điểm giữa.
Ba tầng alert
Alert pipeline hiệu quả phân tầng theo loại bất thường và độ trễ phát hiện. Ba tầng phối hợp bổ sung nhau thay vì thay thế nhau:
- Tầng 1 — Static threshold: nhanh nhất và đơn giản nhất. Dùng cho giới hạn tuyệt đối không phụ thuộc ngữ cảnh: disk usage > 90%, service không response (health check fail), memory OOM, queue depth > giới hạn cứng. Alert tầng 1 luôn là Priority 1 — cần xử lý ngay dù bất kỳ giờ nào
- Tầng 2 — Dynamic baseline: tính rolling mean và rolling std của metric trên cửa sổ thời gian (7 ngày để capture cả weekly seasonality). Alert khi giá trị lệch khỏi mean ± N×std trong ngữ cảnh thời điểm tương ứng — so sánh thứ Ba 2pm với baseline thứ Ba 2pm của 4 tuần trước, không phải baseline tổng thể. Bắt được bất thường có seasonality mà threshold cứng bỏ sót
- Tầng 3 — Anomaly detection: phát hiện pattern bất thường phức tạp hơn mà không thể mô tả bằng threshold hay deviation đơn giản. Isolation Forest cho univariate outlier, DBSCAN cho multivariate clustering, hoặc model dự báo (Prophet, SARIMA) để alert khi actual diverge khỏi forecast vượt ngưỡng cho phép. Tầng này có độ trễ cao hơn nhưng false positive thấp hơn nhiều
Alert routing và escalation policy
Ngay cả khi alert chính xác, nó vô dụng nếu đến sai người hoặc sai kênh. Routing và escalation policy là phần thường bị thiết kế qua loa nhất:
- Phân loại severity trước khi route: P1 (hệ thống down hoặc data loss imminent) → PagerDuty on-call ngay lập tức, bất kể giờ nào. P2 (degraded nhưng vẫn serve) → Slack alert channel, không wake-up on-call. P3 (warning, cần theo dõi) → daily digest hoặc dashboard, không interrupt
- De-duplication: cùng một root cause thường kích hoạt nhiều alert khác nhau — ví dụ DB slow query gây API timeout gây error rate tăng. Alert mà không group và de-duplicate sẽ flood on-call với hàng chục alert cho một sự cố đơn. Dùng correlation window (5–15 phút) để group alert có liên quan
- Escalation timeout: nếu P1 alert không được acknowledge trong 5 phút, escalate lên on-call tiếp theo trong rotation. Tránh tình trạng alert bị bỏ qua vì on-call đang ngủ hoặc không nghe điện thoại
- Inhibition rule: khi alert tầng cao đã fired, suppress alert tầng thấp hơn liên quan — tránh Slack bị flood bởi symptom alert khi root cause alert đã được gửi
Feedback loop: từ incident đến threshold tốt hơn
Alert pipeline không nên là hệ thống "set and forget" — đây chính là lý do loop domain tồn tại. Mỗi incident là cơ hội để cải thiện alert quality:
- Alert này có phát hiện sự cố đủ sớm không? Nếu incident xảy ra và không có alert nào fired trước — threshold quá cao hoặc thiếu metric quan trọng
- Alert này có false positive không? Nếu on-call được wake-up nhưng không có gì cần làm — threshold quá nhạy hoặc cần thêm context filter
- Sau mỗi post-mortem: cập nhật runbook với trigger condition rõ ràng cho alert, và điều chỉnh threshold hoặc routing dựa trên bài học thực tế. Không để threshold được đặt một lần rồi không ai chạm vào trong 12 tháng
Mục tiêu cuối cùng: on-call nhận alert thì biết cần làm gì — có runbook, có context, và alert đó xứng đáng với sự chú ý ngay lúc đó. Alert không đạt tiêu chuẩn này là technical debt trong alert system.
Ví dụ thực tế: monitoring pipeline cho hệ thống IoT 200 cảm biến
Trong dự án giám sát chất lượng nước cho 12 quận tại Cần Thơ, hệ thống nhận data từ 200+ cảm biến và ban đầu dùng static threshold cho mọi metric. Kết quả: hơn 40 alert mỗi ngày, phần lớn là false positive do sensor data có noise tự nhiên và pattern biến đổi theo thủy triều. On-call bắt đầu bỏ qua alert sau 2 tuần.
Sau khi tái thiết kế: tầng 1 chỉ giữ 3 alert tuyệt đối (sensor mất kết nối, giá trị vượt mức nguy hiểm tuyệt đối theo quy chuẩn, pipeline write fail). Tầng 2 dùng rolling baseline 7 ngày với window theo giờ để capture tidal pattern. Tầng 3 dùng Isolation Forest trên multivariate sensor reading để phát hiện pattern bất thường không rõ nguyên nhân. Tổng số actionable alert giảm từ 40+/ngày xuống còn 2–4/ngày, không có incident bị bỏ sót trong 3 tháng vận hành sau khi tái thiết kế.
Kết luận
Alert fatigue không phải vấn đề về tool — mà là vấn đề về thiết kế. Phân tầng alert theo loại bất thường, routing theo severity, và đóng feedback loop sau mỗi incident là ba thực hành cần triển khai đồng thời. Trong lớp Optimization Loop, alert pipeline là một trong những thành phần được chuẩn hóa ngay từ ngày deploy đầu tiên của mỗi Pilot Build — không phải bổ sung sau khi on-call đã burnout.