Biaya & runbook insiden
Dua hal yang menutup proyek ini: angka yang membuktikan migrasinya sepadan, dan dokumen yang dibaca orang saat panik.
Intisari
- Ukur biaya sebelum dan sesudah dengan tag yang sama, supaya bisa dibandingkan.
- Penghematan terbesar biasanya egress, bukan komputasi.
- Runbook per gejala, bukan per komponen โ orang mencari berdasarkan apa yang mereka lihat.
- Setiap runbook harus punya langkah pertama yang aman yang tidak memperburuk keadaan.
- Tulis post-mortem tanpa menyalahkan orang; yang dicari adalah sistem yang membiarkannya terjadi.
Memberi tag supaya bisa diukur
# Tag semua sumber daya dengan skema yang sama
aws ecs tag-resource --resource-arn <arn> \
--tags key=Proyek,value=portal key=Lingkungan,value=produksi key=Komponen,value=web
# Aktifkan tag sebagai kategori biaya
aws ce update-cost-allocation-tags-status \
--cost-allocation-tags-status TagKey=Proyek,Status=Active
Perbandingan sebelum-sesudah
| Komponen | CI3 (sebelum) | Astro (sesudah) | Penyebab perubahan |
|---|---|---|---|
| Komputasi | EC2 untuk PHP-FPM | ECS Fargate | Lebih sedikit request ke origin |
| Egress | ~10,8 TB/bulan | ~1,6 TB/bulan | Cache hit 60% โ 93% |
| RDS | Sama | Sama atau lebih kecil | Beban baca turun drastis |
| Penyimpanan gambar | S3 + egress | R2, egress nol | Pindah penyedia |
| NAT Gateway | Ada | Lebih rendah | VPC Endpoint |
| ALB | Ada | Nol kalau pakai Tunnel | Cloudflare Tunnel |
| CloudWatch | Rendah | Naik | Log terstruktur lebih banyak |
Penghematan terbesar datang dari egress, dan itu konsekuensi langsung dari Fase 8. Dengan asumsi respons rata-rata 30 KB dan tarif egress standar, memangkas 500 ribu request/jam jadi ~87 ribu memindahkan sekitar 9 TB per bulan dari tagihan AWS-mu โ nilainya biasanya beberapa ratus dolar, sebelum menghitung apa pun yang lain. Ukur ukuran respons rata-ratamu yang sebenarnya untuk angka yang tepat; jangan pakai angka contoh ini di presentasi.
# Biaya per layanan bulan ini
aws ce get-cost-and-usage \
--time-period Start=2026-08-01,End=2026-09-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--filter '{"Tags":{"Key":"Proyek","Values":["portal"]}}' \
--query 'ResultsByTime[0].Groups[?Metrics.UnblendedCost.Amount>`10`].
{layanan:Keys[0],biaya:Metrics.UnblendedCost.Amount}' \
--output table
Alarm anggaran
aws budgets create-budget --account-id 123456789012 --budget '{
"BudgetName": "portal-bulanan",
"BudgetLimit": {"Amount": "1200", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST",
"CostFilters": {"TagKeyValue": ["user:Proyek$portal"]}
}' --notifications-with-subscribers '[{
"Notification": {"NotificationType":"FORECASTED","ComparisonOperator":"GREATER_THAN",
"Threshold":110,"ThresholdType":"PERCENTAGE"},
"Subscribers": [{"SubscriptionType":"EMAIL","Address":"[email protected]"}]
}]'
Pakai FORECASTED, bukan ACTUAL: kamu ingin tahu bahwa kamu akan
melewati anggaran, bukan bahwa kamu sudah melewatinya.
Runbook per gejala
| Gejala | Langkah pertama | Tersangka |
|---|---|---|
| Situs lambat, semua halaman | Periksa cache hit ratio Cloudflare | Cache Rule berubah, purge everything, origin jenuh |
| 5xx melonjak | Periksa jumlah task & log error | Deploy buruk, OOM, database |
| Halaman artikel 502 | Periksa health check ECS | keepAliveTimeout < ALB, task berputar |
| Member tidak bisa login | Periksa koneksi database & tabel sesi | Pool habis, replica lag |
| Pembayaran tidak masuk | Periksa log webhook & Security Events Cloudflare | WAF memblokir webhook, tanda tangan salah |
| Paywall bocor | Purge cache seluruh artikel premium | Cache Rule salah, halaman menyetel cookie |
| Trafik Google turun | Periksa Search Console | Redirect rusak, kanonik salah, noindex nyasar |
| Iklan tidak muncul | Periksa CSP & ClientRouter | CSP terlalu ketat, skrip tidak dijalankan ulang |
| Artikel baru tidak muncul | Periksa purge cache tag | Token API kedaluwarsa, TTL terlalu panjang |
| Task ECS berputar terus | Lihat stoppedReason | Secret hilang, OOM, health check |
Perhatikan bahwa langkah pertama untuk "paywall bocor" adalah purge, bukan menyelidiki. Setiap detik kebocoran berlangsung berarti lebih banyak orang mendapat isi berbayar gratis dari cache edge. Hentikan pendarahannya dulu, cari penyebabnya kemudian. Untuk sebagian besar gejala lain, urutannya terbalik โ jangan restart apa pun sebelum tahu apa yang terjadi, karena restart menghapus bukti.
Contoh satu runbook
## Gejala: pembayaran tidak masuk
Dampak: pelanggan membayar tapi langganan tidak aktif. Prioritas TERTINGGI.
Langkah 1 โ apakah webhook sampai?
Logs Insights, 1 jam terakhir:
fields @timestamp, order_id, level
| filter msg like /webhook/
| stats count() by level
Tidak ada baris sama sekali โ webhook tidak sampai. Lanjut ke 2.
Ada baris level=error โ lanjut ke 3.
Langkah 2 โ apakah Cloudflare memblokirnya?
Dashboard โ Security โ Events, filter path = /api/midtrans-webhook
Kalau ada yang diblokir: periksa aturan skip WAF (Fase 6).
Perbaikan cepat: tambahkan aturan Skip untuk path itu.
Langkah 3 โ verifikasi tanda tangan gagal?
Cek MIDTRANS_SERVER_KEY di task yang berjalan cocok dengan dashboard Midtrans.
Cek gross_amount tidak dikonversi (Fase 6).
Langkah 4 โ pulihkan yang tertinggal
Jalankan penyapu manual:
aws ecs run-task --cluster portal --task-definition portal-tugas \
--overrides '{"containerOverrides":[{"name":"tugas",
"command":["node","tugas.mjs","sapu-pesanan"]}]}'
Langkah 5 โ verifikasi
SELECT COUNT(*) FROM langganan
WHERE status='menunggu' AND dibuat_pada < NOW() - INTERVAL 30 MINUTE;
Harus mendekati nol.
Eskalasi: kalau belum selesai dalam 30 menit, hubungi dukungan Midtrans
dengan daftar order_id yang terpengaruh.
Post-mortem
| Bagian | Isinya |
|---|---|
| Ringkasan | Apa yang rusak, berapa lama, siapa terdampak |
| Linimasa | Waktu demi waktu, termasuk kapan diketahui |
| Akar penyebab | Kenapa sistemnya mengizinkan ini terjadi |
| Kenapa tidak tertangkap lebih awal | Sering lebih berharga daripada akar penyebabnya |
| Tindakan | Konkret, ada pemiliknya, ada tenggatnya |
Tanpa menyalahkan orang, dan itu bukan sekadar kesopanan. Post-mortem yang mencari siapa yang salah menghasilkan orang yang menyembunyikan kesalahan, dan insiden berikutnya jadi lebih lama ditemukan. Pertanyaannya bukan "siapa yang menghapus aturan itu" melainkan "kenapa satu orang bisa menghapus aturan itu tanpa review, dan kenapa tidak ada alarm yang menyala".
Baris "kenapa tidak tertangkap lebih awal" sering menghasilkan perbaikan yang lebih bernilai daripada memperbaiki penyebabnya. Insiden 5 menit dan insiden 5 jam bisa punya akar penyebab yang sama persis โ yang membedakan hanya apakah ada yang memberitahumu.
Yang harus ada sebelum kamu tidur nyenyak
| Item | Sudah? |
|---|---|
| Rollback deploy dalam satu perintah | Fase 10 |
| Rollback platform dalam satu aturan | Fase 9 |
| Cadangan database teruji pemulihannya | Fase 10 |
| Alarm untuk 5xx, webhook, koneksi DB, penyimpanan | Fase 10 |
| Uji asap otomatis tiap deploy | Fase 9 |
| Runbook per gejala | Materi ini |
stale-if-error panjang di semua halaman publik | Fase 1 |
| Origin tidak bisa dihubungi langsung | Fase 8 |
Baris ketujuh layak digarisbawahi: dengan stale-if-error sehari penuh, origin yang tumbang
total tetap menyisakan portal yang menyajikan artikel dari edge. Pembaca melihat berita yang terlambat
beberapa jam alih-alih halaman error โ dan kamu punya waktu memperbaiki tanpa tekanan.
Latihan: aktifkan tag alokasi biaya dan ambil rincian biaya bulan berjalan per layanan. Tulis runbook untuk tiga gejala teratas di tabel โ pilih yang paling mungkin terjadi di portalmu. Lalu uji satu runbook dengan benar-benar menjalankan langkahnya di lingkungan uji, dan perbaiki bagian yang ternyata tidak sesuai kenyataan.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.