tutorial

23 Implementasi Client-side Streaming RPC

Dalam dunia microservices modern, gRPC telah menjadi salah satu pilihan utama untuk membangun komunikasi antar layanan yang efisien, terutama jika mengutamakan performa dan fleksibilitas. Salah satu fitur powerful dari gRPC adalah dukungan terhadap streaming RPC. Kali ini, mari kita fokus pada Client-side Streaming RPC, di mana klien dapat mengirimkan banyak pesan secara berurutan ke server, sebelum akhirnya menerima satu respon agregat dari server.

Artikel ini akan membahas konsep, skenario penggunaan, serta memberikan contoh implementasi Client-side Streaming RPC menggunakan Go (golang). Untuk memperjelas, akan disertakan diagram flowchart dan simulasi komunikasi agar Anda mendapatkan gambaran lengkap terkait fitur ini.


Apa Itu Client-side Streaming RPC?

Pada Client-side Streaming RPC, alur komunikasinya kurang lebih seperti berikut:

  • Klien membuka koneksi dan secara bertahap mengirimkan beberapa pesan ke server menggunakan stream.
  • Setelah semua data dikirim, klien menutup stream.
  • Server memproses semua data dan mengirimkan satu respon kembali ke klien.

Berbeda dengan Unary RPC (satu permintaan-satu jawaban) atau Server Streaming (satu permintaan-respon bertahap), di streaming client-side klien memegang kendali berapa banyak pesan yang dikirim sebelum meminta jawaban dari server.

Contoh Use Case

Use caseDeskripsi
Upload file bertahapKlien mengirim bagian file satu per satu ke server
Pengiriman batch data IoTDevice IoT mengirimkan data sensor bertahap ke server
Client-side loggingKlien mengirimkan banyak pesan log lalu menerima summary

Arsitektur dan Flow

Mari kita lihat diagram interaksinya dengan Mermaid:

sequenceDiagram
    participant Client
    participant Server

    Client->>Server: Buka stream
    loop Satu per satu
      Client->>Server: Kirim message (chunk data)
    end
    Client-->>Server: Tutup stream (Done)
    Server-->>Client: Kirim respon hasil agregasi

Pada dasarnya, streaming dimulai ketika klien membuka stream, mengirim semua pesan (bisa loop, misal saat user upload 10MB file dikirim chunk 512KB secara bertahap), lalu akhirnya closing stream dengan CloseAndRecv. Server baru akan memproses setelah stream ditutup.


Skema Protobuf untuk Client-streaming

Misalkan kita ingin mengimplementasikan fitur upload file bertahap seperti Google Drive. Kita dapat mendefinisikan service gRPC di file upload.proto sebagai berikut:

syntax = "proto3";

service FileService {
  // UploadFile: Client streaming, server hanya kirim satu hasil.
  rpc UploadFile (stream Chunk) returns (UploadStatus);
}

message Chunk {
  bytes content = 1;
}

message UploadStatus {
  bool success = 1;
  string message = 2;
}

Penjelasan:

  • Chunk: Struktur pesan yang dikirim klien. Biasanya berisi bagian file (bytes).
  • UploadStatus: Respon status akhir dari server.

Implementasi Client-side Streaming RPC

1. Implementasi Server (Go/gRPC)

Pada server, kita perlu meng-handle data secara bertahap sampai stream client ditutup, kemudian membalas dengan satu pesan.

// file_service.go
type FileServiceServer struct {
  pb.UnimplementedFileServiceServer
}

func (s *FileServiceServer) UploadFile(stream pb.FileService_UploadFileServer) error {
    fmt.Println("Start receiving file chunks...")
    var totalBytes int64
    for {
        chunk, err := stream.Recv()
        if err == io.EOF {
            // Selesai, balas ke client
            return stream.SendAndClose(&pb.UploadStatus{
                Success: true,
                Message: fmt.Sprintf("Upload selesai: %d bytes diterima.", totalBytes),
            })
        }
        if err != nil {
            return err
        }
        // Simulasi write ke disk
        totalBytes += int64(len(chunk.Content))
    }
}

Penjelasan:

  • stream.Recv(): Mendapatkan setiap chunk dari klien.
  • Saat stream EOF (klien tutup stream), server membalas status upload.

2. Implementasi Client (Go/gRPC)

Sisi klien akan membuka stream lalu mengirimkan data secara bertahap.

func uploadFile(client pb.FileServiceClient, filePath string) {
    ctx := context.Background()
    stream, err := client.UploadFile(ctx)
    if err != nil {
        log.Fatalf("Gagal membuka stream: %v", err)
    }

    file, err := os.Open(filePath)
    if err != nil {
        log.Fatalf("Gagal buka file: %v", err)
    }
    defer file.Close()

    buf := make([]byte, 512*1024) // Chunk 512KB
    for {
        n, err := file.Read(buf)
        if n > 0 {
            if err := stream.Send(&pb.Chunk{Content: buf[:n]}); err != nil {
                log.Fatalf("Gagal kirim chunk: %v", err)
            }
        }
        if err == io.EOF {
            break
        } else if err != nil {
            log.Fatalf("Gagal baca file: %v", err)
        }
    }

    status, err := stream.CloseAndRecv()
    if err != nil {
        log.Fatalf("Gagal menerima status upload: %v", err)
    }
    fmt.Printf("Server reply: %v\n", status.Message)
}

Simulasi Komunikasi

Mari kita simulasikan pengiriman file 2MB dalam potongan 512KB:

Urutan ChunkUkuran (KB)Event di Server
1512Menerima chunk 1 (akumulasi: 512KB)
2512Menerima chunk 2 (1MB)
3512Menerima chunk 3 (1.5MB)
4512Menerima chunk 4 (2MB)
EOF-Stream tutup, kirim status

Respons server:

“Upload selesai: 2097152 bytes diterima.”


Kapan Menggunakan Client-side Streaming?

Gunakan Client-side Streaming RPC ketika:

  • Data dari klien besar/banyak & ingin menghindari satu payload raksasa.
  • Data realtime yang ingin dikirim bertahap sebelum hasil agregasi diproses.
  • Klien punya data dalam batch, misal update ribuan records sekaligus.

Perbandingan (Tabel)

TeknikCara KerjaKelebihanKekurangan
Unary RPCSatu permintaan-responSimple, mudah di-implementasiPayload terbatas
Server streamingServer kirim streamRespon terus-menerusClient hanya bisa kirim satu request
Client streamingClient kirim streamClient bisa batching dataAgak kompleks
Bi-directionalDua arah streamFull-duplex, sangat fleksibelKomunikasi rumit

Kesimpulan

Client-side Streaming RPC sangat bermanfaat untuk efisiensi komunikasi data skala besar atau batch tanpa membebani server atau jaringan dengan satu payload besar. Dengan dukungan protokol gRPC, implementasinya relatif sederhana dan scalable. Semoga artikel ini membantu Anda memahami dan mengimplementasikan pola ini!

Jika ingin diskusi lebih lanjut atau contoh di bahasa lain, silakan tinggalkan komentar!


Happy Streaming! 🚀

comments powered by Disqus

Topik Terhangat

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