Giao diện
Challenge: Observability Debug
⚔️ THỰC HÀNH THỰC CHIẾN
Module này là bài tập debug từ góc nhìn Senior SRE On-Call tại HPN. Mục tiêu: Rèn luyện kỹ năng điều tra sự cố production sử dụng Prometheus, Grafana, và Loki.
📋 Kịch Bản: 3:00 AM Production Incident
Tình huống
Bạn đang on-call và nhận được alert lúc 3:00 AM:
text
🚨 FIRING: High Error Rate Detected
Severity: Critical
Service: payment-service
Namespace: production
Error Rate: 15.2% (threshold: 1%)
Started: 2024-01-15 03:00:12 UTC
Runbook: /runbooks/high-error-rate.mdTriệu chứng
Grafana Dashboard hiển thị:
text
╔══════════════════════════════════════════════════════════════════╗
║ 📊 PAYMENT SERVICE - GOLDEN SIGNALS ║
╠══════════════════════════════════════════════════════════════════╣
║ ║
║ ⏱️ Latency P99: █████████████░░ 3.2s (normal: 200ms) 🔴 ║
║ 📈 Traffic: ████████░░░░░░░ 850 RPS ║
║ ❌ Error Rate: ███████████████ 15.2% 🔴🔴🔴 ║
║ 🔋 Saturation: ███████████░░░░ CPU 78% ║
║ ║
╚══════════════════════════════════════════════════════════════════╝💀 Step 1: Initial Triage
Kiểm tra pods status
bash
$ kubectl get pods -n production -l app=payment-service
NAME READY STATUS RESTARTS AGE
payment-service-7d9f8b6c4d-abc1 1/1 Running 0 2d
payment-service-7d9f8b6c4d-def2 1/1 Running 0 2d
payment-service-7d9f8b6c4d-ghi3 1/1 Running 0 2dPods đang Running, không có restart. → Vấn đề không phải crash.
Query Prometheus
Query 1: Error rate breakdown by status code
promql
sum(rate(http_requests_total{service="payment-service", status=~"5.."}[5m]))
by (status)Kết quả:
| Status | Rate (req/s) |
|---|---|
| 500 | 8.5 |
| 503 | 120.3 |
| 504 | 2.1 |
💡 NHẬN XÉT
503 Service Unavailable chiếm đa số! Đây thường là dấu hiệu của:
- Upstream service không respond
- Connection pool exhausted
- Rate limiting
🧠 Bài Tập
Câu hỏi 1: Tiếp tục điều tra
Với thông tin trên, bạn sẽ query thêm những gì để tìm root cause?
💡 Gợi ý
- Service
payment-servicephụ thuộc vào database và Redis - 503 thường liên quan đến upstream dependencies
- Check connection pool metrics
Viết 2-3 PromQL queries tiếp theo trước khi xem đáp án.
Câu hỏi 2: Xác định Root Cause
Sau khi chạy thêm queries, bạn có kết quả sau:
promql
# Database connection pool
pg_pool_active_connections{service="payment-service"} → 50
pg_pool_max_connections{service="payment-service"} → 50 # 💀 MAX!
# Database query latency
histogram_quantile(0.99, rate(pg_query_duration_seconds_bucket[5m])) → 2.8sDựa trên dữ liệu này, root cause là gì?
✅ Đáp Án
Step-by-Step Investigation
Investigation Query 1: Check upstream latency
promql
# Latency của calls từ payment-service đến database
histogram_quantile(0.99,
rate(http_client_request_duration_seconds_bucket{
caller="payment-service",
callee="postgres"
}[5m])
)
# Kết quả: 2.8 seconds (bình thường: < 50ms)Investigation Query 2: Check connection pool
promql
# Active connections / Max connections
pg_pool_active_connections / pg_pool_max_connections
# Kết quả: 1.0 (100% - EXHAUSTED!)Investigation Query 3: Check slow queries
promql
# Top slow queries
topk(5, rate(pg_query_duration_seconds_sum[5m]) / rate(pg_query_duration_seconds_count[5m]))Root Cause Analysis
text
╔══════════════════════════════════════════════════════════════════════════════╗
║ 🔍 ROOT CAUSE ANALYSIS ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ 🎯 PRIMARY CAUSE: Database Connection Pool Exhaustion ║
║ ║
║ ┌─────────────────────────────────────────────────────────────────────┐ ║
║ │ Timeline: │ ║
║ │ │ ║
║ │ 02:45 - Slow query starts (missing index on new column) │ ║
║ │ 02:50 - Query latency: 50ms → 2.8s │ ║
║ │ 02:55 - Connection pool fills up (queries waiting) │ ║
║ │ 03:00 - Pool FULL (50/50) → New requests get 503 │ ║
║ │ 03:00 - 🚨 ALERT FIRES │ ║
║ └─────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ 💡 WHY 503? ║
║ - Application has connection timeout = 5s ║
║ - All 50 connections busy with slow queries ║
║ - New request can't get connection → 503 after timeout ║
║ ║
╚══════════════════════════════════════════════════════════════════════════════╝The Fix
Immediate (Mitigation):
bash
# 1. Kill slow queries
kubectl exec -it postgres-0 -- psql -c "SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE duration > interval '10 seconds'
AND state = 'active';"
# 2. Increase connection pool temporarily
kubectl set env deployment/payment-service DB_POOL_SIZE=100Permanent (Resolution):
sql
-- Add missing index
CREATE INDEX CONCURRENTLY idx_transactions_created_at
ON transactions(created_at);
-- Verify
EXPLAIN ANALYZE SELECT * FROM transactions
WHERE created_at > NOW() - INTERVAL '1 day';📊 Observability Pitfalls
⚠️ NHỮNG LỖI THƯỜNG GẶP
1. Missing Labels = Can't Filter
promql
# ❌ Không có label 'endpoint' → không biết endpoint nào gây lỗi
http_requests_total{status="500"}
# ✅ Có label đầy đủ
http_requests_total{status="500", endpoint="/api/payment", method="POST"}2. Cardinality Explosion = Prometheus OOM
promql
# ❌ Label với giá trị unique (user_id, request_id)
http_requests_total{user_id="..."} # → Triệu series!
# ✅ Label với bounded values
http_requests_total{user_tier="premium"} # → Vài series3. Alert Fatigue = Ignored Critical Alerts
yaml
# ❌ SAI: Alert với threshold quá nhạy
- alert: HighLatency
expr: latency_p99 > 100ms # Fires 100 lần/ngày → Bị ignore
# ✅ ĐÚNG: Alert có ý nghĩa
- alert: HighLatency
expr: latency_p99 > 500ms
for: 5m # Phải kéo dài 5 phút4. No Runbook = Panic at 3 AM
yaml
# ✅ ĐÚNG: Alert có runbook
annotations:
runbook_url: https://wiki/runbooks/high-error-rate.md
summary: "Error rate {{ $value }}% exceeds threshold"✅ Production Observability Checklist
✅ CHECKLIST CHO PRODUCTION
Metrics Collection:
- [ ] Application expose
/metricsendpoint - [ ] Labels có bounded cardinality (< 100 unique values)
- [ ] Có metrics cho 4 Golden Signals (Latency, Traffic, Errors, Saturation)
- [ ] Database connection pool metrics được expose
Alerting:
- [ ] Mỗi alert có severity (critical, warning, info)
- [ ] Mỗi alert có runbook link
- [ ] Alert thresholds được tune (không quá nhạy)
- [ ] PagerDuty/Slack routing được setup
Dashboards:
- [ ] Dashboard overview cho mỗi service
- [ ] Dashboard có time range selector
- [ ] Dashboard có drill-down links
- [ ] Critical metrics có annotations cho incidents
On-Call:
- [ ] Runbooks được viết và test
- [ ] Escalation policy được define
- [ ] Post-mortem process established
🎯 Key Takeaways
📝 BÀI HỌC RÚT RA
- Golden Signals First - Luôn check Latency, Traffic, Errors, Saturation đầu tiên
- Follow the dependency chain - 503 thường là upstream issue
- Connection pools are critical - Monitor và alert khi > 80%
- Labels are your friend - Đầu tư vào labeling strategy sớm
- Runbooks save lives - Viết runbook TRƯỚC khi incident xảy ra
PromQL Cheat Sheet cho On-Call
promql
# Error rate
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100
# Latency P99
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
# Connection pool saturation
pg_pool_active_connections / pg_pool_max_connections * 100
# Memory usage
container_memory_usage_bytes / container_spec_memory_limit_bytes * 100
# CPU throttling
rate(container_cpu_cfs_throttled_seconds_total[5m])🔗 Liên kết
- Lý thuyết: Module 11: Observability
- Tiếp theo: Module 12: Helm Charts