Skip to content

Alerting Architecture — Policies, Conditions & Notification Channels

Tại sao alerting là phức tạp hơn bạn nghĩ

Phần lớn engineer nhìn vào alerting như một bài toán đơn giản: "khi metric X > threshold Y, gửi notification". Nhưng trong thực tế production, alerting có nhiều lớp phức tạp:

  • False positives: Alert fire khi không có vấn đề thực sự → alert fatigue → team ignore alerts → miss outage thực
  • False negatives: Có outage nhưng alert không fire vì threshold sai hoặc evaluation lag
  • Notification reliability: Notification channel lỗi → alert fire nhưng không ai biết
  • Alert chồng chéo: Nhiều policies alert cùng một vấn đề → noise không additive information

Hiểu cơ chế bên trong của alerting engine giúp thiết kế policies tránh được những failure modes này.

Cấu trúc của Alerting Policy

Một alerting policy trong Cloud Monitoring gồm các thành phần:

AlertPolicy
├── displayName: "High CPU"
├── conditions: [Condition1, Condition2, ...]  # 1-6 conditions
├── combiner: OR | AND | AND_WITH_MATCHING_RESOURCE
├── notificationChannels: [channel1, channel2]
├── alertStrategy:
│   ├── autoClose: 7d (thời gian tự đóng incident)
│   └── notificationRateLimit:
│       └── period: 5m (minimum interval giữa 2 notifications)
└── documentation:
    └── content: "Runbook link, context"

Condition — đơn vị đánh giá cơ bản:

Condition
├── displayName: "CPU > 80%"
├── conditionThreshold:
│   ├── filter: 'metric.type="compute.googleapis.com/instance/cpu/utilization"'
│   ├── comparison: COMPARISON_GT
│   ├── thresholdValue: 0.8
│   ├── duration: 60s  # retest window
│   └── aggregations:
│       ├── alignmentPeriod: 60s
│       ├── perSeriesAligner: ALIGN_MEAN
│       └── crossSeriesReducer: REDUCE_MEAN
└── (hoặc conditionAbsent, conditionMonitoringQueryLanguage, conditionPrometheusQueryLanguage)

Condition Types — Bốn cách định nghĩa điều kiện

1. Metric Threshold (conditionThreshold)

Condition phổ biến nhất. Evaluate khi một metric value vượt (hoặc dưới) một ngưỡng.

Filter: Xác định time series nào cần evaluate. Dùng monitoring filter syntax:

metric.type = "compute.googleapis.com/instance/cpu/utilization"
AND resource.labels.project_id = "my-project"
AND metric.labels.instance_name != "bastion"

Comparison operators: COMPARISON_GT, COMPARISON_GE, COMPARISON_LT, COMPARISON_LE, COMPARISON_EQ, COMPARISON_NE

Aggregations: Cách transform raw time series trước khi compare với threshold. Hai bước:

  1. perSeriesAligner: align từng time series (ALIGN_MEAN, ALIGN_MAX, ALIGN_RATE, etc.)
  2. crossSeriesReducer + groupByFields: gộp nhiều time series

Ví dụ: alert khi mean CPU của TẤT CẢ VMs trong project > 80%:

  • perSeriesAligner: ALIGN_MEAN → align từng VM
  • crossSeriesReducer: REDUCE_MEAN → lấy mean của tất cả VMs
  • groupByFields: [] (không group, gộp tất cả thành 1 time series)

Ví dụ khác: alert khi BẤT KỲ VM nào > 80%:

  • perSeriesAligner: ALIGN_MEAN → align từng VM
  • crossSeriesReducer: REDUCE_NONE hoặc không reduce → giữ nguyên per-VM series
  • Mỗi VM là một time series riêng, mỗi cái có thể trigger incident riêng

2. Metric Absence (conditionAbsent)

Alert khi không có data trong một khoảng thời gian nhất định. Hữu ích để detect:

  • Service down (không gửi metrics nữa)
  • Metric collection broken
  • Heartbeat metric missing
conditionAbsent:
  filter: 'metric.type="custom.googleapis.com/my_app/heartbeat"'
  duration: 300s  # alert nếu không có data trong 5 phút
  aggregations: [...]

Giới hạn: Absence condition không thể phân biệt "service down" và "metric collection bị broken". Cả hai đều cho cùng một symptom: không có data.

3. Monitoring Query Language (MQL) condition

Dùng MQL query thay vì filter+aggregation thông thường. Linh hoạt hơn cho các điều kiện phức tạp:

conditionMonitoringQueryLanguage:
  query: |
    fetch gce_instance
    | metric "compute.googleapis.com/instance/cpu/utilization"
    | filter resource.labels.zone = "us-central1-a"
    | group_by [resource.labels.instance_id], mean(val())
    | condition val() > 0.8
  duration: 60s

MQL cho phép join nhiều metrics, tính tỉ lệ phức tạp, và các điều kiện không thể express bằng threshold condition đơn giản.

4. Prometheus Query Language (PromQL) condition

Tương tự MQL nhưng dùng PromQL. Chỉ hoạt động với Prometheus metrics (GMP). Cho phép dùng lại alert rules đã có từ self-hosted Prometheus:

conditionPrometheusQueryLanguage:
  query: |
    rate(http_requests_total{status="5xx"}[5m])
    / rate(http_requests_total[5m]) > 0.05
  duration: 300s

5. Log-based conditions

Alert dựa trên logs chứ không phải metrics. Được evaluate qua log-based metrics. Sẽ được cover chi tiết hơn trong Chapter 40 (Cloud Logging).

Evaluation Engine — Cơ chế hoạt động bên trong

Alignment Period và cách data được xử lý

Mọi condition đều có alignmentPeriod — đây là "độ phân giải" mà condition được evaluate. Alerting engine:

  1. Thu thập raw metric data points trong alignmentPeriod
  2. Áp dụng perSeriesAligner để tính một giá trị đại diện cho period đó
  3. So sánh với threshold
  4. Nếu có crossSeriesReducer, gộp các time series lại trước khi compare

Latency tổng thể:

Total alert latency = metric collection delay + alerting computation + retest window
                    ≈ 60s (GCP metrics) + 330s (computation) + retest window duration

Theo tài liệu GCP chính thức: "Total notification latency includes metric collection delay (up to 60 seconds for Google Cloud), alerting computation (additional 5 minutes 30 seconds), and retest window."

Điều này có nghĩa là: ngay cả khi không có retest window, alert sẽ mất tối thiểu 6.5 phút để fire từ lúc sự kiện xảy ra. Với retest window 5 phút, tổng delay là 11.5 phút.

Retest Window — Tại sao alert không fire ngay

duration trong condition không phải "bao lâu metric ở trên threshold thì alert". Nó là retest window: trong khoảng thời gian này, mọi aligned value đều phải vi phạm threshold.

duration: 300s (5 phút)
alignmentPeriod: 60s (1 phút)

Nghĩa là: trong 5 phút liên tiếp, aligned value mỗi phút đều phải > threshold. Nếu bất kỳ phút nào giá trị xuống dưới threshold, retest window reset về 0.

Theo tài liệu: "A condition resets its retest window each time a measurement or forecast doesn't satisfy the condition."

Tại sao thiết kế này tốt: Loại bỏ false positives từ metric spikes ngắn. CPU 100% trong 10 giây không đủ để breach retest window 5 phút.

Tại sao thiết kế này cần hiểu rõ: Một spike ngắn nhưng nghiêm trọng (ví dụ, memory spike 100% trong 2 phút dẫn đến OOM kill) có thể không trigger alert nếu retest window là 5 phút.

Thiết kế đúng: Dùng retest window ngắn (60s) với alert severity "warning" để catch tất cả, và retest window dài (5-10 phút) cho "critical" alert yêu cầu page oncall.

Multi-condition Logic

Một alerting policy có thể chứa đến 6 conditions. Chúng được kết hợp bằng combiner:

OR (mặc định):

  • Incident mở khi BẤT KỲ condition nào được thỏa mãn
  • Mỗi condition có thể mở incident riêng (nếu trigger bởi different time series)
  • Dùng khi: bất kỳ dấu hiệu nào cũng cần alert

AND:

  • Incident mở khi TẤT CẢ conditions được thỏa mãn (có thể bởi different resources)
  • Dùng khi: cần corroborate từ nhiều signals khác nhau

AND_WITH_MATCHING_RESOURCE:

  • Tất cả conditions phải được thỏa mãn bởi cùng một resource
  • Dùng khi: muốn alert chỉ khi một VM cụ thể có cả high CPU lẫn high memory

Giới hạn quan trọng: Tối đa 1,000 incidents open đồng thời cho một alerting policy. Nếu hit limit này (ví dụ, 1000 VMs đều CPU cao cùng lúc), các incident mới sẽ không được mở. Đây là failure mode nguy hiểm trong large fleet.

Incident Lifecycle

Từ condition violation đến notification

Condition violated
      ↓ (evaluation + retest window)
Incident OPEN
      ↓ (notification sent to all channels)
Notification received by oncall
      ↓ (người dùng acknowledge trong Console/API)
Incident ACKNOWLEDGED (optional state)
      ↓ (condition no longer violated)
Incident CLOSED
      ↓ (resolution notification sent, nếu configured)

Open: Incident được tạo khi condition vi phạm trong toàn bộ retest window. Notification được gửi đến tất cả notification channels đồng thời.

Acknowledged: State tùy chọn, người dùng có thể acknowledge để báo hiệu "đang xử lý". Không ngăn chặn additional notifications (vẫn có repeat notifications nếu configured).

Closed: Có hai cách đóng:

  1. Auto-close: Condition không còn vi phạm (metric trở về bình thường)
  2. Manual close: Người dùng đóng thủ công qua Console/API
  3. Auto-close by time: autoClose duration (mặc định 7 ngày) — nếu missing data kéo dài

Missing Data Handling — Điểm tinh tế

Khi metric data dừng lại (service down, collection broken), condition phải quyết định làm gì với incidents đang mở. Ba chiến lược:

Chiến lượcIncident đang mởIncident mới
EMPTY (mặc định)Giữ nguyênKhông mở mới
VIOLATES_POLICYGiữ nguyênCó thể mở (behave như absence alert)
DOES_NOT_VIOLATEĐóng lạiKhông mở mới

Hiểu lầm phổ biến: Với chiến lược EMPTY (mặc định), nếu service đang bình thường (không có incident) rồi dừng gửi metrics, không có incident nào được mở tự động. Bạn sẽ không biết service down! Để detect service down bằng metric absence, cần conditionAbsent riêng.

Auto-close: Sau autoClose duration (mặc định 7 ngày), incident bị đóng tự động dù condition vẫn vi phạm. Điều này tránh incidents "zombie" tồn tại vô hạn khi data missing. Nhưng nó cũng có nghĩa là incident về service permanently down sẽ bị auto-close sau 7 ngày.

Uptime Checks — Probing từ Outside

Uptime checks là cơ chế probe HTTP/HTTPS/TCP endpoints từ bên ngoài GCP infrastructure, từ nhiều địa điểm trên thế giới.

Cơ chế hoạt động

Cloud Monitoring vận hành một mạng lưới probe agents ở nhiều regions trên thế giới. Mỗi uptime check được configured với:

  • Target: URL, IP address, hoặc cloud resource (GKE service, App Engine, etc.)
  • Check interval: 1, 5, 10, hoặc 15 phút
  • Success criteria: HTTP status code, body matching (regex)
  • Timeout: Mặc định 10 giây

Các probe agents distributed check từ 6 vị trí mặc định (USA, Europe, Asia, South America). Mỗi vị trí là một independent check.

Uptime check metric: Kết quả được ghi vào metric monitoring.googleapis.com/uptime_check/check_passed (BOOL GAUGE, per-location). Và uptime_check/request_latency (latency của mỗi check).

Alert condition trên uptime check:

Để alert khi service down, dùng threshold condition trên check_passed:

yaml
filter: metric.type="monitoring.googleapis.com/uptime_check/check_passed"
        AND metric.labels.check_id="my-check-id"
comparison: COMPARISON_LT
thresholdValue: 1  # alert nếu bất kỳ location nào fail
# hoặc
aggregations:
  crossSeriesReducer: REDUCE_FRACTION_TRUE  # alert khi < 50% locations pass
thresholdValue: 0.5

Tại sao uptime checks quan trọng cho SRE: Chúng detect user-visible outages mà internal metrics không thấy. Một GKE Pod healthy (internal metrics xanh) nhưng Load Balancer health check broken → users không reach được → uptime check fail → alert. Internal metrics không bao giờ thấy điều này.

Giới hạn của uptime checks

  • Không thể probe private endpoints (chỉ public URLs)
  • Không thể authenticate với OAuth2 hoặc mTLS (chỉ basic auth + custom headers)
  • Interval tối thiểu 1 phút → không detect sub-minute outages
  • False positives nếu service có geographic restrictions

Notification Channels — Reliability là vấn đề số 1

Các loại notification channels

ChannelReliabilityLatency
EmailCao (email servers)Vài phút (có thể vào spam)
SMSTrung bình (phụ thuộc carrier)30s-5 phút
PagerDutyCao (dedicated service)<1 phút
OpsgenieCao<1 phút
SlackTrung bình (phụ thuộc Slack uptime)<1 phút
Pub/SubRất cao (GCP managed)<30 giây
WebhooksPhụ thuộc endpoint availability<1 phút
Google ChatTrung bình<1 phút

Pub/Sub là channel đáng tin cậy nhất: Khi alert policy fire, message được push vào Pub/Sub topic. Bạn có thể build consumers để route đến bất kỳ đích nào (PagerDuty API, internal ticketing, JIRA, custom dashboard). Vì Pub/Sub là GCP managed service với at-least-once delivery, message không bị mất ngay cả khi consumer tạm thời down.

Reliability consideration

Theo tài liệu GCP: Khi một policy có nhiều notification channels, tất cả đều nhận notification đồng thời. Không có cách chỉ gửi đến một channel cụ thể.

Failure mode: Nếu Slack down (thực tế xảy ra), và Slack là channel duy nhất của bạn, alert fire nhưng không ai biết. Luôn có ít nhất 2 channels: một dedicated alert platform (PagerDuty/Opsgenie) và một fallback (email hoặc Pub/Sub consumer).

Notification rate limiting: alertStrategy.notificationRateLimit.period — thời gian tối thiểu giữa 2 notifications cho cùng một incident. Mặc định không có rate limit. Nếu condition vi phạm liên tục và period được set là 1 giờ, notification sẽ được gửi mỗi giờ dù incident vẫn đang mở.

Điều này ngăn "notification storms" khi một vấn đề kéo dài gửi notification mỗi vài phút. Nhưng cũng có nghĩa là oncall nhận được ít context hơn về timeline của incident.

Alert Fatigue — Failure mode lớn nhất

Alert fatigue xảy ra khi team nhận quá nhiều alerts, phần lớn là false positives, đến mức bắt đầu ignore alerts. Đây là failure mode nguy hiểm nhất của alerting strategy vì nó làm mất đi toàn bộ giá trị của monitoring.

Nguyên nhân gốc rễ theo cơ chế

1. Threshold quá thấp:

Đặt CPU alert > 60% cho production VMs. Nếu VMs thường chạy ở 55-65%, sẽ có nhiều false positives. Cần hiểu baseline metrics của hệ thống trước khi đặt threshold.

2. Retest window quá ngắn:

Retest window 60s với metric noisy (như network packet rate) sẽ fire nhiều false positives. Cần balance giữa detection speed và noise.

3. Alert không actionable:

Alert "Memory usage > 80%" nhưng không có runbook, không có context, không có suggested action → oncall không biết phải làm gì → alert bị ignore.

4. Alert trùng lặp:

Nhiều policies alert cùng một vấn đề (CPU alert, latency alert, error rate alert — tất cả fire khi service overloaded) → noise nhân lên.

5. Alert không phân biệt severity:

Mọi alert đều page oncall dù chỉ là "minor degradation" → alert fatigue.

Thiết kế đúng để giảm alert fatigue

Nguyên tắc cốt lõi: Chỉ alert khi cần human action ngay lập tức. Nếu alert không yêu cầu action ngay, nó không nên page oncall.

Phân tầng severity:

  • Critical (page ngay): Outage đang ảnh hưởng users, cần action trong phút
  • Warning (ticket): Degradation nhẹ, cần xử lý trong giờ làm việc
  • Info (dashboard): Trend đáng chú ý, không cần action ngay

Symptom-based alerting:

Thay vì alert "CPU > 80%", alert "Latency P99 > 1 giây". CPU cao không nhất thiết là vấn đề với user; latency cao thì có. Alert trên symptoms (ảnh hưởng user-visible) tốt hơn alert trên causes (resource usage).

yaml
# Tránh (cause-based):
metric: compute.googleapis.com/instance/cpu/utilization
threshold: 0.8

# Tốt hơn (symptom-based):
metric: loadbalancing.googleapis.com/https/total_latencies  
p99 threshold: 1000ms  # 1 giây

Tham khảo chính thức