SLO & SLA #
Monitoring memperlihatkan bahwa service lambat. Alert memberitahu bahwa latensi naik. Tapi pertanyaan yang paling penting bagi bisnis adalah: seberapa banyak insiden yang bisa kita toleransi sebelum melanggar komitmen ke pelanggan? SLO (Service Level Objective) dan SLA (Service Level Agreement) memberikan jawaban yang terukur dan terstruktur. SLO adalah target internal yang dijaga oleh tim engineering; SLA adalah janji eksternal ke pelanggan dengan konsekuensi hukum/commercial jika dilanggar. Ansible bisa mengotomasi seluruh infrastruktur pengukurannya — dari recording rules di Prometheus hingga dashboard SLO di Grafana — sehingga kepatuhan terhadap target selalu terukur secara real-time dan laporan bulanan ke pelanggan bisa di-generate tanpa pekerjaan manual.
Konsep Dasar: SLI, SLO, Error Budget, dan SLA #
Empat konsep ini sering tertukar, padahal masing-masing punya peran yang berbeda dalam hierarki:
flowchart TD
SLI["SLI<br/>Service Level Indicator<br/>metrik aktual yang diukur"] --> SLO["SLO<br/>Service Level Objective<br/>target yang ingin dicapai"]
SLO --> EB["Error Budget<br/>100% - SLO target<br/>margin kegagalan yang ditoleransi"]
EB --> BR["Burn Rate<br/>seberapa cepat budget terbakar"]
EB --> SLA["SLA<br/>Service Level Agreement<br/>kontrak formal ke pelanggan"]
SLI -. "contoh" .-> SLIex["99.5% request success rate"]
SLO -. "contoh" .-> SLOex["target 99.9%<br/>selama 30 hari"]
EB -. "contoh" .-> EBex["0.1% x 30 hari<br/>= ~43 menit downtime"]
BR -. "contoh" .-> BRex["1x = normal<br/>14x = budget habis dalam ~2 hari"]
SLA -. "contoh" .-> SLAex["99.5% uptime<br/>refund 10% biaya bulanan<br/>jika dilanggar"]
Definisi formal yang perlu kita pegang:
- SLI (Service Level Indicator) — metrik aktual yang diukur. Contoh: persentase request dengan response code non-5xx dalam window 5 menit, atau latensi P99 dalam 1 jam terakhir. SLI selalu terukur dan bisa di-query dari Prometheus.
- SLO (Service Level Objective) — target yang ingin dicapai untuk SLI tersebut. Contoh: SLI
success rateharus ≥ 99.9% dalam window 30 hari. SLO adalah kontrak internal antara tim engineering dengan product/business. - Error Budget — margin kegagalan yang diizinkan. Jika SLO 99.9%, error budget = 0.1%. Dalam 30 hari, ini berarti 0.1% × 30 × 24 × 60 = 43.2 menit downtime. Tim boleh gagal sampai sebanyak itu; setelah lewat, harus ada tindakan (postmortem, moratorium fitur, refactor).
- SLA (Service Level Agreement) — kontrak formal ke pelanggan dengan konsekuensi komersial. Biasanya SLO lebih ketat dari SLA: jika SLA 99.5% dan SLO 99.9%, tim punya margin 0.4% untuk insiden yang tidak melanggar SLA.
Jangan pernah menetapkan SLO sama dengan atau lebih ketat dari SLA. SLA adalah janji yang jika dilanggar berkonsekuensi kompensasi; SLO adalah target internal. Jika SLO = SLA, kita tidak memiliki buffer saat ada insiden — pelanggan akan mengajukan keluhan setiap kali target internal tidak tercapai, yang seharusnya masih dalam margin yang ditoleransi.
Memilih SLI yang Tepat #
SLI yang dipilih harus merepresentasikan pengalaman pengguna, bukan metrik internal yang mudah dicapai. Tiga kategori SLI yang paling umum:
| Kategori SLI | Metrik | Cocok untuk | Kapan TIDAK cocok |
|---|---|---|---|
| Availability | Persentase request yang berhasil (non-5xx) dalam window | API HTTP, web service, database yang menerima query | Service yang secara desain return error untuk input invalid (4xx bukan masalah) |
| Latency | Persentase request dengan response time di bawah threshold | User-facing service, real-time API, payment processing | Background job, batch processing (latensi tidak diperhatikan user) |
| Throughput | Request per detik yang berhasil diproses | Service yang harus handle high traffic, data pipeline | Service dengan traffic rendah dan tidak dipredict |
| Freshness | Umur data yang tersedia saat di-query | Data pipeline, analytics, dashboard yang merefresh data | Service yang selalu return data real-time (freshness selalu 0) |
| Correctness | Persentase output yang benar dibanding ground truth | ML inference, calculation engine, ETL | Service sederhana yang tidak ada kemungkinan “incorrect” output |
Pemilihan SLI adalah keputusan produk, bukan teknis. Tanyakan ke product manager: “metrik apa yang paling mewakili user senang dengan service ini?” Jawaban yang benar biasanya availability atau latency — bukan CPU usage.
Recording Rules untuk SLI yang Efisien #
Kalkulasi SLI yang kompleks bisa sangat mahal jika dikalkulasi setiap kali di-query dari dashboard atau alert. Recording rules menghitung dan menyimpan hasilnya secara berkala — hasilnya adalah time series baru yang bisa di-query dengan murah:
# roles/prometheus/tasks/slo-rules.yml
---
- name: Deploy recording rules untuk SLO
template:
src: rules/slo-recording.yml.j2
dest: /etc/prometheus/rules/slo-recording.yml
owner: prometheus
mode: '0644'
validate: promtool check rules %s
notify: Reload Prometheus
{# templates/rules/slo-recording.yml.j2 #}
groups:
# Grup 1: SLI metrics (dasar pengukuran)
- name: slo_recording_rules
interval: 30s
rules:
# SLI: Availability — persentase request yang berhasil (non-5xx)
- record: job:http_requests_total:success_rate5m
expr: >
sum(rate(http_requests_total{status!~"5.."}[5m])) by (job, service)
/
sum(rate(http_requests_total[5m])) by (job, service)
# SLI: Latency P99 dari histogram
- record: job:http_request_duration_seconds:p99_5m
expr: >
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (job, service, le)
)
# SLI: Latency P95
- record: job:http_request_duration_seconds:p95_5m
expr: >
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (job, service, le)
)
# Grup 2: Error budget metrics (turunan dari SLI)
- name: error_budget_rules
interval: 30s
rules:
# Error budget burn rate (multi-window, multi-burn-rate)
# Page alert jika burn rate 14x lebih cepat dari normal — akan habis dalam ~2 hari
- record: job:error_budget_burn_rate:1h
expr: >
(1 - job:http_requests_total:success_rate5m)
/
(1 - {{ slo_availability_target | default(0.999) }})
# Sisa error budget dalam 30 hari terakhir
- record: job:error_budget_remaining:30d
expr: >
1 - (
(1 - avg_over_time(job:http_requests_total:success_rate5m[30d]))
/
(1 - {{ slo_availability_target | default(0.999) }})
)
# Prediksi kapan error budget akan habis jika burn rate saat ini bertahan
- record: job:error_budget_exhaustion_days:current
expr: >
(1 - {{ slo_availability_target | default(0.999) }})
/
(1 - job:http_requests_total:success_rate5m) * 30
Tiga group yang perlu kita pahami: (1) SLI metrics adalah pengukuran mentah — selalu kalkulasi ulang dari data asli. (2) Error budget metrics adalah turunan — kalkulasi dari SLI metrics. (3) Prediksi membantu tim merencanakan — “jika kondisi sekarang bertahan, budget habis dalam X hari”.
Selalu simpan SLI di level job/service, bukan instance. SLO adalah tentang service secara keseluruhan — instance tunggal yang gagal bukan pelanggaran SLO jika service lain masih sehat dan load balancer melakukan failover dengan benar.
Alert Berbasis Error Budget (Multi-Window, Multi-Burn-Rate) #
Alert tradisional (CPU > 80%, latensi > 200ms) sering memunculkan false alarm. Alert berbasis error budget jauh lebih presisi — hanya alert saat error budget benar-benar terbakar dengan cepat. Pola multi-window, multi-burn-rate dari Google SRE workbook adalah standar industri:
{# templates/rules/slo-alerts.yml.j2 #}
groups:
- name: slo_alerts
rules:
# === PAGE ALERT (critical, butuh respons dalam 15 menit) ===
# Dua window pendek — burn rate tinggi dalam window cepat
- alert: SLO_HighBurnRate_Fast
expr: >
job:error_budget_burn_rate:1h > 14.4
and
job:error_budget_burn_rate:5m > 14.4
for: 2m
labels:
severity: critical
slo: availability
team: platform
annotations:
summary: "SLO burn rate sangat tinggi: {{ '{{' }} $labels.service {{ '}}' }}"
description: >
Burn rate {{ '{{' }} $value | humanize {{ '}}' }}x dari normal.
Error budget akan habis dalam ~2 hari jika burn rate ini bertahan.
RESPON DALAM 15 MENIT.
runbook_url: "https://wiki.company.com/runbooks/slo-burn-fast"
dashboard_url: "https://grafana.company.com/d/slo-burn?var-service={{ '{{' }} $labels.service {{ '}}' }}"
# === TICKET ALERT (warning, respon dalam working hours) ===
# Window sedang — burn rate tinggi tapi tidak urgent
- alert: SLO_MediumBurnRate
expr: >
job:error_budget_burn_rate:6h > 6
and
job:error_budget_burn_rate:30m > 6
for: 15m
labels:
severity: warning
slo: availability
annotations:
summary: "SLO burn rate tinggi: {{ '{{' }} $labels.service {{ '}}' }}"
description: >
Burn rate {{ '{{' }} $value | humanize {{ '}}' }}x dari normal dalam 6 jam terakhir.
Error budget akan habis dalam ~5 hari. PERLU DISELIDIKI HARI INI.
runbook_url: "https://wiki.company.com/runbooks/slo-burn-medium"
# === SLOW BURN (warning, respon dalam minggu) ===
# Window panjang — burn rate rendah tapi berkelanjutan
- alert: SLO_SlowBurnRate
expr: >
job:error_budget_burn_rate:3d > 1
and
job:error_budget_burn_rate:6h > 1
for: 1h
labels:
severity: warning
slo: availability
annotations:
summary: "SLO slow burn terdeteksi: {{ '{{' }} $labels.service {{ '}}' }}"
description: >
Burn rate {{ '{{' }} $value | humanize {{ '}}' }}x dari normal selama 3 hari.
Error budget akan habis dalam ~30 hari. RENCANAKAN PERBAIKAN.
runbook_url: "https://wiki.company.com/runbooks/slo-burn-slow"
Logika di balik multi-window: jika burn rate tinggi konsisten di window pendek DAN window panjang, alarm valid. Ini menghindari false positive dari satu window pendek (misalnya traffic spike 5 menit) atau window panjang (misalnya metric scrape error sesaat).
Tabel di bawah menjelaskan threshold burn rate yang umum digunakan:
| Burn Rate | Window | Alert Level | Tindakan | Implikasi |
|---|---|---|---|---|
| 14.4x | 1h + 5m | Page (critical) | Drop everything, investigasi sekarang | Budget habis dalam ~2 hari |
| 6x | 6h + 30m | Ticket (warning) | Investigasi hari ini, fix minggu ini | Budget habis dalam ~5 hari |
| 3x | 24h + 2h | Ticket (warning) | Buat tiket, rencanakan fix | Budget habis dalam ~10 hari |
| 1x | 3d + 6h | Slow burn (warning) | Tambah ke backlog | Budget habis tepat di akhir periode (30 hari) |
Decision Tree: Pilih SLO Target yang Realistis #
Pemilihan target SLO bukan angka arbitrer. Trade-off utama: target lebih tinggi = lebih reliable untuk user, tapi lebih mahal (butuh redundancy, faster rollback, more SRE). Decision tree berikut membantu menentukan target yang sesuai:
flowchart TD
A["Baru mulai<br/>definisikan SLO"] --> B{"Ada data<br/>historical<br/>reliability?"}
B -- "Ya" --> C{"Lihat percentile<br/>terburuk 30 hari<br/>terakhir"}
B -- "Tidak" --> D["Mulai ukur SLI<br/>selama 30 hari<br/>sebelum set SLO"]
C --> E{"P99 latency<br/>saat ini<br/>di mana?"}
E -- "50ms" --> F["Target SLO:<br/>99.9%<br/>latency 100ms"]
E -- "200ms" --> G["Target SLO:<br/>99.5%<br/>latency 500ms"]
E -- "2 detik" --> H["Target SLO:<br/>99%<br/>latency 5 detik"]
D --> I["Setelah 30 hari<br/>data terkumpul"]
I --> C
F --> J{"Apakah ada<br/>SLA ke<br/>pelangan?"}
G --> J
H --> J
J -- "Ya" --> K["SLA = SLO - 0.3%<br/>ada buffer insiden"]
J -- "Tidak" --> L["SLO adalah<br/>target internal<br/>saja"]
Empat pertanyaan yang harus dijawab sebelum set SLO:
- Apa reliability saat ini? — Jika service sudah jalan di 99.5% dalam 30 hari terakhir, set SLO 99.5% (realistis) bukan 99.99% (mustahil tanpa improvement).
- Apa impact of failure? — Payment service yang down = kehilangan revenue langsung. Blog yang down = inconvenience. Target SLO harus proportional.
- Berapa biaya untuk naik 0.1%? — Dari 99.9% ke 99.95% mungkin butuh multi-region active-active, redundancy database, dan tim on-call 24/7. Apakah bisnis mau bayar?
- Apa SLA yang sudah dijanjikan ke pelanggan? — SLO internal harus lebih ketat dari SLA eksternal untuk punya buffer.
Dashboard SLO di Grafana #
Dashboard SLO yang baik menampilkan semua yang dibutuhkan untuk trust bahwa service memenuhi target. Rekomendasi struktur panel:
| Panel | Tipe | Query | Tujuan |
|---|---|---|---|
| Current Availability | Stat (gauge) | avg(job:http_requests_total:success_rate5m) |
Angka real-time “sekarang service ini sehat” |
| Error Budget Remaining | Stat (gauge) | job:error_budget_remaining:30d |
Sisa budget dalam periode 30 hari — angka paling penting untuk prioritas |
| 30-Day Availability Trend | Timeseries | avg_over_time(job:http_requests_total:success_rate5m[30d]) |
Trend availability dengan garis target SLO |
| Latency P50/P95/P99 | Timeseries | job:http_request_duration_seconds:p99_5m |
Distribusi latensi dengan garis threshold |
| Burn Rate (multi-window) | Timeseries | job:error_budget_burn_rate:1h, :6h, :24h |
Seberapa cepat budget terbakar di berbagai window |
| SLO Status per Service | Table | topk(20, job:error_budget_remaining:30d) |
Tabel semua service yang di-track, sort by error budget |
Untuk deploy dashboard SLO via Ansible:
- name: Deploy SLO dashboard ke Grafana
copy:
src: files/dashboards/slo-overview.json
dest: /var/lib/grafana/dashboards/slo-overview.json
owner: grafana
mode: '0640'
notify: Reload Grafana dashboards
Pattern penting: error budget remaining harus menjadi panel paling prominen — bukan success rate, bukan latency. Error budget adalah angka yang langsung menjawab “apakah kita aman bulan ini?”.
Sequence Diagram: Alur SLO dari Pengukuran ke Keputusan #
Untuk memahami bagaimana data SLO mengalir dari metrik mentah ke keputusan bisnis, perhatikan sequence di bawah:
sequenceDiagram
participant App as Aplikasi
participant Prom as Prometheus
participant RR as Recording Rules
participant AR as Alert Rules
participant AM as Alertmanager
participant Dash as Grafana SLO Dashboard
participant PM as Product Manager
App->>Prom: "Expose /metrics (request count, duration, status)"
Prom->>Prom: "Scrape setiap 15s"
Prom->>RR: "Evaluate recording rules (setiap 30s)"
RR->>Prom: "Simpan SLI & error budget series"
Prom->>AR: "Evaluate alert rules (setiap 15s)"
AR->>AR: "Hitung burn rate multi-window"
AR->>AM: "Kirim alert jika burn rate > threshold"
AM->>AM: "Route alert by severity"
AM-->>PM: "PagerDuty / Slack notification"
PM->>Dash: "Buka SLO dashboard (mingguan review)"
Dash->>Prom: "Query SLI series"
Prom-->>Dash: "Data 30 hari terakhir"
Dash-->>PM: "Visualisasi error budget, burn rate, trend"
PM->>PM: "Keputusan:"
Note over PM: "Budget > 50%? Aman, lanjut roadmap\nBudget 20-50%? Waspada, defer fitur non-kritis\nBudget < 20%? Stop fitur, fokus reliability"
PM->>AR: "Update threshold SLO jika perlu"
PM->>App: "Trigger refactor jika slow burn"
Pola yang penting dari sequence ini: SLO yang terukur dengan baik memungkinkan product manager membuat keputusan berdasarkan data, bukan intuisi. Tanpa angka error budget, meeting mingguan biasanya jadi perdebatan “service-nya sehat atau tidak” yang tidak ada ujungnya.
Laporan SLA Otomatis #
Untuk SLA yang dijanjikan ke pelanggan, laporan bulanan wajib dikirim tepat waktu. Ansible + Prometheus API bisa mengotomasi pengumpulan data dan generate laporan PDF/HTML:
# playbooks/generate-sla-report.yml
---
- name: Generate laporan SLA bulanan
hosts: localhost
vars:
report_month: "{{ lookup('pipe', 'date +%Y-%m') }}"
prometheus_url: "https://prometheus.company.com"
slo_availability_target: 0.999
slo_latency_target_ms: 200
tasks:
- name: Ambil data availability bulan ini
uri:
url: "{{ prometheus_url }}/api/v1/query_range"
method: GET
body_format: form-urlencoded
body:
query: 'avg_over_time(job:http_requests_total:success_rate5m{service="myapp"}[30d])'
start: "{{ lookup('pipe', 'date -d\"first day of this month\" +%s') }}"
end: "{{ lookup('pipe', 'date +%s') }}"
step: "3600"
headers:
Authorization: "Bearer {{ vault_prometheus_token }}"
return_content: true
register: availability_data
no_log: true
- name: Ambil data latency P99 bulan ini
uri:
url: "{{ prometheus_url }}/api/v1/query_range"
method: GET
body_format: form-urlencoded
body:
query: 'avg_over_time(job:http_request_duration_seconds:p99_5m{service="myapp"}[30d])'
start: "{{ lookup('pipe', 'date -d\"first day of this month\" +%s') }}"
end: "{{ lookup('pipe', 'date +%s') }}"
step: "3600"
headers:
Authorization: "Bearer {{ vault_prometheus_token }}"
return_content: true
register: latency_data
no_log: true
- name: Kalkulasi availability rate rata-rata
set_fact:
avg_availability: >-
{{ (availability_data.json.data.result[0].values
| map(attribute=1) | map('float') | sum
/ availability_data.json.data.result[0].values | length * 100) | round(4) }}
- name: Kalkulasi latency P99 rata-rata
set_fact:
avg_latency_ms: >-
{{ (latency_data.json.data.result[0].values
| map(attribute=1) | map('float') | sum
/ latency_data.json.data.result[0].values | length * 1000) | round(2) }}
- name: Tentukan status SLA
set_fact:
sla_status: >-
{{ 'COMPLIANT' if (avg_availability | float >= 99.9 and avg_latency_ms | float < slo_latency_target_ms | float)
else 'BREACH' }}
- name: Generate file laporan Markdown
template:
src: sla-report.md.j2
dest: "/var/reports/sla-{{ report_month }}-{{ inventory_hostname }}.md"
- name: Generate PDF dari Markdown
command: >
pandoc /var/reports/sla-{{ report_month }}-{{ inventory_hostname }}.md
-o /var/reports/sla-{{ report_month }}-{{ inventory_hostname }}.pdf
--pdf-engine=xelatex
-V geometry:margin=1in
--toc
when: sla_install_pandoc | default(false)
- name: Kirim laporan ke email tim
community.general.mail:
host: "{{ smtp_host }}"
port: "{{ smtp_port }}"
to: "{{ sla_report_recipients }}"
subject: "Laporan SLA {{ report_month }} — {{ sla_status }}"
body: "{{ lookup('file', '/var/reports/sla-' + report_month + '-' + inventory_hostname + '.md') }}"
attach:
- "/var/reports/sla-{{ report_month }}-{{ inventory_hostname }}.md"
when: sla_send_email | default(false)
Template laporan SLA yang informatif:
{# sla-report.md.j2 #}
# Laporan SLA — {{ report_month }}
**Periode:** 1 {{ report_month }} — {{ lookup('pipe', 'date +%d %B %Y') }}
**Status:** `{{ sla_status }}`
## Ringkasan
| Metrik | Target SLA | Aktual | Status |
|---|---|---|---|
| Availability | ≥ 99.9% | {{ avg_availability }}% | {{ '✓' if avg_availability | float >= 99.9 else '✗' }} |
| Latency P99 | ≤ {{ slo_latency_target_ms }}ms | {{ avg_latency_ms }}ms | {{ '✓' if avg_latency_ms | float < slo_latency_target_ms else '✗' }} |
## Insiden Signifikan
{% for incident in monthly_incidents | default([]) %}
- **{{ incident.date }}** — {{ incident.summary }} (durasi: {{ incident.duration }})
{% endfor %}
_(Tidak ada insiden yang melebihi 5 menit pada periode ini)_
## Tren
Lampirkan grafik availability 30 hari dan grafik latency P99 30 hari
dari dashboard SLO untuk konteks visual.
## Komitmen
Kami {{ 'MEMENUHI' if sla_status == 'COMPLIANT' else 'TIDAK MEMENUHI' }}
komitmen SLA untuk periode {{ report_month }}.
{{ 'Tidak ada kompensasi yang dijadwalkan.' if sla_status == 'COMPLIANT' else 'Tim kami akan mengirim detail kompensasi yang berlaku sesuai kontrak.' }}
Generate laporan SLA via cron job di akhir bulan, bukan manual. Tambahkan0 9 1 * *di crontab untuk menjalankangenerate-sla-report.ymldi tanggal 1 setiap bulan jam 9 pagi. Laporan tersedia sebelum meeting bulanan, dan tidak ada yang lupa generate.
ANTI-PATTERN vs BENAR pada SLO Implementation #
Beberapa jebakan umum saat mengadopsi SLO. Memahaminya di awal akan menghemat waktu berminggu-minggu:
# ANTI-PATTERN: SLO tanpa error budget calculation
# "SLO kita 99.9%" - ok, tapi 99.9% dari apa? Per jam? Per hari? Per bulan?
# Tanpa error budget yang eksplisit, SLO jadi jargon tanpa konsekuensi
# BENAR: definisikan SLO + window + error budget secara eksplisit
# Format: SLI + target + window + error budget
slo_definitions:
- name: api-availability
sli: "percentage of HTTP requests with status < 500"
target: 99.9
window: 30d
error_budget: "43.2 minutes per 30 days" # Eksplisit, bukan hanya angka
owner: platform-team
# ANTI-PATTERN: alert yang langsung page saat SLO sedikit di bawah target
- alert: SLOBreach
expr: job:http_requests_total:success_rate5m < 0.999
for: 1m
labels:
severity: critical
# Masalah: success rate 99.8% dalam 5 menit BUKAN berarti SLO 99.9%/30d dilanggar
# Ini false positive yang akan bombardir on-call
# BENAR: alert berdasarkan burn rate, bukan absolute value
- alert: SLO_HighBurnRate_Fast
expr: >
job:error_budget_burn_rate:1h > 14.4
and
job:error_budget_burn_rate:5m > 14.4
for: 2m
labels:
severity: critical
# Alert hanya jika budget terbakar CEPAT (akan habis dalam 2 hari)
# SLO 99.8% sebentar itu bukan masalah; SLO 99.5% selama 6 jam = masalah
# ANTI-PATTERN: target SLO yang tidak realistis
- alert: CriticalServiceDown
expr: up{job="critical"} == 0
# Implikasi: setiap downtime 1 menit pun page on-call
# Target internal 100% availability = tidak ada error budget = setiap insiden adalah "SLO breach"
# On-call burnout dalam 3 bulan
# BENAR: set SLO yang menyisakan margin
# Realita: 99.99% availability butuh multi-region active-active, redundansi 3x, on-call 24/7
# Untuk kebanyakan service, 99.9% adalah sweet spot antara reliability dan biaya
# Definisi "down" juga harus jelas: 5xx > 1% dari traffic? Atau single endpoint fail?
slo_target: 99.9 # Realistis
sla_target: 99.5 # Lebih longgar dari SLO
error_budget_30d: 43m # Tim punya margin
# ANTI-PATTERN: SLO yang hanya ada di spreadsheet
# "Target kita 99.9%" - ditulis di Google Sheet, tidak terlihat di dashboard
# Tim tidak tahu apakah mereka on-track sampai akhir bulan
# BENAR: SLO visible di dashboard real-time
# - Panel "Error Budget Remaining" prominen di dashboard service
# - Alert page on-call jika burn rate tinggi
# - Status SLO di-review mingguan di meeting
# - Laporan SLA ke pelanggan di-generate otomatis dari data real-time
Tiga pola yang bisa diambil: (1) SLO tanpa error budget hanya angka — error budget yang eksplisit membuat SLO punya konsekuensi. (2) Alert berdasarkan absolute value = false positive — burn rate alert merefleksikan impact ke SLO. (3) SLO yang tidak terlihat = SLO yang dilupakan — dashboard dan alert membuat SLO bagian dari daily operations.
Integrasi SLO dengan Alert dan Incident Response #
SLO yang terdefinisi dengan baik punya implikasi langsung ke alert policy dan incident handling. Tiga koneksi kunci:
-
Burn rate alert → runbook linkage — setiap alert burn rate punya
runbook_urlyang menjelaskan langkah diagnosis dan mitigasi. Lihat Alerting untuk detail tentang alert routing. -
SLO violation → incident severity classification — saat SLO dilanggar, tentukan severity incident berdasarkan berapa banyak error budget yang terbakar:
- Page alert (14x burn rate) = severity 1 incident, butuh on-call immediate
- Ticket alert (6x burn rate) = severity 2, fix dalam working hours
- Slow burn (1x untuk 3 hari) = severity 3, backlog item
-
Error budget policy → feature freeze — saat error budget tinggal < 20%, tim biasanya menyetujui “feature freeze” — semua engineering effort difokuskan ke reliability, bukan fitur baru. Ini keputusan product, bukan teknis — playbook bisa diotomasi untuk notifikasi.
Detail lebih lanjut tentang incident response workflow ada di Incident Response. Untuk setup Prometheus yang menjadi dasar pengukuran SLI, lihat Monitoring.
Testing SLO Alert Rules #
Sama seperti alert rules biasa, SLO alert rules harus di-test untuk memastikan threshold dan window menghasilkan alert yang tepat. Pakai promtool test rules:
# tests/slo-alerts.test.yml
rule_files:
- /etc/prometheus/rules/slo-recording.yml
- /etc/prometheus/rules/slo-alerts.yml
evaluation_interval: 1m
tests:
# Test 1: SLO alert TIDAK firing saat error rate rendah
- interval: 1m
name: "low error rate stays calm"
input_series:
- series: 'http_requests_total{job="api",status="200"}'
values: '9990x60'
- series: 'http_requests_total{job="api",status="500"}'
values: '10x60' # 0.1% error rate — di bawah SLO 99.9%
alert_rule_test:
- eval_time: 1h
alertname: SLO_HighBurnRate_Fast
exp_alerts: [] # Should NOT fire
# Test 2: SLO alert firing saat error rate tinggi
- interval: 1m
name: "high error rate triggers page"
input_series:
- series: 'http_requests_total{job="api",status="200"}'
values: '500x60'
- series: 'http_requests_total{job="api",status="500"}'
values: '500x60' # 50% error rate — disaster
alert_rule_test:
- eval_time: 10m
alertname: SLO_HighBurnRate_Fast
exp_alerts:
- exp_labels:
severity: critical
slo: availability
job: api
exp_annotations:
summary: "SLO burn rate sangat tinggi"
runbook_url: "https://wiki.company.com/runbooks/slo-burn-fast"
# Test 3: Medium burn rate fires ticket alert, not page
- interval: 1m
name: "medium burn rate fires ticket"
input_series:
- series: 'http_requests_total{job="api",status="200"}'
values: '900x360'
- series: 'http_requests_total{job="api",status="500"}'
values: '100x360' # 10% error rate over 6 hours — 6x burn rate
alert_rule_test:
- eval_time: 6h
alertname: SLO_MediumBurnRate
exp_alerts:
- exp_labels:
severity: warning
slo: availability
Jalankan test ini di CI pipeline setiap kali threshold atau window diubah:
promtool test rules /etc/prometheus/tests/slo-alerts.test.yml
Ringkasan #
- SLI → SLO → Error Budget → Burn Rate adalah rantai yang logis: ukur SLI, tetapkan target SLO, hitung error budget yang tersisa, monitor burn rate untuk prediksi habisnya budget.
- SLI harus merepresentasikan pengalaman pengguna — availability dan latency adalah yang paling umum. CPU usage dan memory usage bukan SLI yang baik karena tidak berkorelasi langsung dengan user satisfaction.
- Recording rules untuk kalkulasi SLI yang kompleks — jauh lebih efisien dari query real-time di setiap evaluasi alert atau render dashboard.
- Multi-window burn rate (1h+5m untuk page, 6h+30m untuk ticket, 3d+6h untuk slow burn) menangkap masalah yang cepat maupun lambat tanpa terlalu banyak false alarm — single window = noisy, multi-window = robust.
- Alert berdasarkan burn rate, bukan absolute value — success rate 99.8% dalam 5 menit BUKAN berarti SLO 30 hari dilanggar. Burn rate 14x berarti budget habis dalam 2 hari, itu yang harus page.
- Dashboard SLO harus menampilkan error budget remaining sebagai panel paling prominen — ini adalah angka yang paling bermakna untuk keputusan prioritas engineering.
- SLO lebih ketat dari SLA — SLA 99.5% = SLO 99.9%. Buffer 0.4% memberi ruang untuk insiden yang tidak melanggar kontrak tapi tetap perlu diinvestigasi.
- Laporan SLA otomatis via Ansible + Prometheus API menghilangkan pekerjaan manual penyusunan laporan bulanan ke pelanggan atau manajemen — generate via cron job di awal bulan.
- Test SLO alert rules dengan
promtool test rulesdi CI — pastikan threshold dan window menghasilkan alert yang tepat untuk berbagai skenario error rate.- SLO tanpa error budget hanya angka — error budget yang eksplisit dengan unit waktu (43 menit/bulan) membuat SLO punya konsekuensi dan jadi bahan diskusi di planning meeting.