tutorial

21 Memahami Konsep Streaming pada gRPC

Jika Anda sudah familiar dengan REST API, mungkin konsep komunikasi request-response terasa sangat natural. Namun, saat aplikasi makin kompleks dan kebutuhan komunikasi dua arah yang efisien dibutuhkan—seperti real-time chat, monitoring sistem, atau transfer file yang besar—REST mulai menunjukkan keterbatasannya. Di sinilah kekuatan gRPC, khususnya fitur streaming-nya, benar-benar menonjol.

Pada artikel kali ini, kita akan membedah konsep streaming pada gRPC. Kita akan memahami mekanismenya, melihat tipe-tipe streaming pada gRPC, dan menuliskannya dalam contoh kode Go yang mudah dicerna. Tidak lupa, kita juga menyajikan simulasi, diagram alur, dan tabel supaya konsepnya makin solid di kepala.


Apa Itu Streaming pada gRPC?

Secara sederhana, streaming pada gRPC adalah mekanisme di mana klien dan/atau server dapat mengirimkan serangkaian pesan, bukan hanya satu request/response saja. Artinya, data dapat ‘dikirim bertahap’ antar klien dan server, secara asynchronous maupun synchronous, tanpa harus menunggu semua data selesai di sisi pengirim.

Mengapa Streaming Perlu?

Beberapa use-case yang paling membutuhkan streaming:

  • File transfer besar: Memecah file besar menjadi chunk yang dikirim bertahap.
  • Real-time chat: Pesan bisa terus mengalir dua arah.
  • Live data feed: Streaming monitor server, dashboard transaksi, dsb.

Tipe-Tipe Streaming pada gRPC

Ada empat jenis metode RPC di gRPC:

TipeClient StreamServer StreamContoh Skenario
UnaryRequest-Response
Server StreamingMonitor server
Client StreamingUpload file chunk
BidirectionalLive chat

Mari kita lihat diagram mermaid berikut untuk visualisasinya:

flowchart LR
    A[Unary] --> B1[Client Request] & B2[Server Response]
    C[Server Streaming] --> D1[Client Request] --> D2[Server Stream Data]
    E[Client Streaming] --> F1[Client Stream Data] --> F2[Server Response]
    G[Bidirectional] --> H1[Client Stream] <--> H2[Server Stream]

1. Unary RPC (Request-Response)

Paling sederhana, satu permintaan dibalas satu respons. Tidak ada streaming. Biasanya seperti ini di Protobuf:

service FileService {
    rpc GetFileMetadata(FileRequest) returns (FileMetadata) {}
}

2. Server Streaming RPC

Klien mengirim satu request, server membalas serangkaian data stream. Contoh kasus: dashboard yang ingin menampilkan update status server secara periodik.

service MonitorService {
    rpc MonitorStatus(Empty) returns (stream Status) {}
}

Alurnya:

  1. Client kirim request.
  2. Server kirim berkali-kali data/response hingga selesai.
  3. Client membaca stream data sampai habis.

Contoh kode Go (Server Streaming)

Definisi Protobuf:

syntax = "proto3";

service MonitorService {
    rpc MonitorStatus(Empty) returns (stream Status) {}
}

message Status {
    string server = 1;
    string state = 2;
    int32 cpuUsage = 3;
}

message Empty {}

Server Go:

func (s *server) MonitorStatus(req *Empty, stream MonitorService_MonitorStatusServer) error {
    for i := 0; i < 5; i++ {
        status := &Status{
            Server: "MyApp",
            State: "UP",
            CpuUsage: rand.Int31n(100),
        }
        if err := stream.Send(status); err != nil {
            return err
        }
        time.Sleep(2 * time.Second)
    }
    return nil
}

Client Go:

stream, _ := client.MonitorStatus(context.Background(), &Empty{})
for {
    status, err := stream.Recv()
    if err == io.EOF {
        break
    }
    fmt.Printf("Status: %+v\n", status)
}

3. Client Streaming RPC

Client dapat mengirim banyak pesan ke server, lalu server membalas satu kali response setelah semua pesan diterima.

Use-case: Mengirim bagian-bagian file (chunk) untuk diunggah.

Protobuf:

service FileService {
    rpc Upload(stream FileChunk) returns (UploadStatus) {}
}

message FileChunk {
    bytes content = 1;
}

message UploadStatus {
    string message = 1;
}

Server Go:

func (s *server) Upload(stream FileService_UploadServer) error {
    var totalBytes int
    for {
        chunk, err := stream.Recv()
        if err == io.EOF {
            return stream.SendAndClose(&UploadStatus{Message: fmt.Sprintf("Received %d bytes", totalBytes)})
        }
        totalBytes += len(chunk.Content)
    }
}

Client Go:

stream, _ := client.Upload(context.Background())
for i := 0; i < 10; i++ {
    stream.Send(&FileChunk{Content: []byte("part")})
}
resp, _ := stream.CloseAndRecv()
fmt.Println(resp.Message)

4. Bidirectional Streaming

Baik client maupun server dapat saling mengirim data stream kapan saja dan seberapa banyak.

Use-case: Real-time chat, collaborative editing, dsb.

Protobuf:

service ChatService {
    rpc Chat(stream ChatMessage) returns (stream ChatMessage) {}
}

message ChatMessage {
    string user = 1;
    string text = 2;
    int64 timestamp = 3;
}

Server Go:

func (s *server) Chat(stream ChatService_ChatServer) error {
    for {
        msg, err := stream.Recv()
        if err == io.EOF {
            return nil
        }
        // broadcast to other users (simplified)
        stream.Send(&ChatMessage{
            User: "Server",
            Text: "Received: " + msg.Text,
            Timestamp: time.Now().Unix(),
        })
    }
}

Client Go:

ctx := context.Background()
stream, _ := client.Chat(ctx)
go func() {
    for _, text := range []string{"Hi", "Apa kabar?"} {
        stream.Send(&ChatMessage{User: "Alice", Text: text, Timestamp: time.Now().Unix()})
        time.Sleep(time.Second)
    }
    stream.CloseSend()
}()
for {
    msg, err := stream.Recv()
    if err == io.EOF {
        break
    }
    fmt.Printf("Received: %s\n", msg.Text)
}

Simulasi Waktu & Efisiensi

Mari bandingkan upload file 100MB dengan RPC unary vs client streaming:

MetodeChunk SizeTotal RequestLatency per ReqEst. Total Time
Unary (100MB sekali)-15s5s
Streaming (10MB)10MB100.5s5s
Streaming pipeline10MB10parallel (0.5s)~0.5s

Pada streaming, chunk dapat dikirim bertahap & pipeline, sehingga selama bandwidth cukup, waktu lebih cepat dan resource lebih optimal.


Kesimpulan

gRPC Streaming membuka peluang komunikasi jaringan yang jauh lebih fleksibel, efisien, dan real-time dibandingkan RPC konvensional (unary). Berikut key takeaway-nya:

  • Gunakan server streaming untuk broadcast/monitoring.
  • Pilih client streaming untuk upload banyak data secara bertahap.
  • Manfaatkan bidirectional streaming untuk use-case dua arah real-time.
  • Streaming lebih efisien untuk data besar/berulang ketimbang unary.

Teknologi ini akan makin krusial seiring bergesernya aplikasi ke arah interaktif, event-driven, dan data intensif.

Semoga penjelasan, kode, dan diagram di atas bikin Anda makin mantap memahami streaming di gRPC. Sudah siap mengimplementasikannya ke sistem produksi Anda? 🚀

comments powered by Disqus

Topik Terhangat

programming
176
tips-and-trick
43
tutorial
43
jaringan
28
hardware
11
linux
4
kubernetes
1