tutorial

  1. Menyambungkan gRPC Service dengan Kafka

76. Menyambungkan gRPC Service dengan Kafka

Dalam membangun sistem terdistribusi modern, pola komunikasi antar-microservices menjadi sangat krusial. Dua teknologi populer yang sering digunakan adalah gRPC dan Apache Kafka. Kombinasi dua teknologi ini menawarkan kecepatan, kestabilan, serta skalabilitas untuk sistem enterprise. Pada artikel kali ini, saya akan membahas tentang bagaimana menyambungkan gRPC Service dengan Kafka—mulai dari arsitektur, implementasi kode, hingga simulasi pengujian.


Mengapa Perlu Integrasi gRPC dengan Kafka?

gRPC adalah sistem komunikasi Remote Procedure Call (RPC) modern berbasis HTTP/2 dan Protocol Buffers, yang efisien untuk komunikasi synchronous antar service. Sementara Kafka adalah message broker yang powerful untuk pengiriman pesan asynchronous dalam jumlah masif.

Pola tipikal yang sering digunakan:

  • gRPC sebagai API service layer (front-facing service, melakukan validasi, dan proses sinkronus).
  • Kafka sebagai event bus untuk komunikasi asinkron dan pengolahan data secara real-time/batch oleh downstream service.

Dengan begitu, setiap request yang diterima oleh gRPC bisa dipush sebagai event ke Kafka—membuka jalan bagi service lain untuk bereaksi terhadap event tersebut secara loose-coupled.


Studi Kasus: Order Service

Bayangkan kita membangun Order Service (gRPC) yang, setiap kali user membuat order baru, service ini akan mem-publish order event ke Kafka. System lain seperti Inventory Service, Notification Service akan mengonsumsi event ini untuk memproses lebih lanjut.


Arsitektur High Level

Mari kita lihat alur sistem ini dengan kode Mermaid Diagram:

sequenceDiagram
    participant Client
    participant gRPC Service
    participant Kafka
    participant Consumer Service

    Client->>gRPC Service: gRPC call (CreateOrder)
    gRPC Service->>Kafka: Publish OrderCreated event
    Kafka->>Consumer Service: Consumer receives OrderCreated event

Langkah singkat:

  1. Client mengirim permintaan CreateOrder ke gRPC Service.
  2. gRPC Service memvalidasi, lalu push event OrderCreated ke Kafka topic.
  3. Service lain menjadi consumer dari topic tersebut.

Persiapan Lingkungan

Untuk simulasi, kita akan menggunakan stack berikut:

  • Go sebagai bahasa pemrograman (karena binding gRPC dan Kafka di Go sangat solid)
  • protoc untuk generate stubs dari proto file
  • sarama sebagai Kafka client di Go

Kode berikut relevan untuk stack selain Go, karena prinsipnya sama (publish event ke Kafka setelah menangani gRPC).


1. Definisi Protobuf

File: order.proto

syntax = "proto3";

package order;

service OrderService {
  rpc CreateOrder (OrderRequest) returns (OrderResponse);
}

message OrderRequest {
  string item = 1;
  int32 qty = 2;
  string user_id = 3;
}

message OrderResponse {
  string order_id = 1;
  string status = 2;
}

Generate kode Go untuk service dan message tersebut.


2. Implementasi gRPC Server dengan Kafka Publisher

File: main.go

package main

import (
	"context"
	"log"
	"net"

	pb "github.com/yourorg/orderpb"
	"github.com/Shopify/sarama"
	"google.golang.org/grpc"
)

type server struct {
	producer sarama.SyncProducer
	pb.UnimplementedOrderServiceServer
}

func (s *server) CreateOrder(ctx context.Context, req *pb.OrderRequest) (*pb.OrderResponse, error) {
	orderID := generateOrderID() // fungsi random, misal UUID

	event := map[string]interface{}{
		"order_id": orderID,
		"item":     req.Item,
		"qty":      req.Qty,
		"user_id":  req.UserId,
	}

	// Serialize ke JSON
	marshalled, err := json.Marshal(event)
	if err != nil {
		return nil, err
	}

	// Publish ke Kafka topic
	message := &sarama.ProducerMessage{
		Topic: "order_events",
		Value: sarama.ByteEncoder(marshalled),
	}

	_, _, err = s.producer.SendMessage(message)
	if err != nil {
		return nil, err
	}

	return &pb.OrderResponse{
		OrderId: orderID,
		Status:  "CREATED",
	}, nil
}

func main() {
	// Inisialisasi Kafka producer
	config := sarama.NewConfig()
	config.Producer.Return.Successes = true
	producer, err := sarama.NewSyncProducer([]string{"localhost:9092"}, config)
	if err != nil {
		log.Fatalf("Failed to start Sarama producer: %v", err)
	}

	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	grpcServer := grpc.NewServer()
	pb.RegisterOrderServiceServer(grpcServer, &server{producer: producer})

	log.Println("gRPC & Kafka server running at :50051 ...")
	if err := grpcServer.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}

Penjelasan Kode

  • Setiap berhasil create order, event didorong ke Kafka Topic.
  • gRPC tetap memberikan response synchronous ke client (“CREATED”).
  • Kode mudah dikembangkan untuk juga melakukan sinkronisasi database, logging, dsb.

3. Kafka Consumer (simulasi)

Order Event dari Kafka ini bisa dikonsumsi oleh service lain seperti berikut:

consumer, err := sarama.NewConsumer([]string{"localhost:9092"}, nil)
if err != nil {
    panic(err)
}
partitionConsumer, err := consumer.ConsumePartition("order_events", 0, sarama.OffsetNewest)
if err != nil {
    panic(err)
}
for message := range partitionConsumer.Messages() {
    var event map[string]interface{}
    if err := json.Unmarshal(message.Value, &event); err == nil {
        log.Printf("Order Event received: %+v\n", event)
        // Lakukan hal lain: update stok, kirim email, dsb.
    }
}

Simulasi Pengujian

Mari kita buat simulasi pengujian menggunakan tabel step serta sample output log.

StepActionExpected Output
1Client gRPC call CreateOrderResponse {“order_id”: “…”, “status”:“CREATED”}
2Kafka topic receive eventEvent order muncul di Kafka
3Consumer membaca eventLog: Order Event received: …

Contoh log output:

2024/06/12 11:00:01 gRPC & Kafka server running at :50051 ...
2024/06/12 11:00:08 Order Event received: map[item:"Coffee" order_id:"123" qty:2 user_id:"abcde"]

Manfaat Arsitektur ini

Kelebihan

  • Scalability: Order event bisa diterima oleh banyak konsumen tanpa menambah beban pada gRPC API.
  • Decoupling: Downstream service bisa subscribe/unsubscribe tanpa mengubah code OrderService.
  • Reliability & Retries: Kafka mendukung re-delivery ketika konsumen gagal.
  • Asynchronous processing: Proses berat (misal update stok, kirim email) tak memblokir request client.

Kekurangan

  • Kebutuhan Infrastruktur: Perlu deploy dan mengelola Kafka cluster.
  • Error Handling: Perlu monitoring/kebijakan retry jika publish ke Kafka gagal.
  • Duplicate Event: Downstream service perlu idempoten (event bisa diterima lebih dari sekali).

Kesimpulan

Dengan mengombinasikan gRPC (untuk API synchronous) dan Kafka (untuk event asynchronous), kita bisa membangun microservices yang scalable dan loosely coupled. Teknik yang telah dijelaskan di atas sudah menjadi praktik terbaik di banyak perusahaan tech besar.

Berikut 📝 checklist integrasi gRPC + Kafka production ready:

  • Gunakan schema registry untuk event contracts (menghindari broken consumer)
  • Logging & distributed tracing di setiap step
  • Monitoring publish dan delivery event
  • Implementasi retry/retry policy pada publisher dan consumer

Integrasi ini cocok untuk berbagai use case — dari order management, payment, hingga notifikasi email/SMS.
Silakan coba struktur ini di proyek microservices Anda, dan nikmati kemudahannya dalam scaling layanan 🚀.


Referensi

comments powered by Disqus