Dashboards, Phương Pháp Observability & Alert Best Practices
Vấn đề của "monitor everything"
Khi team mới bắt đầu với Cloud Monitoring, phản ứng thường gặp là "add tất cả metrics vào dashboard và alert". Kết quả: dashboard với 50 charts không ai nhìn vào, 30 alerts với 40% false positive rate, và oncall burnout sau 2 tuần.
Vấn đề cốt lõi: Không phải thiếu data, mà thiếu framework để biết data nào quan trọng. Đây là lý do tại sao SRE community phát triển các phương pháp có cấu trúc để chọn metrics cần monitor.
Ba phương pháp quan trọng nhất
USE Method — Cho Infrastructure
USE = Utilization, Saturation, Errors. Áp dụng cho từng resource vật lý hoặc ảo trong hệ thống.
Utilization: Phần trăm thời gian resource đang bận với useful work. Ví dụ: CPU utilization 80% = CPU đang busy 80% thời gian.
Saturation: Mức độ resource đang bị overloaded — work đang queue chờ. CPU saturation = run queue length (bao nhiêu processes đang chờ CPU). Đây là dấu hiệu đầu tiên của performance problems, thường xuất hiện trước utilization đạt 100%.
Errors: Số lượng lỗi của resource. Disk errors, network packet drops, CPU exceptions.
Áp dụng USE cho từng resource:
| Resource | Utilization | Saturation | Errors |
|---|---|---|---|
| CPU | compute.googleapis.com/instance/cpu/utilization | Run queue length (via cAdvisor container_cpu_cfs_throttled_periods) | CPU errors (hiếm) |
| Memory | compute.googleapis.com/instance/memory/balloon/ram_used | OOM kills, swapping | Memory ECC errors |
| Disk I/O | I/O utilization (% time busy) | Disk queue depth | Disk errors |
| Network | Network bandwidth utilization | Network queue drops | networking.googleapis.com/vm_flow/rx_packets_dropped |
| GKE Node | CPU/Memory requests vs allocatable | Pending pods due to resource pressure | Node conditions |
Khi nào USE thực sự hữu ích:
USE giúp phát hiện resource bottlenecks trước khi chúng biểu hiện thành user-visible problems. Nếu saturation (queue depth) tăng, đó là early warning — utilization có thể chỉ 60% nhưng queue đang build up.
Giới hạn của USE:
USE không giúp bạn biết liệu service có đang serve users tốt không. CPU 5% và memory 10% (utilization thấp) không có nghĩa là không có bug gây ra slow responses. USE là cần thiết nhưng không đủ.
RED Method — Cho Microservices
RED = Rate, Errors, Duration. Áp dụng cho từng service trong microservices architecture.
Rate: Số requests per second đang được service xử lý. Cho biết traffic volume.
Errors: Số (hoặc tỉ lệ) requests đang fail. Định nghĩa "error" phụ thuộc vào service: HTTP 5xx, gRPC status codes, business logic errors.
Duration: Distribution của response time. Quan trọng: không chỉ mean, mà cần P50, P90, P95, P99. Latency distribution thường có long tail — P99 có thể gấp 10x P50.
RED metrics trong thực tế với GKE services:
Nếu service của bạn expose Prometheus metrics qua GMP:
# Rate
rate(http_requests_total[5m])
# Error rate
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
# Duration P99
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))Nếu dùng Cloud Load Balancer:
# Rate
metric.type="loadbalancing.googleapis.com/https/request_count"
# Errors
metric.type="loadbalancing.googleapis.com/https/request_count"
filter metric.labels.response_code_class="5xx"
# Duration (P99)
metric.type="loadbalancing.googleapis.com/https/total_latencies"
alignmentPeriod: 60s, perSeriesAligner: ALIGN_PERCENTILE_99Khi nào RED quan trọng nhất:
RED là foundation của SLO-based monitoring. SLI availability = 1 - (Error/Rate). SLI latency = fraction of requests with Duration < threshold. Hiểu RED giúp thiết kế SLIs đúng.
Four Golden Signals — Cho User-Facing Services
Được đề xuất trong SRE Book của Google, Four Golden Signals bao gồm: Latency, Traffic, Errors, Saturation.
Latency: Thời gian để serve một request. Phân biệt rõ successful vs failed requests — successful latency giúp hiểu performance; failed latency thường artificially thấp (fast fail) hoặc cao (timeout).
Traffic: Demand đặt lên hệ thống. HTTP requests/s, active connections, I/O rate. Traffic giúp contextualize các signals khác: latency tăng khi traffic tăng gấp đôi có ý nghĩa khác với latency tăng khi traffic không đổi.
Errors: Rate của failed requests. Định nghĩa failure: explicit failures (HTTP 500), implicit failures (HTTP 200 nhưng wrong content), policy violations (response chậm hơn SLO).
Saturation: Fullness của service. Thường là metric khó nhất để đo. CPU queue depth, memory % used, connection pool exhaustion. Saturation thường predict upcoming problems trước khi errors và latency increase.
Tại sao Four Golden Signals tốt hơn "monitor everything":
Bốn signals này đủ để:
- Detect khi users bị ảnh hưởng (Latency + Errors)
- Understand tại sao (Traffic + Saturation)
- Dự đoán future problems (Saturation)
Khi có incident và bạn chỉ có thời gian check 4 charts, đây là 4 charts cần check.
Kết hợp ba phương pháp
Trong thực tế, ba phương pháp này bổ sung cho nhau:
Four Golden Signals (user-visible layer)
↓ khi thấy vấn đề
RED per-service (service layer — tìm service nào đang có vấn đề)
↓ sau khi tìm ra service
USE per-resource (resource layer — tìm resource bottleneck)Đây là chiến lược top-down cho incident investigation.
Dashboards as Code với Terraform
Tại sao dashboards phải là code
Dashboard click-to-create trong Console là tiện lợi nhưng có nhiều vấn đề:
- Không reproducible: Không có cách recreate dashboard nếu accidentally deleted
- Không versionable: Không biết ai thay đổi gì, khi nào
- Không auditable: Không có audit trail
- Không scalable: Copy dashboard cho 10 environments bằng click → toil
Dashboards as code giải quyết tất cả điều này.
Terraform resource cho Cloud Monitoring dashboards
resource "google_monitoring_dashboard" "service_overview" {
dashboard_json = jsonencode({
displayName = "Service Overview — ${var.service_name}"
gridLayout = {
columns = 2
widgets = [
# Rate chart
{
title = "Request Rate"
xyChart = {
dataSets = [{
timeSeriesQuery = {
timeSeriesFilter = {
filter = "metric.type=\"loadbalancing.googleapis.com/https/request_count\" resource.type=\"https_lb_rule\" resource.label.\"url_map_name\"=\"${var.lb_name}\""
aggregation = {
alignmentPeriod = "60s"
perSeriesAligner = "ALIGN_RATE"
crossSeriesReducer = "REDUCE_SUM"
}
}
}
}]
timeshiftDuration = "0s"
yAxis = {
label = "Requests/s"
scale = "LINEAR"
}
}
},
# Error rate chart
{
title = "Error Rate (5xx %)"
xyChart = {
dataSets = [{
timeSeriesQuery = {
timeSeriesFilterRatio = {
numerator = {
filter = "metric.type=\"loadbalancing.googleapis.com/https/request_count\" metric.label.\"response_code_class\"=\"5xx\""
aggregation = {
alignmentPeriod = "60s"
perSeriesAligner = "ALIGN_RATE"
crossSeriesReducer = "REDUCE_SUM"
}
}
denominator = {
filter = "metric.type=\"loadbalancing.googleapis.com/https/request_count\""
aggregation = {
alignmentPeriod = "60s"
perSeriesAligner = "ALIGN_RATE"
crossSeriesReducer = "REDUCE_SUM"
}
}
}
}
}]
}
}
]
}
})
}Terraform cho alerting policies
resource "google_monitoring_alert_policy" "high_error_rate" {
display_name = "${var.service_name} — High Error Rate"
combiner = "AND"
conditions {
display_name = "Error rate > 5% (1h window, 14.4x burn rate)"
condition_monitoring_query_language {
query = <<-EOT
select_slo_burn_rate(
"${google_monitoring_slo.availability_slo.id}",
1h
) > 14.4
EOT
duration = "0s"
}
}
conditions {
display_name = "Error rate > 5% (5m window, 14.4x burn rate)"
condition_monitoring_query_language {
query = <<-EOT
select_slo_burn_rate(
"${google_monitoring_slo.availability_slo.id}",
5m
) > 14.4
EOT
duration = "0s"
}
}
notification_channels = [
google_monitoring_notification_channel.pagerduty.id,
google_monitoring_notification_channel.slack.id,
]
alert_strategy {
auto_close = "86400s" # 24 giờ
notification_rate_limit {
period = "300s" # Tối thiểu 5 phút giữa 2 notifications
}
}
documentation {
content = "Error budget burn rate cao. Runbook: ${var.runbook_url}"
mime_type = "text/markdown"
}
}Tổ chức Terraform modules cho monitoring
modules/
└── service-monitoring/
├── variables.tf # service_name, slo_target, etc.
├── dashboard.tf # Service overview dashboard
├── alerting.tf # Alerting policies
├── slo.tf # SLO definition
└── notification.tf # Notification channels
# Sử dụng:
module "api_service_monitoring" {
source = "./modules/service-monitoring"
service_name = "payment-api"
slo_target = 0.999
runbook_url = "https://wiki.internal/runbooks/payment-api"
}Module hóa monitoring config cho phép tạo consistent observability setup cho mỗi service mà không phải duplicate config. Khi có best practice update (ví dụ, add thêm một alert condition), chỉ cần update module — tất cả services tự động được cập nhật qua terraform apply.
Alert Design Best Practices
1. Một alert chỉ có một action
Mỗi alert phải có một action rõ ràng trong documentation. Nếu không biết action nào khi nhận alert, đó là sign alert không nên exist hoặc cần được rethink.
Trong documentation.content, luôn include:
- What happened: Mô tả ngắn về condition
- Impact: Ảnh hưởng đến user thế nào
- Immediate action: Phải làm gì ngay
- Runbook link: Link đến detailed runbook
2. Alert trên user-visible symptoms, không phải causes
Đây là nguyên tắc quan trọng nhất. Luôn hỏi: "Có user nào đang bị ảnh hưởng bởi điều này không?"
- ❌ Alert: Pod restart count > 3 lần/giờ
- ✅ Alert: SLO burn rate > 6x (user đang gặp vấn đề)
Pod restart nhiều nhưng nếu service vẫn serve requests tốt (readiness probe pass nhanh), users không bị ảnh hưởng. Alert trên pod restarts tạo noise mà không có signal.
3. Đặt threshold từ data, không từ intuition
Trước khi đặt threshold, thu thập ít nhất 2-4 tuần data về metric trong điều kiện bình thường (baseline). Alert threshold nên là:
- Rõ ràng higher than normal (không overlap với normal range)
- Dựa trên historical data của chính hệ thống
Công thức thực dụng: threshold = baseline_p99 × 2 cho threshold "cần điều tra", và baseline_p99 × 5 cho threshold "cần page ngay".
4. Phân biệt pages và tickets
Không phải mọi alert đều cần wake up oncall lúc 3 giờ sáng:
| Severity | Khi nào | Action |
|---|---|---|
| Page (critical) | User impact đang xảy ra | Oncall phải respond trong 5 phút |
| Ticket (warning) | Potential future impact | Engineer xử lý trong giờ làm việc |
| Info | FYI, no action needed | Dashboard hoặc Slack channel only |
Phần lớn alerts nên là "tickets", không phải "pages". Pages phải reserved cho incidents yêu cầu immediate human action.
5. Alert group để giảm noise
Khi một vấn đề gốc rễ gây ra nhiều symptoms, bạn muốn nhận một notification về "có vấn đề", không phải 50 notifications về mỗi symptom.
Trong Cloud Monitoring, notification grouping được xử lý qua:
- Condition combiner: Dùng
ORđể group conditions trong một policy - Pub/Sub consumer: Build custom routing logic để deduplicate alerts trước khi send to PagerDuty/Slack
PagerDuty và Opsgenie có native alert grouping features — configure policy alerting để push qua một channel (Pub/Sub hoặc webhook) đến các tools này, và let them handle grouping.
Dashboard Design Principles
Hierarchy: Overview → Service → Component
Good dashboard hierarchy:
- Org-level overview: Health của toàn bộ platform (SLO compliance per service)
- Service-level: Four Golden Signals cho một service
- Component-level: USE metrics cho infrastructure components
- Incident dashboard: Relevant metrics khi đang investigate incident
Oncall đầu tiên nhìn vào overview để tìm service nào có vấn đề, rồi drill down vào service dashboard, rồi component dashboard.
Luôn show context
Một chart đứng một mình không có ý nghĩa. Luôn đặt charts theo nhóm để show context:
[Error rate] [Request rate] ← Side by side để thấy errors relative to traffic
[P99 Latency] [P50 Latency] ← Để thấy tail behavior vs typical
[CPU Utilization] [Memory] ← Resource side by sideTime range defaults
Mặc định dashboard nên hiển thị 1 giờ cuối cho incident investigation. Nhưng luôn có "comparison" với "cùng thời điểm hôm qua/tuần trước" để thấy anomaly so với normal pattern.