Protocol Buffer (Protobuf) adalah sebuah library untuk serialisasi data yang dikembangkan oleh Google. Ini juga berfungsi sebagai Interface Definition Language (IDL), yang memungkinkan kita untuk mendefinisikan struktur data dan antarmuka layanan (service) dalam sebuah file khusus (.proto).
Komponen utamanya meliputi:
IDL: Bahasa untuk mendeskripsikan skema data.
Compiler (protoc): Alat yang mengambil file .proto dan menghasilkan kode sumber dalam berbagai bahasa pemrograman (misalnya Java, C++, Python).
Library: Pustaka runtime untuk setiap bahasa yang menangani proses serialisasi (mengubah objek menjadi byte stream) dan deserialisasi/parsing (mengubah byte stream kembali menjadi objek).
Apa itu gRPC?
gRPC (gRPC Remote Procedure Call) adalah sebuah framework RPC open-source modern yang juga dikembangkan oleh Google. gRPC dirancang untuk membangun layanan terdistribusi yang efisien dan dapat diandalkan.
Fokus utamanya adalah:
Efisiensi: Menggunakan Protobuf untuk serialisasi data yang ringkas dan HTTP/2 untuk transport yang cepat.
Language Interoperability: Memungkinkan client dan server berkomunikasi meskipun ditulis dalam bahasa pemrograman yang berbeda (misalnya client Java, server Go).
Usability: Menyediakan alat untuk membangkitkan kode client dan server secara otomatis, menyederhanakan pengembangan.
Arsitektur Dasar & Alur Kerja gRPC
Alur kerja pengembangan dengan gRPC dimulai dengan mendefinisikan layanan dan pesan dalam sebuah file .proto.
Service Definition (.proto file): Developer mendefinisikan service (kumpulan metode RPC) dan message (struktur data) menggunakan sintaks Protobuf.
Code Generation: Compiler protoc dengan plugin gRPC digunakan untuk menghasilkan:
Client Stub (Sisi Konsumen): Sebuah objek lokal yang merepresentasikan layanan remote. Ketika client memanggil metode pada stub, gRPC akan menangani serialisasi permintaan, mengirimkannya ke server, dan mengembalikan respons yang sudah dideserialisasi.
Server Skeleton (Sisi Penyedia Layanan): Kerangka antarmuka di sisi server. Developer hanya perlu mengimplementasikan logika bisnis dari setiap metode yang didefinisikan di file .proto.
Komunikasi: Client dan Server berkomunikasi melalui Protocol Buffer yang ditransmisikan di atas protokol HTTP/2.
Peran HTTP/2 dalam gRPC
gRPC secara spesifik memilih HTTP/2 sebagai lapisan transportnya, berbeda dengan Thrift yang lebih fleksibel. Pilihan ini memberikan beberapa keuntungan signifikan:
1. Binary Framing Layer
HTTP/2 memperkenalkan lapisan binary framing. Tidak seperti HTTP/1.1 yang berbasis teks, semua pesan HTTP/2 dipecah menjadi unit-unit biner yang lebih kecil yang disebut frame. Setiap frame memiliki tujuan tertentu, misalnya HEADERS frame untuk metadata dan DATA frame untuk payload. Pendekatan biner ini lebih efisien untuk diproses oleh mesin, mengurangi potensi kesalahan parsing, dan lebih ringkas.
2. Multiplexing & Streams
Fitur paling kuat dari HTTP/2 adalah multiplexing. Ini memungkinkan beberapa permintaan dan respons untuk dikirim secara bersamaan melalui satu koneksi TCP tunggal tanpa saling memblokir.
Stream: Setiap pasangan permintaan/respons (misalnya, satu panggilan RPC) berjalan di dalam sebuah stream independen.
Connection: Semua stream ini berjalan di atas satu koneksi TCP.
Ini mengatasi masalah “head-of-line blocking” di HTTP/1.1 dan secara dramatis meningkatkan efisiensi jaringan, terutama untuk aplikasi yang membutuhkan banyak panggilan konkuren.
Struktur File Definisi .proto
File .proto adalah pusat dari gRPC, tempat struktur data dan layanan didefinisikan.
// Menentukan versi sintaks yang digunakansyntax = "proto3";// Mendefinisikan namespace untuk mencegah konflik namapackage tutorial;// Opsi spesifik untuk bahasa, contoh untuk Java> > option java_package = "com.example.tutorial";option java_outer_classname = "AddressBookProtos";// Definisi struktur data (message)message Person { // Aturan field: required (harus ada), optional (boleh tidak ada) required string name = 1; // Angka 1 adalah tag unik untuk field required int32 id = 2; optional string email = 3; // Definisi tipe data enumerasi (enum) enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; // Field bisa memiliki nilai default optional PhoneType type = 2 [default = HOME]; } // repeated menandakan field ini bisa berisi 0 atau lebih elemen (seperti list/array) repeated PhoneNumber phone = 4;}// Message lain yang menggunakan message Personmessage AddressBook { repeated Person person = 1;}
Pembangkitan Kode, Serialisasi & Parsing
Pembangkitan Kode: Menggunakan command-line tool protoc untuk mengompilasi file .proto. Contoh:
Server Streaming RPC: Client mengirim satu permintaan, dan server merespons dengan sebuah stream (aliran) pesan. Berguna untuk notifikasi atau pengiriman data besar.
Client Streaming RPC: Client mengirim sebuah stream pesan ke server, dan server merespons dengan satu pesan tunggal setelah semua pesan client diterima. Berguna untuk upload file atau data streaming.
Client Call: Client memanggil metode pada objek stub lokal (misal: getProduct("ABC")).
Stub Builds Message: Client stub menyusun pesan permintaan menggunakan Protobuf, mengubahnya menjadi format biner.
Sent Across Network: Pesan biner beserta headernya (seperti path service dan nama metode) dikirim melalui koneksi HTTP/2 ke server.
Server Stub Receives: Server menerima frame HTTP/2 dan menyerahkannya ke server stub.
Stub Unpacks Message: Server stub mem-parsing pesan biner kembali menjadi objek sesuai definisi .proto.
Local Call: Server stub memanggil implementasi metode yang sebenarnya (getProduct()) di sisi server dengan objek hasil parsing sebagai argumen. Hasilnya dikirim kembali ke client melalui proses yang sama secara terbalik.
Perbandingan: gRPC vs Apache Thrift
Fitur
gRPC
Apache Thrift
Transport
Terikat pada HTTP/2. Kurang fleksibel namun dioptimalkan.
Lapisan transport yang pluggable (bisa diganti). Mendukung TCP, HTTP/2, AMQP, dll. Sangat fleksibel.
Streaming
Mendukung bidirectional streaming secara native.
Memerlukan implementasi manual atau kustom untuk streaming dua arah yang kompleks.
Popularitas
Saat ini lebih populer dan memiliki ekosistem yang berkembang pesat.
Sudah matang dan stabil, namun popularitasnya cenderung menurun dibandingkan gRPC.
Tipe Data
Menggunakan message untuk tipe komposit. Tidak memiliki tipe map atau set bawaan.
Menggunakan struct. Mendukung list, set, dan map.
Konstanta
Tidak mendukung definisi konstanta.
Mendukung definisi konstanta.
Exception
Tidak ada tipe exception khusus, error ditangani melalui kode status.
Mendukung definisi exception secara eksplisit.
Hasil Benchmark (github.com/chrislee87/rpc_benchmark):
Untuk koneksi jangka panjang (long connection): Performa QPS (Query Per Second) tidak jauh berbeda.
gRPC unggul dalam latensi yang lebih rendah.
Thrift unggul dalam penggunaan CPU yang lebih rendah.
Untuk koneksi jangka pendek (short connection): Thrift (menggunakan TCP) mengungguli gRPC (menggunakan HTTP/2) di semua metrik: QPS, CPU, dan latensi.
Catatan: Latensi pada aplikasi Go tidak bisa sepenuhnya dikontrol karena adanya Garbage Collector (GC) yang dapat “menghentikan dunia”. Untuk aplikasi realtime dengan syarat latensi sangat ketat, disarankan menggunakan C/C++.
Summary
Protocol Buffer (Protobuf) adalah fondasi untuk serialisasi data yang efisien, sedangkan gRPC adalah framework RPC yang menggunakan Protobuf dan HTTP/2 untuk membangun layanan terdistribusi yang cepat, multi-bahasa, dan modern. Protobuf mendefinisikan “apa” yang dikirim (struktur data dan antarmuka layanan melalui file .proto), sementara gRPC dan HTTP/2 mendefinisikan “bagaimana” data itu dikirim (melalui panggilan prosedur jarak jauh yang efisien dengan fitur canggih seperti streaming dua arah dan multiplexing di atas satu koneksi TCP). Perbedaan utama dengan alternatif seperti Thrift terletak pada keterikatan gRPC pada HTTP/2 yang memberinya performa optimal untuk kasus penggunaan tertentu, meskipun dengan fleksibilitas transport yang lebih rendah.
Additional Information
Pendalaman Teknis: Encoding Protobuf
Salah satu alasan efisiensi Protobuf adalah teknik encodingnya. Untuk integer, Protobuf menggunakan format yang disebut Varints (Variable-length integers). Angka kecil hanya membutuhkan satu byte untuk disimpan, sedangkan angka yang lebih besar membutuhkan lebih banyak byte. Ini membuat payload sangat ringkas dibandingkan dengan mengirim angka sebagai teks (seperti di JSON) atau dalam format integer ukuran tetap (misalnya, 32-bit atau 64-bit setiap saat).
Pendalaman Teknis: Lapisan Transport Thrift yang Pluggable
Fleksibilitas Thrift berasal dari kemampuannya untuk memisahkan protokol serialisasi dari lapisan transport. Anda bisa menggunakan serialisasi Thrift di atas berbagai mekanisme transport, seperti:
TSocket: Transport TCP/IP blocking standar.
TNonblockingSocket: Transport non-blocking untuk server I/O yang efisien.
TFramedTransport: Mengirim data dalam frame-frame berukuran tertentu. Diperlukan saat menggunakan TNonblockingSocket.
THttpClient: Menggunakan protokol HTTP sebagai transport.
Ini memungkinkan developer untuk memilih transport yang paling sesuai untuk arsitektur aplikasi mereka.
Eksplorasi Mandiri
Untuk memahami konsep ini secara praktis, coba bangun sebuah microservice sederhana menggunakan gRPC.
Definisikan Service: Buat file notes.proto yang mendefinisikan layanan NoteService dengan metode AddNote, GetNote, dan ListNotes.
Implementasi Server: Tulis server dalam bahasa Go atau Python yang mengimplementasikan NoteService.
Implementasi Client: Tulis client dalam bahasa Java atau Node.js yang memanggil metode pada server.
Eksperimen: Coba ubah salah satu metode menjadi server streaming (misalnya, StreamNotes yang mengirimkan catatan baru saat ditambahkan).