tutorial

22 Implementasi Server-side Streaming RPC

gRPC telah menjadi salah satu protokol komunikasi yang paling banyak digunakan di ekosistem aplikasi mikroservis modern. Fungsi utamanya sebagai pengganti REST di banyak sistem tidak lepas dari fleksibilitas model RPC (Remote Procedure Call), kecepatan, serta kemampuan streaming datanya yang superior. Salah satu model streaming yang cukup powerful adalah Server-side Streaming RPC.

Pada artikel ini, saya akan membahas konsep Server-side Streaming RPC, langkah implementasinya, serta studi kasus menggunakan bahasa Go (golang). Untuk memudahkan pemahaman, akan ada contoh kode, simulasi alur request-response, dan tabel perbandingan sederhana antara model RPC lainnya.


Apa Itu Server-side Streaming RPC?

Pada skenario Server-side Streaming RPC, klien mengirimkan satu permintaan ke server dan menerima stream respons secara bertahap dari server hingga selesai. Intinya, server dapat mengirim lebih dari satu pesan kembali ke klien setelah permintaan awal diterima—mirip seperti “push notification” di jalur HTTP/2.

Diagram Alur

Mari kita visualisasikan alurnya menggunakan mermaid diagram:

sequenceDiagram
    participant Client
    participant Server

    Client->>Server: Send Request (permintaan tunggal)
    loop Selama masih ada data
        Server-->>Client: Stream Response (berulang kali)
    end
    Server-->>Client: (Stream selesai / EOF)

Kapan Menggunakan Server-side Streaming RPC?

Beberapa use case khas meliputi:

  • Pengiriman data dalam batch besar (report, file, logs)
  • Streaming hasil query database secara bertahap
  • Push notifikasi tentang status atau update proses latar belakang
  • Event-driven communication (misal: progres build pipeline)

Tabel berikut membandingkan model RPC dalam gRPC:

Jenis RPCRequestResponseContoh
Unary RPCSatuSatuGetUser() -> User
Server-side StreamingSatuStream (banyak)ListLogs() -> LogEntry*
Client-side StreamingStream (banyak)SatuUploadPhotos() -> UploadStatus
Bidirectional StreamingStreamStream (banyak, 2 arah)Chat() -> Message*/Message*


Studi Kasus: Streaming Log dengan gRPC Go

Kita akan membuat service gRPC sederhana bernama LogService, di mana klien dapat meminta log dan server akan membalas dengan stream data log secara bertahap.

1. Mendefinisikan Protobuf

File: log.proto

syntax = "proto3";

package log;

service LogService {
    rpc FetchLogs(LogRequest) returns (stream LogEntry) {}
}

message LogRequest {
    string filter = 1;
}

message LogEntry {
    int32 id = 1;
    string timestamp = 2;
    string message = 3;
}

2. Implementasi Server

File: server.go

package main

import (
    "context"
    "fmt"
    "log"
    "net"
    "time"

    "google.golang.org/grpc"

    pb "path/to/your/generated/proto/log"
)

type server struct {
    pb.UnimplementedLogServiceServer
}

func (s *server) FetchLogs(req *pb.LogRequest, stream pb.LogService_FetchLogsServer) error {
    logs := []pb.LogEntry{
        {Id: 1, Timestamp: "2024-06-05T10:00:00Z", Message: "Server started"},
        {Id: 2, Timestamp: "2024-06-05T10:10:00Z", Message: "Process completed"},
        {Id: 3, Timestamp: "2024-06-05T10:15:00Z", Message: "User login"},
    }

    for _, entry := range logs {
        // Simulasi log dikirim bertahap
        if err := stream.Send(&entry); err != nil {
            return err
        }
        time.Sleep(1 * time.Second) // Simulasi delay streaming
    }
    return nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterLogServiceServer(s, &server{})
    log.Println("gRPC server started at :50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

3. Implementasi Client

File: client.go

package main

import (
    "context"
    "log"
    "time"

    "google.golang.org/grpc"

    pb "path/to/your/generated/proto/log"
)

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewLogServiceClient(conn)

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    stream, err := c.FetchLogs(ctx, &pb.LogRequest{Filter: "all"})
    if err != nil {
        log.Fatalf("Error on FetchLogs: %v", err)
    }

    for {
        entry, err := stream.Recv()
        if err != nil {
            log.Printf("End of stream or error: %v", err)
            break
        }
        log.Printf("LogEntry: [%d] %s - %s", entry.Id, entry.Timestamp, entry.Message)
    }
}

4. Simulasi Interaksi Klien-Server

Mari gambarkan simulasi request dan response:

sequenceDiagram
    participant Client
    participant Server

    Client->>Server: FetchLogs({filter:"all"})
    Server-->>Client: LogEntry #1
    Note over Server,Client: (1 detik kemudian)
    Server-->>Client: LogEntry #2
    Note over Server,Client: (1 detik kemudian)
    Server-->>Client: LogEntry #3
    Server-->>Client: [EOF]

Tantangan dan Praktik Terbaik

1. Error Handling:
Stream bisa putus akibat jaringan atau error aplikasi. Pastikan error propagation jelas di kedua sisi; gunakan kode status gRPC (codes.Canceled, codes.Unavailable, dll).

2. Deadline/Timeout:
Klien wajib memberikan deadline agar stream tak menggantung selamanya.

3. Skalabilitas:
Streaming cocok untuk volume data besar, tapi tetaplah perhatikan batasan buffer, pool goroutine, dan pengaturan flow-control.

4. Versioning:
Jagalah backward-compatibility pada pesan stream, terutama jika ada klien/services lintas versi.


Kesimpulan

Server-side Streaming RPC adalah fitur powerful dari gRPC yang cocok untuk mengirimkan data dalam jumlah banyak atau bila respon tidak bisa sekaligus dikirim (misal, progres report, hasil query besar, notifikasi update, dsb).

Dengan memahami pola implementasi server-side streaming, engineer dapat:

  • Menghemat resource (karena data tak ditahan sebagai satu batch besar)
  • Meningkatkan responsifitas klien (data bisa segera diproses setelah diterima sebagian)
  • Memanfaatkan jalur komunikasi di HTTP/2 lebih optimal

Jika Anda ingin lebih siap menghadapi kebutuhan real-time atau big-data di backend sistem mikroservis Anda, server-side streaming adalah skill yang wajib dikuasai.


Referensi:

Jika artikel ini bermanfaat, jangan lupa share dan beri bintang!
Mari diskusi: implementasi streaming RPC seperti apa yang pernah kamu lakukan—dan apa tantangannya? Tulis di kolom komentar! 🚀

comments powered by Disqus

Topik Terhangat

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