Studi Kasus: Komunikasi antara Microservice Go dan Java via Protobuf
Interoperabilitas microservices lintas bahasa jadi prioritas utama di skenario arsitektur modern. Bagaimana Go dan Java bisa saling bicara dengan efisien? Protocol Buffers (Protobuf) menjawab tantangan tersebut. Berikut studi kasus dan tutorial konkret penerapannya.
Pendahuluan
Microservices memungkinkan kita membangun sistem yang scalable, modular, dan dapat dikembangkan secara paralel. Sering kali, tim berbeda menggunakan bahasa pemrograman berbeda untuk implementasi service mereka, misalnya Go (Golang) dan Java. Namun, tantangan terbesar adalah bagaimana memastikan komunikasi data antar service berjalan mulus dan efisien.
Di sini, gRPC dan Protocol Buffers (Protobuf) muncul sebagai solusi. Dengan Protobuf, serialisasi data jadi jauh lebih ringan dibanding JSON/XML—mengurangi latensi dan overhead, serta memungkinkan kompatibilitas lintas bahasa.
Artikel ini membahas studi kasus nyata: Bagaimana membangun komunikasi antara satu microservice Go dan satu microservice Java, keduanya berkomunikasi via gRPC dengan data serialization menggunakan Protobuf.
Studi Kasus: Order Service (Go) dan Payment Service (Java)
Bayangkan kita punya dua service penting dalam sistem e-commerce:
- Order Service—Ditulis dalam Go.
- Payment Service—Ditulis dalam Java.
Order Service akan mengirim instruksi pembayaran ke Payment Service, lalu menunggu konfirmasi. Skema diilustrasikan sebagai berikut:
sequenceDiagram
participant Go-OrderService
participant Java-PaymentService
Go-OrderService->>Java-PaymentService: RequestPayment(orderId, amount)
Java-PaymentService-->>Go-OrderService: PaymentResponse(status, transactionId)
Desain Kontrak Data dengan Protobuf
Agar interoperabilitas terjaga, kita desain file Protobuf (payment.proto) yang merepresentasikan kontrak data, berikut endpoint servis yang disediakan oleh Payment Service.
// payment.proto
syntax = "proto3";
package payment;
// Request dari OrderService ke PaymentService
message PaymentRequest {
string order_id = 1;
double amount = 2;
}
// Response PaymentService ke OrderService
message PaymentResponse {
string status = 1; // "SUCCESS" or "FAIL"
string transaction_id = 2; // ID transaksi jika sukses
}
// Service definition
service PaymentService {
rpc MakePayment(PaymentRequest) returns (PaymentResponse);
}
File ini nantinya akan digunakan untuk generate stub gRPC pada kedua service, baik Go maupun Java.
Generate Stub Protobuf
Langkah-langkah generate kode:
1. Install Protobuf Compiler (protoc)
# Ubuntu
sudo apt-get install -y protobuf-compiler
# Mac
brew install protobuf
2. Generate Stub di Go
Install plugin:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Generate:
protoc --go_out=. --go-grpc_out=. payment.proto
3. Generate Stub di Java
Tambahkan dependency Maven/Gradle:
<!-- build.gradle -->
dependencies {
implementation 'io.grpc:grpc-protobuf:1.54.0'
implementation 'io.grpc:grpc-netty-shaded:1.54.0'
implementation 'io.grpc:grpc-stub:1.54.0'
}
Generate via plugin/maven/protoc:
protoc --java_out=. --grpc-java_out=. payment.proto
Implementasi Payment Service (Java)
Mari lihat bagaimana Payment Service mengimplementasikan service sesuai kontrak.
// Java PaymentServiceImpl.java
public class PaymentServiceImpl extends PaymentServiceGrpc.PaymentServiceImplBase {
@Override
public void makePayment(Payment.PaymentRequest request, StreamObserver<Payment.PaymentResponse> responseObserver) {
String orderId = request.getOrderId();
double amount = request.getAmount();
// Simulasi pembayaran berhasil
Payment.PaymentResponse response = Payment.PaymentResponse.newBuilder()
.setStatus("SUCCESS")
.setTransactionId("TXN-" + orderId)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
Bootstrapping server-nya:
public static void main(String[] args) throws IOException, InterruptedException {
Server server = ServerBuilder.forPort(50051)
.addService(new PaymentServiceImpl())
.build()
.start();
server.awaitTermination();
}
Implementasi Order Service (Go)
Di sisi Go, kita build gRPC client yang melakukan request ke Payment Service.
// order_service.go
package main
import (
"context"
"log"
"payment" // hasil generate dari payment.proto
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("Did not connect: %v", err)
}
defer conn.Close()
client := payment.NewPaymentServiceClient(conn)
req := &payment.PaymentRequest{
OrderId: "ORD-123",
Amount: 150000,
}
resp, err := client.MakePayment(context.Background(), req)
if err != nil {
log.Fatalf("Error calling MakePayment: %v", err)
}
log.Printf("Payment Status: %s, Transaction ID: %s", resp.GetStatus(), resp.GetTransactionId())
}
Simulasi Komunikasi
Langkah menjalankan simulasi:
- Jalankan Payment Service (Java, port 50051)
- Jalankan Order Service (Go)
Order Service akan mengirim permintaan pembayaran via gRPC dan menerima respons sukses.
Output yang Diharapkan
Payment Status: SUCCESS, Transaction ID: TXN-ORD-123
Bandingkan Efisiensi: Protobuf vs JSON
| Format | Serialized Size | Parsing Latency | Interoperability | Strictness |
|---|---|---|---|---|
| Protobuf | Kecil | Rendah | Kuat (multi-bahasa) | Strict |
| JSON | Lebih besar | Lebih tinggi | Baik (tapi parser bervariasi) | Flexible |
Dengan Protobuf, kelebihan yang kasat mata antara lain:
- Serialized message jauh lebih kecil.
- Parsing & serialisasi lebih cepat.
- Kontrak antar layanan jadi “typed” dan versioned.
Diagram Arsitektur
flowchart LR
GS[Go Order Service] -- gRPC+Protobuf --> JS[Java Payment Service]
Tips Best Practices
- Jaga backward-compatibility schema Protobuf, apalagi jika service sudah di-deploy ke production dan ada client beda versi.
- Otomatiskan generate code di CI/CD pipeline agar setiap perubahan .proto langsung ter-reflect di stub language masing-masing.
- Monitor latency. Protobuf memang cepat, tapi pastikan overhead networking gRPC cukup rendah.
- Protocol versioning. Gunakan field number baru untuk penambahan fitur, hindari menghapus/mengubah arti field lama.
Kesimpulan
Perpaduan Go dan Java dengan Protobuf menunjukkan microservice lintas bahasa bisa tetap efisien, maintainable, dan future-proof. Dengan satu kontrak data, developer tinggal fokus ke logic bisnis—interoperabilitas, scale, dan kecepatan sudah terjamin oleh Protobuf dan gRPC.
Punya pengalaman membangun microservices lintas bahasa dengan Protobuf? Share di komentar!