Sistem modern berjalan di ratusan microservices yang terdistribusi di cloud. Bagaimana memastikan keandalan ketika satu komponen gagal bisa merembet ke mana-mana?
Monolith = Warung Nasi: Satu tempat, semua ada — masak, bayar, meja di satu lokasi. Mudah dikelola, tapi kalau dapur kebakaran, seluruh warung tutup.
Microservices = Mal Besar: Ratusan tenant terpisah — restoran, bank, apotek, masing-masing independen. Kalau satu toko tutup, mal tetap buka. Tapi koordinasi antar tenant (parkir, listrik, keamanan) jauh lebih kompleks.
Tantangan keandalan microservices: kegagalan satu service bisa memicu cascade failure ke service lain yang bergantung padanya — seperti listrik mal mati total hanya karena satu tenant lupa bayar tagihan.
Arsitektur gedung tahan gempa tidak cukup hanya di atas kertas. Insinyur melakukan simulasi gempa buatan untuk membuktikan gedung benar-benar tahan. Chaos Engineering adalah simulasi gempa untuk sistem software: kita sengaja mematikan server, memotong koneksi jaringan, atau menambahkan latency buatan — untuk membuktikan bahwa sistem tetap berfungsi dan memulihkan diri secara otomatis.
Tentukan metrik "sistem berjalan normal": error rate <0.1%, latency p99 <500ms, availability >99.9%. Ini adalah baseline yang harus tetap terjaga selama eksperimen.
Buat hipotesis: "Jika payment service mati, checkout service akan fallback ke antrian dan transaksi tidak hilang." Hypothesis harus spesifik dan bisa diukur.
Gunakan Chaos Monkey, Gremlin, atau LitmusChaos untuk inject failure: kill pod, tambah latency 500ms, simulasi disk full, matikan availability zone. Mulai dari scope kecil!
Monitor apakah metrik menyimpang dari steady state. Apakah error rate naik? Apakah auto-recovery berjalan? Berapa lama sistem pulih (RTO)?
Jika sistem gagal: perbaiki kelemahan (tambah retry, circuit breaker, fallback). Jika hipotesis terbukti: tingkatkan scope eksperimen. Dokumentasikan semua temuan sebagai runbook.
⚠️ Aturan emas Chaos Engineering: Selalu mulai dari staging, bukan production. Saat pertama kali di production, lakukan di jam traffic rendah dengan tim on-call siaga. Chaos Engineering bukan "sengaja merusak" tapi "mengontrol kondisi failure untuk belajar".
Maskapai penerbangan tidak menjanjikan "tidak pernah terlambat" — itu mustahil. Mereka menjanjikan "on-time departure 85% dari penerbangan". Ini adalah SLO (Service Level Objective). SLA adalah kontrak hukumnya dengan konsekuensi jika dilanggar. SLI adalah ukuran aktualnya: berapa persen penerbangan benar-benar on-time bulan ini.
Filosofi Google SRE: 100% reliability is wrong target — sistem yang berusaha 100% uptime akan terlalu lambat berinovasi. Error budget memberikan tim kebebasan untuk deploy fitur baru selama masih dalam batas toleransi.
| Konsep | Definisi | Contoh Nyata (SIAKAD ISTN) | Siapa yang Ukur |
|---|---|---|---|
| SLI Service Level Indicator | Metrik yang mengukur perilaku sistem secara kuantitatif | % request SIAKAD yang direspons dalam 2 detik, diukur per 5 menit | Engineering / Monitoring sistem otomatis |
| SLO Service Level Objective | Target internal yang ingin dicapai berdasarkan SLI | 99% request SIAKAD harus respons <2 detik selama 30 hari rolling | Engineering team — self-commitment |
| SLA Service Level Agreement | Kontrak formal dengan konsekuensi jika SLO dilanggar | ISTN berkomitmen ke mahasiswa: SIAKAD tersedia 99.5% saat UTS/UAS berlangsung | Management / Legal — kontraktual |
| Error Budget Anggaran Error | Sisa "jatah down" yang masih boleh terjadi dalam periode SLO | SLO 99%: boleh down max 7.2 jam/bulan. Jika budget habis → freeze deploy baru. | Engineering & Product team bersama |
Aturan Error Budget: Jika budget habis sebelum akhir bulan → tim harus menghentikan deploy fitur baru dan fokus pada reliability improvement. Budget tersisa = tim bebas berinovasi.
Rumah modern punya MCB (Miniatur Circuit Breaker) per ruangan — kalau ada korsleting di kamar tidur, MCB-nya trip dan hanya kamar itu yang mati, bukan seluruh rumah. Circuit Breaker pattern dalam microservices bekerja sama: kalau payment service gagal terus, circuit breaker "trip" dan request tidak lagi dikirim ke sana — mencegah cascade failure ke checkout service yang memanggil payment.
Supir becak tahu kondisi kendaraannya dari feeling — kurang lebih. Pilot pesawat modern punya ratusan instrumen yang memberikan data real-time: ketinggian, kecepatan, bahan bakar, suhu mesin, setiap sensor aktif. Observability adalah mengubah sistem software dari "supir becak" menjadi "pilot" — kita bisa tahu persis apa yang sedang terjadi di dalam sistem kapan saja.
📌 OpenTelemetry adalah standar terbuka untuk instrumentasi observability. Dengan satu SDK, data Metrics + Logs + Traces bisa dikirim ke berbagai backend (Jaeger, Prometheus, Datadog) tanpa vendor lock-in. Ini standar de-facto industri saat ini.
# ================================================================
# S11409 - Sesi 12: Circuit Breaker & SLO Error Budget
# Dosen: Riadi Marta Dinata, S.Ti., M.Kom. | ISTN Jakarta
# ================================================================
import time, random, statistics
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Callable
# ── CIRCUIT BREAKER IMPLEMENTATION ───────────────────────────
class CBState(Enum):
CLOSED = "CLOSED" # Normal: request berjalan
OPEN = "OPEN" # Gagal: request langsung ditolak
HALF_OPEN = "HALF_OPEN" # Percobaan: tes apakah service pulih
@dataclass
class CircuitBreaker:
name: str
failure_threshold: int = 5 # Gagal berturut → OPEN
recovery_timeout: int = 10 # Detik sebelum coba HALF_OPEN
success_threshold: int = 2 # Sukses berturut di HALF_OPEN → CLOSED
_state: CBState = field(default=CBState.CLOSED, init=False)
_failure_count: int = field(default=0, init=False)
_success_count: int = field(default=0, init=False)
_last_failure_time: float = field(default=0.0, init=False)
_call_count: int = field(default=0, init=False)
@property
def state(self): return self._state
def call(self, func: Callable, *args, **kwargs):
self._call_count += 1
if self._state == CBState.OPEN:
elapsed = time.time() - self._last_failure_time
if elapsed < self.recovery_timeout:
return None, "CIRCUIT_OPEN — Request ditolak (fail-fast)"
else:
self._state = CBState.HALF_OPEN
self._success_count = 0
print(f" [CB:{self.name}] OPEN → HALF_OPEN (mencoba recovery)")
try:
result = func(*args, **kwargs)
self._on_success()
return result, "OK"
except Exception as e:
self._on_failure()
return None, f"FAILED: {e}"
def _on_success(self):
self._failure_count = 0
if self._state == CBState.HALF_OPEN:
self._success_count += 1
if self._success_count >= self.success_threshold:
self._state = CBState.CLOSED
print(f" [CB:{self.name}] HALF_OPEN → CLOSED (service pulih!)")
def _on_failure(self):
self._failure_count += 1
self._last_failure_time = time.time()
if self._failure_count >= self.failure_threshold:
if self._state != CBState.OPEN:
self._state = CBState.OPEN
print(f" [CB:{self.name}] CLOSED → OPEN (terlalu banyak error!)")
# ── SIMULASI PAYMENT SERVICE ──────────────────────────────────
def payment_service(amount, service_healthy=True):
"""Simulasi: service sehat vs sakit"""
if not service_healthy:
raise ConnectionError("Payment gateway timeout!")
if amount <= 0:
raise ValueError("Amount must be positive")
return {"status": "SUCCESS", "amount": amount,
"tx_id": f"TX-{random.randint(10000,99999)}"}
print("=" * 60)
print(" CIRCUIT BREAKER SIMULATION")
print(" S11409 ISTN Jakarta")
print("=" * 60)
cb = CircuitBreaker("payment-svc", failure_threshold=3, recovery_timeout=2)
# Fase 1: Service normal
print("\n--- Fase 1: Service Normal (5 request) ---")
for i in range(5):
result, status = cb.call(payment_service, 100_000, service_healthy=True)
print(f" Request {i+1}: {status} | CB State: {cb.state.value}")
# Fase 2: Service mulai gagal
print("\n--- Fase 2: Service Gagal (5 request) ---")
for i in range(5):
result, status = cb.call(payment_service, 100_000, service_healthy=False)
print(f" Request {i+1}: {status} | CB State: {cb.state.value}")
# Fase 3: Tunggu recovery timeout
print("\n--- Fase 3: Menunggu recovery timeout (2 detik)... ---")
time.sleep(2.1)
# Fase 4: Coba kembali (HALF_OPEN)
print("\n--- Fase 4: Coba kembali setelah timeout ---")
for i in range(4):
result, status = cb.call(payment_service, 100_000, service_healthy=True)
print(f" Request {i+1}: {status} | CB State: {cb.state.value}")
# ── SLO ERROR BUDGET TRACKER ──────────────────────────────────
@dataclass
class SLOTracker:
service_name: str
slo_target: float = 0.999 # 99.9%
window_days: int = 30
_requests: List[dict] = field(default_factory=list, init=False)
def record(self, success: bool, latency_ms: float):
self._requests.append({
"success": success, "latency": latency_ms,
"timestamp": time.time()
})
@property
def sli(self):
if not self._requests: return 1.0
return sum(1 for r in self._requests if r["success"]) / len(self._requests)
@property
def error_budget_total(self):
"""Total detik error budget dalam window"""
return (1 - self.slo_target) * self.window_days * 24 * 3600
@property
def error_budget_used(self):
"""Perkiraan detik yang sudah terpakai"""
error_rate = 1 - self.sli
return error_rate * self.window_days * 24 * 3600
@property
def error_budget_remaining_pct(self):
total = self.error_budget_total
if total == 0: return 0
used = min(self.error_budget_used, total)
return max(0, (total - used) / total * 100)
def report(self):
latencies = [r["latency"] for r in self._requests]
print(f"\n Service : {self.service_name}")
print(f" Total req: {len(self._requests)}")
print(f" SLI : {self.sli:.4%}")
print(f" SLO Tgt : {self.slo_target:.4%}")
status = "OK" if self.sli >= self.slo_target else "VIOLATED"
print(f" SLO Status: {status}")
print(f" Error Budget Total : {self.error_budget_total/60:.1f} menit/bulan")
print(f" Error Budget Used : {self.error_budget_used/60:.1f} menit/bulan")
print(f" Error Budget Remaining: {self.error_budget_remaining_pct:.1f}%")
if latencies:
p50 = statistics.median(latencies)
p99 = sorted(latencies)[int(len(latencies)*0.99)]
print(f" Latency p50: {p50:.0f}ms | p99: {p99:.0f}ms")
if self.error_budget_remaining_pct < 20:
print(" !! WARNING: Error budget hampir habis — tahan deploy baru!")
print("\n\n" + "=" * 60)
print(" SLO ERROR BUDGET TRACKER — SIAKAD ISTN")
print("=" * 60)
tracker = SLOTracker("siakad-api", slo_target=0.999)
random.seed(42)
# Simulasi 1000 request (99.2% success rate — di bawah SLO!)
for _ in range(1000):
success = random.random() > 0.008 # 0.8% error rate
latency = random.gauss(120, 40) if success else random.gauss(4500, 500)
tracker.record(success, max(10, latency))
tracker.report()
print("\nDone! Gunakan sebagai baseline monitoring SIAKAD.")
SIAKAD ISTN memiliki 4 service: Auth, KRS, Nilai, dan Payment. KRS memanggil Auth untuk validasi token, Payment juga memanggil Auth. Jika Auth service down 100%: (a) Gambarlah alur cascade failure, (b) Resilience pattern apa yang bisa mencegahnya? (c) Bagaimana fallback yang tepat untuk masing-masing service?
Anda menjadi SRE di startup fintech. Buat rencana Chaos Engineering untuk menguji ketahanan payment service: (a) Definisikan steady state yang terukur, (b) Buat 3 hipotesis chaos experiment, (c) Jenis failure apa yang akan di-inject, dan (d) Apa kriteria "eksperimen berhasil" vs "gagal"?
Aplikasi e-learning ISTN memiliki SLO: 99.5% availability per bulan. Dalam bulan berjalan terjadi 2 insiden: (a) down 45 menit karena maintenance, (b) down 2 jam karena bug deployment. (a) Hitung total error budget yang terpakai dalam menit, (b) Hitung sisa error budget dan persentasenya, (c) Apakah tim masih boleh deploy fitur baru minggu ini?
Circuit Breaker payment service dikonfigurasi: failure_threshold=5, recovery_timeout=30s, success_threshold=2. Jelaskan secara detail state transitions yang terjadi jika: request 1-3 sukses, request 4-8 gagal semua, lalu diam 35 detik, lalu request 9-12 berhasil semua. Di state apa CB akhirnya?
Modifikasi SLOTracker di atas: (a) tambahkan SLI latency — "99% request harus selesai dalam 500ms", (b) implementasikan burndown alert — jika error budget akan habis dalam 7 hari berdasarkan laju saat ini, kirim peringatan, (c) tambahkan visualisasi matplotlib untuk error budget burndown selama 30 hari.
Microservices memberikan fault isolation tapi menciptakan tantangan baru: cascade failure, network unreliability, dan distributed tracing
Chaos Engineering bukan merusak sistem — tapi membuktikan keandalan dengan mengontrol kondisi failure secara terencana
SLO + Error Budget memberikan framework objektif: kapan tim boleh berinovasi vs kapan harus fokus reliability
Circuit Breaker mencegah cascade failure dengan 3 state: CLOSED (normal) → OPEN (fail-fast) → HALF_OPEN (recovery probe)
Tiga pilar observability: Metrics (apa yang terjadi), Logs (mengapa terjadi), Traces (di mana terjadi dalam distributed system)
SLO 100% adalah target yang salah — sistem yang berusaha 100% uptime terlalu lambat berinovasi. Error budget adalah keseimbangan antara reliability dan velocity.