← AIOps W3 — Reliability Engineering & Postmortem

W3-D1: SLO, Error Budget, Burn-Rate Alerting

SLO, Error Budget, Burn-Rate Alerting

1. Định nghĩa

Khái niệmLà gìPhạm viPhạt khi miss
SLI — Service Level IndicatorMột số đo, range 0-1, đo từ phía user, proportional với user painEngineer-level metric
SLO — Service Level ObjectiveTarget cho SLI, ví dụ 99.9% trong 30-day windowInternal commitmentRelease freeze, reliability work
SLA — Service Level AgreementCam kết với customer, hợp đồngLegalTiền (refund, credit)

Quan hệ: SLA < SLO < hiện tại. SLA luôn lỏng hơn SLO; SLO luôn lỏng hơn measurement hiện tại (để có buffer fix).

Source: Beyer et al., Site Reliability Engineering, O’Reilly 2016, Chapter 4. sre.google/sre-book/service-level-objectives


2. SLI selection theo service type

Google SRE Workbook Chapter 2 phân service thành 4 loại, mỗi loại có metric chuẩn:

Service typeSLI categoriesVí dụ formula
Request-response (API, web)Availability, Latencycount(2xx,3xx,4xx_not_429 AND latency < 200ms) / count(all)
Data processing (ETL, stream)Freshness, Correctness, Coverage, Throughputcount(events processed within 5min lag) / count(all events)
Storage (S3-like, DB)Durability, Availabilitycount(read OR write success) / count(all)
Batch job (cron)Completeness, Runtimecount(completed within 1h SLA) / count(scheduled)

2.1 SLI quality criteria

Mỗi SLI phải pass 3 test:

  1. Measurable — có metric thật từ system, không phải khái niệm trừu tượng.
  2. User-side — đo từ phía user (load balancer log, RUM, synthetic probe). Đo từ phía app server miss network drop.
  3. Proportional — SLI giảm khi user pain, không giảm khi user OK.

2.2 Anti-pattern: CPU làm SLI

CPU không proportional với user pain:

  • CPU 80%, latency 150ms → user OK, nhưng SLI báo “không OK”.
  • CPU 30%, deadlock, latency 5s → user khổ, nhưng SLI báo “OK”.

CPU là saturation signal, không phải user happiness metric. Giữ cho capacity dashboard, không dùng làm SLI.

2.3 Latency: percentile selection

PercentileCaptureDùng khi
p50 (median)Trung vịThroughput-bound system (data pipeline)
p95Top 5% slowestBáo cáo general
p99Top 1% — tail real user painDefault cho user-facing
p99.9Top 0.1%Tier-1 service (search, login)

Default cho user-facing service: p99.

2.4 Availability: status code accounting

HTTP rangeĐếm vào fail?Lý do
5xxServer error
429Rate-limited bởi system → system reject user
4xx (không 429)User-side error (bad request)
2xx, 3xxSuccess

3. SLO target ladder

3.1 Số 9 và downtime budget

30-day window:

SLODowntime/thángDowntime/tuầnDowntime/ngày
99%7h 18m1h 41m14m
99.5%3h 39m50m7m
99.9%43m10m1m 26s
99.95%21m 36s5m43s
99.99%4m 19s1m8.6s
99.999%26s6s0.86s

3.2 Cost ladder

Mỗi tier thêm 1 số 9 thường nhân chi phí infra + ops headcount lên 3-10×:

SLOArchitecture cần
99%1 instance, manual recovery
99.9%Multi-instance, LB, auto-failover
99.99%Multi-AZ, automated runbook, 24/7 on-call
99.999%Multi-region active-active, dedicated SRE team

Source: Beyer et al., Chapter 4, “The Nines of Availability.”


4. Error budget

$$ \text{budget} = (1 - \text{SLO}) \times \text{total_events} $$

4.1 Đơn vị budget

Đơn vịKhi nào dùng
Số request failService có request count rõ
Phút downtimeService binary up/down
Số window failStream pipeline, batch

4.2 Ví dụ tính budget

SLO 99.9%, traffic 1M req/day, 30-day window:

budget = 0.001 × 1M × 30 = 30,000 request fail / month

Convert sang downtime equivalent (nếu sự cố 100% fail tại 12 req/s peak):

downtime budget = 30,000 / 12 = 2,500s ≈ 41 phút / tháng

4.3 Burn-down chart

% budget
consumed
100% ┤                                ╱─── exhausted
     │                          ╱────╱
 75% ┤                    ╱────╱
     │              ╱────╱   ← burn rate ≈ 1.5 (normal range)
 50% ┤        ╱────╱
     │  ╱────╱
 25% ┤─╱
     │
   0%└────┬────┬────┬────┬────┬────┬─── day
        D5   D10  D15  D20  D25  D30

Slope = burn rate. Slope 1.0 nghĩa là đốt budget đúng tốc độ baseline.

Source: Google SRE Workbook Chapter 2 “Implementing SLOs.” sre.google/workbook/implementing-slos


5. Burn rate

$$ \text{burn_rate} = \frac{\text{error_rate trong window}}{1 - \text{SLO}} $$

5.1 Burn rate → time to exhaust

Với SLO 99.9%, 30-day window:

Burn rateTime to exhaust budget
130 ngày (baseline)
215 ngày
65 ngày
14.450 giờ
3620 giờ
1445 giờ
144030 phút

5.2 Tại sao burn rate hơn raw error rate

Raw “5% error rate” không trả lời “có nên page không”:

  • SLO 99% → 5% error → burn rate 5 → vừa phải.
  • SLO 99.9% → 5% error → burn rate 50 → page ngay.

Burn rate normalize theo SLO → 1 ngưỡng dùng được cho mọi service.

5.3 Burn rate trên Prometheus

(
  sum(rate(http_requests_total{status=~"5..|429"}[1h]))
  / sum(rate(http_requests_total[1h]))
) / (1 - 0.999)

6. Single-window alert failure modes

WindowFalse positiveMTTDStop-firing lag
1 phútCao (spike-prone)1-2 phút<1 phút
5 phútTrung bình3-5 phút5 phút
1 giờThấp5-15 phút1 giờ
6 giờRất thấp30+ phút6 giờ

Không có window đơn perfect: short = noisy, long = chậm + dính lâu sau khi hết sự cố.


7. Multi-Window Multi-Burn-Rate (MWMBR)

Source: Google SRE Workbook Chapter 5 “Alerting on SLOs,” Section 6. sre.google/workbook/alerting-on-slos

7.1 Công thức

Alert fire khi CẢ HAI condition true cùng lúc:

  1. Long window burn rate ≥ T (sự cố đủ lớn để đáng action)
  2. Short window burn rate ≥ T (sự cố vẫn đang diễn ra ngay bây giờ)

Quy tắc tỉ lệ: short window ≈ long / 12.

7.2 Tier table chuẩn Google SRE

TierLong windowShort windowBurn rate thresholdBudget burned khi fireAction
1 — urgent page1h5min14.42% trong 1hPage on-call ngay
2 — page6h30min65% trong 6hPage on-call ngay
3 — ticket3 ngày6h110% trong 3 ngàyTicket, giờ hành chính

Công thức derive threshold:

$$ T = \frac{\text{budget_fraction}}{\text{window_fraction_of_SLO_period}} $$

Ví dụ Tier 1: muốn 2% budget burned in 1h → T = 0.02 / (1h / 720h) = 14.4.

7.3 Recovery behavior

Khi sự cố hết:

  • Short window về dưới threshold trong ~5 phút → AND condition false → alert stop.
  • Long window vẫn còn cao thêm 30-60 phút, nhưng AND đã false → không spam.

Đây là lý do AND quan trọng: alert recover nhanh.

7.4 Prometheus implementation

groups:
- name: slo-alerts
  rules:
  - alert: SLO_BurnRate_Tier1
    expr: |
      (
        sum(rate(http_requests_total{status=~"5..|429"}[1h]))
        / sum(rate(http_requests_total[1h]))
      ) / (1 - 0.999) >= 14.4
      AND
      (
        sum(rate(http_requests_total{status=~"5..|429"}[5m]))
        / sum(rate(http_requests_total[5m]))
      ) / (1 - 0.999) >= 14.4      
    labels: {severity: page, tier: "1"}
    annotations:
      summary: "Burn rate ≥ 14.4 over both 1h and 5m windows"
      runbook: "https://runbooks.example.com/slo-burn"

  - alert: SLO_BurnRate_Tier2
    expr: |
      (sum(rate(http_requests_total{status=~"5..|429"}[6h]))
       / sum(rate(http_requests_total[6h]))) / (1 - 0.999) >= 6
      AND
      (sum(rate(http_requests_total{status=~"5..|429"}[30m]))
       / sum(rate(http_requests_total[30m]))) / (1 - 0.999) >= 6      
    labels: {severity: page, tier: "2"}

  - alert: SLO_BurnRate_Tier3
    expr: |
      (sum(rate(http_requests_total{status=~"5..|429"}[3d]))
       / sum(rate(http_requests_total[3d]))) / (1 - 0.999) >= 1
      AND
      (sum(rate(http_requests_total{status=~"5..|429"}[6h]))
       / sum(rate(http_requests_total[6h]))) / (1 - 0.999) >= 1      
    labels: {severity: ticket, tier: "3"}

8. Khi nào dùng SLO-based vs anomaly detection

Metric X
├── Proportional với user pain?
│   ├── YES → SLI candidate → SLO-based MWMBR alert
│   └── NO → continue
├── Saturation signal (CPU, mem, queue, FD count)?
│   ├── YES → ticket alert (low priority) hoặc capacity dashboard, không page
│   └── NO → continue
└── Leading indicator (drift, gradual change)?
    └── YES → anomaly detection (W1) trên metric, alert ticket khi sustained
MetricSLI?Loại alert
HTTP 5xx rateSLO MWMBR
Request latency p99SLO MWMBR
Kafka consumer lag✅ (freshness SLI)SLO MWMBR
CPU usageSaturation, no page
Memory usageSaturation, no page
Disk free %Operational ticket
Log error cluster volume (Drain3)Anomaly alert, no page

9. Bài tập

9.0 Setup

Download pack:

wget https://learning-notes-dz2.pages.dev/aiops-w3/lab/w3-d1-pack.zip
unzip w3-d1-pack.zip -d w3-d1-pack/
cd w3-d1-pack/

Install deps + generate 3-day synthetic data (chạy 1 lần, ~30s, output ~300MB):

uv venv --python 3.12
uv pip install pyyaml
uv run python generate_data.py

9.1 Cấu trúc pack

w3-d1-pack/
├── generate_data.py          # sinh 3-day synthetic log (đã chạy ở §9.0)
├── docker-compose.yml        # Prometheus 2.50 + Alertmanager 0.27 + Grafana 10.4
├── configs/                  # prometheus.yml + alertmanager.yml
├── scripts/
│   ├── compute_baseline.py   # extract baseline SLI từ log
│   ├── validate.py           # compare alert rules với incident_window.csv
│   └── prometheus_replay.sh  # (optional) push metric vào Prometheus
├── sample-solution/          # SLO + alert YAML mẫu — tham khảo, KHÔNG copy
└── data/                     # sinh sau khi chạy generate_data.py
    ├── access_log.jsonl      # ~2M event nginx access log
    ├── db_query_log.jsonl    # ~170k pg_stat_statements sample
    ├── frontend_rum.jsonl    # ~520k RUM page load event
    ├── topology.yaml         # service map: frontend → api → db
    └── incident_window.csv   # 5 ground-truth incident

Stack giả định: 3-tier service — React frontend (CDN) + FastAPI 4-instance + Postgres primary/replica. Peak ~15 req/s sampled traffic, e-commerce context.

Log schema (mỗi dòng 1 JSON event):

// access_log.jsonl
{"ts": "2026-06-01T00:00:00+00:00", "method": "GET", "path": "/api/orders",
 "status": 200, "latency_ms": 142}

// db_query_log.jsonl
{"ts": "2026-06-01T00:00:00+00:00", "query": "SELECT ...",
 "duration_ms": 38, "success": true, "rows": 17}

// frontend_rum.jsonl
{"ts": "2026-06-01T00:00:00+00:00", "page": "/products",
 "dom_ready_ms": 1240, "js_error": false, "network_error": false}

incident_window.csv (ground truth, dùng để validate):

incident_id,layer,severity,start_utc,end_utc,fail_rate_multiplier
1,api,tier1,2026-06-01T03:00:00+00:00,2026-06-01T03:08:00+00:00,100

9.2 Bước 1 — Compute baseline

uv run python scripts/compute_baseline.py --data data/ --out baseline.json

Output:

{
  "frontend": {"success_rate_p50": 0.992, "success_rate_p99": 0.974, "events_per_day": 171428},
  "api":      {"success_rate_p50": 0.997, "success_rate_p99": 0.989, "events_per_day": 714285},
  "db":       {"success_rate_p50": 0.999, "success_rate_p99": 0.996, "events_per_day": 114285}
}

Dùng baseline.json làm input cho mọi quyết định ở step sau.

9.3 Bước 2 — Viết slo_spec.yaml

Schema bắt buộc (mỗi service 1 entry, tổng 3 entry):

version: 1
services:
  - name: <frontend|api|db>
    sli:
      name: <ví dụ frontend_availability>
      kind: <availability|latency|freshness|throughput>
      formula: "<mô tả plain text: numerator / denominator>"
      promql_good: "<promql đếm event thoả SLO>"
      promql_total: "<promql đếm tổng event>"
      source: <log file path hoặc Prometheus metric>
    slo:
      target: <float ∈ [0.9, 0.9999]>     # e.g. 0.999 = 99.9%
      window_days: 30
    budget:
      total_events_per_month: <int>        # từ baseline.json × 30
      allowed_failures_per_month: <int>    # = (1 - target) × total
      downtime_minutes_equivalent: <int>   # = allowed_failures / req_per_minute

9.4 Bước 3 — Viết burn_rate_alerts.yaml

3 tier MWMBR cho mỗi service → tổng 9 alert rule. Template §7.4.

Verify syntax:

promtool check rules burn_rate_alerts.yaml
# Expected: 9 rules found, 0 errors

9.5 Bước 4 — Validate trên replay data

bash scripts/prometheus_replay.sh           # replay 7-day log vào Prometheus
python scripts/validate.py \
  --rules burn_rate_alerts.yaml \
  --truth data/incident_window.csv \
  --baseline-rule "error_rate > 0.01 for 5m" \
  --out validation_report.json

Output schema:

{
  "static_baseline": {"fired": 43, "tp": 4, "fp": 39, "fn": 0, "mttd_p50_s": 252},
  "your_mwmbr":      {"fired": 6,  "tp": 4, "fp": 2,  "fn": 0, "mttd_p50_s": 287},
  "noise_reduction_pct": 86.0,
  "mttd_delta_s": 35,
  "verdict": "pass"
}

Acceptance: noise_reduction_pct ≥ 70 AND mttd_delta_s < 60 AND your_mwmbr.fn = 0.

Nếu fail → tune threshold, đổi window size, hoặc đổi SLO target. Iterate.

9.6 Bước 5 — Viết DESIGN.md

Trả lời 5 câu hỏi, mỗi câu 100-200 từ, bắt buộc reference số từ baseline.json hoặc validation_report.json:

  1. SLI choice cho frontend. Tại sao chọn metric X thay vì Y? Frontend RUM cho 4 candidate signal (page load time, DOM ready, JS error rate, network error rate). Chọn cái nào, vì sao loại 3 cái còn lại?
  2. SLO target cho api. Tại sao 99.9% chứ không 99% hoặc 99.99%? Cost của mỗi tier (§3.2) so với baseline hiện tại 99.7% (từ baseline.json).
  3. Latency threshold p99. Bạn cut latency ở mốc nào (200ms? 500ms? 1s?)? Plot distribution latency 7-day (text/table OK), defend choice.
  4. 4xx exclusion. Tại sao loại 4xx ra khỏi error count (trừ 429)? Có log endpoint nào có rate 4xx > 5% mà không phải hệ thống lỗi không? Reference data.
  5. MWMBR tuning. Dùng Google default (14.4, 6, 1) hay tune? Nếu tune, dựa vào ảnh hưởng đến noise_reduction_pctfn thế nào?

9.7 Bước 6 — Viết SUBMIT.md

# W3-D1 Submission — <your name>

## 3 thứ tôi học được
1. ...
2. ...
3. ...

## 1 thứ vẫn chưa rõ
...

## 1 trade-off trong SLO decision của tôi mà tôi không chắc
...

## Validation report
- noise_reduction_pct: __%
- mttd_delta_s: __s
- false_negative: __
- verdict: __

9.8 Acceptance checklist

  • slo_spec.yaml parse được, có đủ 3 service, target ∈ [0.9, 0.9999]
  • burn_rate_alerts.yaml có 9 rule, promtool check rules pass với 0 error
  • validation_report.json đạt acceptance ở §9.5 (noise ≥ 70%, MTTD delta < 60s, FN = 0)
  • DESIGN.md trả lời cả 5 câu, mỗi câu có ít nhất 1 số từ baseline/validation
  • SUBMIT.md đủ 4 section

10. Anti-patterns

Anti-patternHậu quả
CPU làm SLIFalse positive khi user OK; false negative khi user khổ
SLO 99.999% cho mọi serviceMiss SLO ngay tháng đầu → bị ignore
Single-window alertSpam khi window ngắn; chậm + dính lâu khi window dài
Đếm 4xx vào failSLI bị bot/scraper kéo xuống
1 SLO cho cả 3-tier serviceMất visibility từng layer
SLO chỉ trong YAML, không có dashboardKhông ai review → SLO chết
Bỏ short window trong MWMBRAlert dính 1-6h sau khi sự cố hết

11. Deliverable summary

FileMô tả ngắnSpec chi tiết
slo_spec.yaml3 service × SLI+SLO+budget§9.3
burn_rate_alerts.yaml9 Prometheus alert rule (3 tier × 3 service)§9.4
validation_report.jsonKết quả compare MWMBR vs static baseline§9.5
DESIGN.mdTrả lời 5 câu defend choice§9.6
SUBMIT.mdReflection 4-section§9.7

Đường dẫn nộp: aiops-<tên>/w3/d1/.


12. References

SourceTopicURL
Beyer et al. SRE Book Ch 4SLO foundationshttps://sre.google/sre-book/service-level-objectives/
SRE Workbook Ch 2Implementing SLOshttps://sre.google/workbook/implementing-slos/
SRE Workbook Ch 5Alerting on SLOs (MWMBR công thức gốc)https://sre.google/workbook/alerting-on-slos/
Coursera Google CloudSRE: Measuring and Managing Reliability (4-week)https://www.coursera.org/learn/site-reliability-engineering-slos
Prometheus docsAlerting rules syntaxhttps://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/
Grafana LabsSLO dashboard exampleshttps://grafana.com/grafana/dashboards/?dataSource=prometheus&search=slo