Membidik performa secara ilmiah: profiling untuk menemukan bottleneck nyata, strategi optimasi latency termasuk tail latency, dan load testing dengan k6 lengkap dengan threshold — dibuktikan dengan praktik optimasi latency sebelum-sesudah yang terukur

Setelah reliability-as-code di episode 14 mengunci pengukuran dan pemulihan, muncullah pertanyaan yang paling sering menggelisahkan tim produksi: kenapa lambat? SLO latensi sudah ditetapkan, alert sudah terpasang, tetapi permintaan tetap membengkak di p95. Menjawab dengan tebakan — "mungkin database-nya" — adalah taruhan yang mahal dan sulit dipertanggungjawabkan.
Performance engineering adalah pendekatan ilmiah: temukan bottleneck dengan data (profiling), optimasi bagian yang paling berdampak, lalu buktikan dengan load testing yang terukur. Episode 15 membawa kalian dari "rasa-rasa lambat" ke angka yang bisa dibela di depan tim.
Sebelum mengoptimasi, jawab satu pertanyaan: kode apa yang paling banyak menghabiskan CPU dan waktu? Jawabannya bukan opini, melainkan hasil sampling profiler — alat yang memotret stack trace program ribuan kali per detik dan mengagregasikannya.
Beberapa tool yang lazim:
pprof bawaan runtime — go tool pprof.py-spy (sampling tanpa mengubah kode) atau cProfile.perf di Linux untuk profiling sistem.py-spy record --pid 4821 -o flame.svg --duration 30Hasilnya berupa flame graph: sumbu horizontal adalah proporsi waktu, sumbu vertikal adalah kedalaman call stack. Batang yang paling lebar di puncak adalah tersangka utama — dan biasanya jawabannya mengejutkan: bukan SQL query yang rumit, melainkan serialisasi JSON berulang atau logging yang sinkron.
Tip
Profil di lingkungan yang sedekat mungkin dengan produksi — throughput, ukuran data, dan konfigurasi yang sama. Profil di laptop dengan data dummy sering menunjukkan bottleneck yang tidak ada di produksi, dan sebaliknya.
Latensi punya distribusi. Mean menutupi kenyataan: 99% request selesai dalam 50 ms, tetapi 1% memakan 3 detik — dan pengguna yang merasakan p99 adalah pengguna yang paling lama menunggu. Google dan Netflix menemukan bahwa tail latency (p99, p999) hampir selalu menentukan pengalaman nyata, terutama karena satu request melintasi banyak service.
Ketika SLO latensi adalah 500 ms, bagilah menjadi budget per lapisan:
gateway → 50 ms (5%)
auth service → 50 ms (5%)
payment service → 300 ms (60%)
database → 80 ms (16%)
buffer → 20 ms (4%)Kunci budget ini adalah menolak penambahan di luar batas. Begitu satu service melampaui jatahnya, seluruh endpoint terkena imbas. Budget mengubah pertanyaan dari "berapa cepat masing-masing?" menjadi "berapa yang tersisa untuk lapisan berikutnya?".
Empat dari lima kategori di atas tidak bisa diselesaikan dengan "menambah cache" saja. Queueing dipecahkan dengan batching dan concurrency control, GC dengan tuning heap, serialisasi dengan memilih format yang lebih cepat, dan dependency dengan paralelisme — bukan menghapus batas timeout.
Setelah bottleneck diperbaiki, buktikan dengan beban yang terukur. k6 (sudah ada di setup episode 0) memungkinkan tes beban didefinisikan sebagai kode, lengkap dengan threshold yang bisa digagalkan — persis pola load test-as-code yang selaras dengan episode 14.
import http from "k6/http";
import { check } from "k6";
export const options = {
scenarios: {
ramp: {
executor: "ramping-vus",
stages: [
{ duration: "1m", target: 50 },
{ duration: "2m", target: 200 },
{ duration: "1m", target: 0 },
],
},
},
thresholds: {
http_req_duration: ["p(95)<500", "p(99)<1200"],
http_req_failed: ["rate<0.01"],
},
};
export default function () {
const res = http.get("https://api.example.com/checkout");
check(res, { "status 2xx": (r) => r.status >= 200 && r.status < 300 });
}k6 run --out json=results.json load-test.jsBagian thresholds adalah kunci: ia mengubah tes beban dari laporan menjadi gate. Jika p95 melampaui 500 ms, k6 keluar dengan exit code non-zero — siap dipakai di CI sebagai blokir rilis, persis seperti unit test yang gagal.
Ikuti siklus lengkap pada service lab kalian:
k6 run dengan 100 VU selama 3 menit; catat p50, p95, p99.py-spy record (atau profiler bahasa kalian) selama tes beban; buka flame graph.results.json sebelum/sesudah di repo sebagai bukti (episode 14).Metric Sebelum Sesudah
http_req_duration p95 612ms 341ms
http_req_duration p99 1480ms 720ms
http_req_failed 1.2% 0.3%Warning
Dua jebakan klasik: mengoptimasi mean alih-alih tail (pengguna merasakan p99, bukan p50), dan mengoptimasi dengan microbenchmark di luar alur request nyata. Selalu ukur dalam konteks alur lengkap, dengan beban mendekati produksi, sebelum mengklaim kemenangan.
Pada episode 15 ini, kalian telah belajar mendekati performa dengan data, bukan perasaan.
Inti yang harus dibawa pulang:
Di episode 16 selanjutnya, kita akan memperluas jangkauan: multi-region & disaster recovery — arsitektur active-active, failover, konsep RTO/RPO, dan DR drill untuk memastikan kalian pulih bukan hanya cepat, tapi juga terlatih. Sampai jumpa di episode 16!