Mengetahui apa yang terjadi
Kenapa latensi rata-rata berbohong, berapa harga satu label ber-kardinalitas tinggi, bagaimana trace context berjalan, dan untuk apa error budget sebenarnya.
Pola resiliensi menentukan bagaimana sebuah service berperilaku saat tertekan. Materi ini soal bisa mengetahui bahwa dia memang berperilaku begitu.
Rata-rata menyembunyikan gangguan
Latensi rata-rata adalah metrik utama yang salah, karena dia didominasi oleh banyaknya request yang cepat. Sepuluh ribu request di 20ms dan seratus request di 8 detik menghasilkan rata-rata di bawah 100ms — angka yang terlihat sehat sementara seratus orang menatap spinner.
Persentil menjawab pertanyaan yang sebenarnya kamu punya:
| Yang dia beri tahu | |
|---|---|
| p50 | pengalaman yang tipikal |
| p95 / p99 | pengalaman pengguna yang sedang bernasib buruk |
| max | biasanya sebuah timeout, dan layak diketahui timeout yang mana |
Pantau p99. Dan hati-hati merata-ratakan persentil antar instance — rata-rata dua p99 bukan p99 dari apa pun. Histogram bisa diagregasi dengan benar; persentil yang sudah dihitung tidak.
Kardinalitas itu biaya, dan user id adalah kesalahan klasiknya
Satu metrik adalah satu time series per kombinasi label unik. Beri label user id pada sebuah counter dan kamu baru saja membuat satu time series per pengguna — ratusan ribu, masing-masing dengan retensinya sendiri, masing-masing memakan memori di exporter dan di backend.
Hasilnya bukan grafik yang bagus. Hasilnya sistem metrik yang tumbang, dan tagihan yang sepadan. Sama untuk request id, session id, path URL lengkap yang berisi id, dan pesan error yang memuat nilai.
Label itu untuk hal-hal yang himpunan nilainya kecil dan berbatas: status
code, method, template endpoint (/orders/{id}, bukan /orders/8412),
instance. Kalau kamu butuh detail per pengguna, itu gunanya log dan trace —
mereka di-index oleh waktu, bukan oleh kardinalitas.
Log, trace, dan keunggulan masing-masing
Structured logging berarti memancarkan baris log sebagai data key–value
alih-alih satu kalimat. Keuntungan praktisnya: status=500 tenant=acme duration_ms=8123 bisa di-query, diagregasi, dan dipasangi alert. Sebuah kalimat
harus di-parse dengan regular expression yang rusak pertama kali ada orang
mengubah susunan katanya.
Correlation atau trace id di setiap baris itulah yang membuat query-nya berguna. Tanpa itu kamu punya seribu baris dari seratus request bersamaan yang saling menyela, tanpa cara menentukan mana yang satu keluarga. Dengan itu, satu field mengubah tumpukan menjadi cerita.
Trace memberi apa yang tidak bisa diberi metrik dan log: bentuk satu request melintasi banyak service, dengan waktu tiap hop. Metrik memberi tahu p99 memburuk; trace memberi tahu panggilan mana dari enam panggilan di request itu yang membengkak, dan apakah membengkak karena dipanggil lebih sering atau karena tiap panggilannya melambat.
Trace context berjalan lewat HTTP sebagai header — traceparent dan
tracestate di W3C Trace Context. Setiap service wajib membacanya dari request
yang masuk dan meneruskannya ke request yang keluar. Lewatkan itu di satu service
dan trace-nya patah di situ: kamu dapat dua trace terputus tanpa kaitan — dan itu
lebih buruk daripada tidak ada, karena kelihatannya utuh.
Probe itu dua pertanyaan yang berbeda
| Probe | Pertanyaan | Kalau gagal |
|---|---|---|
| liveness | apakah proses ini macet? | container di-restart |
| readiness | bisakah dia melayani trafik sekarang? | dia dikeluarkan dari load balancer |
Menyamakan keduanya adalah kesalahan yang umum dan menyakitkan. Kalau liveness probe memeriksa database, maka satu gangguan kecil database me-restart setiap instance service-mu — mengubah masalah dependensi menjadi gangguan milikmu sendiri. Liveness sebaiknya memeriksa bahwa prosesnya sendiri hidup. Dependensi tempatnya di readiness.
Graceful shutdown
Saat SIGTERM, sebuah service seharusnya: berhenti menerima pekerjaan baru,
menyelesaikan yang sedang berjalan, menutup resource, dan baru kemudian keluar.
Dia juga harus dikeluarkan dari routing lebih dulu sebelum berhenti menerima —
kalau tidak, load balancer terus mengirim request ke socket yang sedang menutup,
dan klien melihat connection reset.
Urutan yang biasa: gagalkan readiness dulu, tunggu satu interval probe, baru kuras. Urutannya lebih penting daripada nilai timeout-nya.
SLI, SLO, dan error budget
- SLI — pengukurannya: “proporsi request yang dilayani di bawah 300ms”.
- SLO — targetnya untuk pengukuran itu: “99,9% selama 30 hari”.
- Error budget — yang diizinkan target itu untuk kamu belanjakan: 0,1%, yang dalam 30 hari sekitar 43 menit.
Budget itulah intinya. Dia mengubah reliabilitas dari perdebatan menjadi aritmetika: budget masih ada berarti kamu boleh rilis, deploy hari Jumat, menjalankan migrasi yang berisiko. Budget habis berarti pekerjaan berikutnya adalah pekerjaan reliabilitas — dan itu keputusan yang dibuat oleh angka, bukan oleh orang yang paling keras suaranya di ruangan.
Target 100% tidak punya budget, yang berarti tidak boleh ada perubahan — dan itu sebabnya tidak ada orang kredibel yang menetapkannya.
JDK Flight Recorder
JFR dirancang untuk menyala di produksi: dia tertanam di JVM, dan pada setelan default biayanya beberapa persen throughput saja. Itulah yang membedakannya dari profiler yang kamu tempelkan saat insiden — event yang kamu butuhkan sudah terekam ketika insidennya mulai, bukan baru mulai dikumpulkan setelah ada yang menyadari.
Instrumentasinya dalam kode, dan insiden yang membentuk pilihan-pilihan ini: Bertahan di Produksi dengan Java.
Diskusi
Memuat komentar…