Episode ini membahas performansi gRPC: mengukur latency dan throughput dengan ghz, optimasi lewat compression dan connection reuse, penanganan backpressure, serta menyusun message protobuf yang efisien dengan packed fields dan repeated fields.

gRPC sudah cepat secara bawaan, tapi "cepat" bukanlah angka. Untuk mengoptimalkan, kalian harus mengukur dulu — dan pengukuran gRPC punya tool khusus yang tepat. Episode 13 membahas sisi performansi: mengukur dengan ghz, lalu mengoptimalkan di tiga level: transport (compression dan connection reuse), aplikasi (backpressure), dan data (desain message protobuf).
Urutannya penting: ukur, identifikasi bottleneck, baru optimalkan. Mengoptimalkan tanpa pengukuran hanya menebak.
ghz adalah tool benchmark untuk gRPC yang memakai reflection — tidak perlu file .proto:
ghz --insecure \
-n 10000 \
-c 50 \
-d '{"id":"p-001"}' \
localhost:50051 catalog.v1.CatalogService/GetProductFlag -c 50 membuka 50 worker konkuren yang memanggil total 10 ribu kali. Output ghz menampilkan RPS, persentil latensi (p50, p90, p99), dan jumlah error — semuanya yang kalian butuhkan untuk menilai baseline.
Fokus pada tiga metrik: RPS (requests per second) untuk throughput, p99 untuk pengalaman terburuk, dan error rate untuk keandalan. Simpan output sebagai baseline sebelum dan sesudah perubahan — perbandingan itulah yang membuktikan optimasi berhasil.
Payload biner protobuf sudah ringkas, tapi bisa lebih kecil lagi dengan compression. Aktifkan di client:
import "google.golang.org/grpc/encoding/gzip"
res, err := client.GetProduct(ctx, &pb.ProductId{Id: "p-001"},
grpc.UseCompressor(gzip.Name))grpc.UseCompressor(gzip.Name) mengompresi request dengan gzip. Efeknya paling terasa untuk payload besar atau lewat bandwidth terbatas — tapi ada trade-off: CPU ekstra di kedua sisi. Untuk payload kecil, compression malah bisa memperlambat.
Ingat pelajaran episode 10: channel di-reuse, bukan dibuat baru per request. Dua pengaturan tambahan yang sering memberi lonjakan performa:
conn, _ := grpc.NewClient("localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(8*1024*1024)),
grpc.WithInitialWindowSize(2*1024*1024),
grpc.WithInitialConnWindowSize(8*1024*1024),
)grpc.WithInitialWindowSize(2*1024*1024) memperbesar flow control window sehingga throughput tinggi tidak terhambat backpressure yang terlalu agresif. Sesuaikan dengan pola traffic kalian, bukan sekadar menyalin nilai.
Backpressure justru teman, bukan lawan: gRPC membatasi laju pengiriman sesuai kemampuan receiver. Pada stream yang besar, jangan memanggil Recv secara berurutan dalam satu goroutine jika ingin paralelisme tinggi — baca dari goroutine terpisah agar flow control tidak menggantung pipeline.
Ada dua tingkatan flow control di gRPC: connection window (berlaku untuk seluruh stream di satu koneksi) dan stream window (berlaku per stream). Ketika throughput tertahan, periksa dulu apakah window yang terlalu kecil menjadi pembatasnya sebelum menambah thread — ghz dengan -c yang lebih besar sering mengungkap gejala ini lebih cepat daripada menebak di kode.
Untuk list scalar, protobuf memakai packed encoding secara default di proto3: semua elemen dikirim berurutan di satu blok, bukan satu tag per elemen. Artinya repeated int64 yang berisi seribu angka tidak menyeret seribu tag — hanya datanya.
message Order {
repeated int64 item_ids = 1 [packed = true];
}[packed = true] memastikan pengemasan eksplisit walau defaultnya sudah begitu di proto3. Untuk repeated message, encoding tidak bisa packed — setiap elemen tetap membawa tag-nya.
Tipe data memengaruhi ukuran wire format:
int32 vs sint32: untuk angka yang bisa negatif, sint32 memakai ZigZag encoding dan lebih kecil.int32 vs int64: int32 dengan nilai kecil hanya butuh 1-2 byte.double bila int32 cukup — presisi dan ukuran yang berlebihan tidak gratis.Aturan praktis dari pembandingan ini: ukur dulu payload aktual dengan grpcurl -v untuk melihat ukuran message, lalu putuskan tipe mana yang layak disederhanakan. Optimasi tanpa data pengukuran hampir selalu mengarah ke penyesuaian yang tidak berdampak.
Bagi message besar menjadi beberapa panggilan atau pakai streaming. Dua aturan praktis: jangan kirim seluruh riwayat user dalam satu response, dan jangan memasukkan field yang jarang dipakai ke dalam hot-path. Desain message yang ramping membuat panggilan unary tetap ringan.
Terakhir, jangan lupa menguji setiap optimasi dengan benchmark yang sama persis sebelum dan sesudahnya. Perubahan seperti compression atau window size bisa saling berinteraksi — pengujian baseline ghz yang konsisten adalah satu-satunya cara tahu kombinasi mana yang benar-benar memberi hasil.
Inti yang harus dibawa pulang:
ghz — RPS, p99, dan error rate — sebelum mengubah apa pun.Di episode 14 selanjutnya kita membahas observability, tracing, dan monitoring gRPC — metrics dengan Prometheus dan OpenTelemetry, distributed tracing pada RPC, propagasi span context, serta debugging dengan grpcurl dan ghz pada dashboard. Performa yang diukur kini harus dipantau secara terus-menerus di produksi.