API Tasarımı & Gerçek Zamanlı İletişim 6 dk okuma 3 okunma

gRPC ile Streaming: Server, Client ve Bidirectional

gRPC'nin HTTP/2 üzerinde sunduğu dört iletişim modeli (Unary, Server Streaming, Client Streaming, Bidirectional Streaming), .proto tanımlamaları, .NET'te sunucu ve istemci implementasyonları, akış kontrolü, hata yönetimi, performans optimizasyonları ve gerçek dünya kullanım senaryoları ele alınır.

gRPC ile Streaming: Server, Client ve Bidirectional

gRPC ile Streaming: Server, Client ve Bidirectional Streaming

gRPC (gRPC Remote Procedure Call), Google tarafından geliştirilen, HTTP/2 üzerinde çalışan ve Protocol Buffers (Protobuf) ile binary serileştirme kullanan yüksek performanslı bir RPC framework'üdür. gRPC'nin en güçlü yanlarından biri, dört farklı iletişim modelini desteklemesidir: Unary (Tekli), Server Streaming (Sunucu Akışı), Client Streaming (İstemci Akışı) ve Bidirectional Streaming (Çift Yönlü Akış). Bu modeller, gerçek zamanlı veri akışı, büyük veri transferi ve etkileşimli uygulamalar için güçlü çözümler sunar. Bu yazıda, gRPC streaming modellerini, .proto tanımlamalarını, .NET'te sunucu ve istemci implementasyonlarını ve en iyi pratikleri detaylıca ele alacağız.


1. gRPC İletişim Modelleri (4 Temel Model)

Model Açıklama Kullanım Alanı
Unary RPC Klasik istek-yanıt modeli. İstemci bir istek gönderir, sunucu bir yanıt döner. Basit CRUD işlemleri, tek seferlik sorgular.
Server Streaming RPC İstemci bir istek gönderir, sunucu bir dizi yanıt döner (akış). Canlı veri akışı, büyük veri kümeleri, log takibi.
Client Streaming RPC İstemci bir dizi istek gönderir (akış), sunucu tek bir yanıt döner. Dosya yükleme, toplu veri gönderimi, telemetri.
Bidirectional Streaming RPC Hem istemci hem sunucu birbirine bağımsız olarak akış gönderir. Sohbet uygulamaları, oyunlar, gerçek zamanlı işbirliği.

2. Proto Tanımlamaları

Her streaming modeli, .proto dosyasında stream anahtar kelimesi ile tanımlanır.

protobuf

syntax = "proto3";

option csharp_namespace = "GrpcStreamingDemo";

package streaming;

service StreamService {
  // 1. Unary RPC
  rpc GetById (Request) returns (Response);

  // 2. Server Streaming RPC
  rpc GetStream (Request) returns (stream Response);

  // 3. Client Streaming RPC
  rpc UploadStream (stream Request) returns (Response);

  // 4. Bidirectional Streaming RPC
  rpc Chat (stream Request) returns (stream Response);
}

message Request {
  int32 id = 1;
  string message = 2;
}

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

3. Server Streaming (Sunucu Akışı)

Nasıl Çalışır? İstemci tek bir istek gönderir, sunucu ise bir dizi yanıt döner. Sunucu, veri akışını tamamlayana kadar yanıt göndermeye devam eder.

Sunucu Tarafı (.NET):

csharp

public class StreamService : StreamServiceBase
{
    // Server Streaming
    public override async Task GetStream(
        Request request,
        IServerStreamWriter<Response> responseStream,
        ServerCallContext context)
    {
        // 10 adet yanıt gönder
        for (int i = 0; i < 10; i++)
        {
            // İptal kontrolü (istemci bağlantıyı kapatırsa)
            if (context.CancellationToken.IsCancellationRequested)
                break;

            await responseStream.WriteAsync(new Response
            {
                Id = i,
                Message = $"Mesaj {i}: {request.Message}",
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });

            await Task.Delay(500); // Her mesaj arasında bekle
        }
    }
}

İstemci Tarafı (.NET):

csharp

var client = new StreamServiceClient(channel);

// Server Streaming - Yanıtları akış olarak oku
using var streamingCall = client.GetStream(new Request { Id = 1, Message = "Merhaba" });

await foreach (var response in streamingCall.ResponseStream.ReadAllAsync())
{
    Console.WriteLine($"Alındı: {response.Message}");
}

Kullanım Alanları:

  • Canlı borsa/finans verisi akışı

  • Sunucu log'larının gerçek zamanlı takibi

  • Büyük veri kümelerinin parça parça gönderimi

  • IoT sensör verisi akışı


4. Client Streaming (İstemci Akışı)

Nasıl Çalışır? İstemci bir dizi istek gönderir (akış), sunucu ise tüm istekleri aldıktan sonra tek bir yanıt döner.

Sunucu Tarafı (.NET):

csharp

public class StreamService : StreamServiceBase
{
    // Client Streaming
    public override async Task<Response> UploadStream(
        IAsyncStreamReader<Request> requestStream,
        ServerCallContext context)
    {
        int count = 0;
        int totalLength = 0;

        // İstemciden gelen tüm istekleri oku
        await foreach (var request in requestStream.ReadAllAsync())
        {
            count++;
            totalLength += request.Message.Length;
            Console.WriteLine($"İstek {count}: {request.Message}");
        }

        // Tek bir yanıt dön
        return new Response
        {
            Id = count,
            Message = $"Toplam {count} istek alındı, toplam uzunluk: {totalLength}",
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
        };
    }
}

İstemci Tarafı (.NET):

csharp

var client = new StreamServiceClient(channel);

// Client Streaming
using var streamingCall = client.UploadStream();

// Birden fazla istek gönder
for (int i = 0; i < 10; i++)
{
    await streamingCall.RequestStream.WriteAsync(new Request
    {
        Id = i,
        Message = $"Mesaj {i}"
    });
}

// Akışı tamamla
await streamingCall.RequestStream.CompleteAsync();

// Sunucudan tek yanıt al
var response = await streamingCall.ResponseAsync;
Console.WriteLine($"Sunucu yanıtı: {response.Message}");

Kullanım Alanları:

  • Dosya yükleme (chunk'lar halinde)

  • Toplu veri gönderimi (batch processing)

  • Telemetri toplama

  • Log toplama


5. Bidirectional Streaming (Çift Yönlü Akış)

Nasıl Çalışır? Hem istemci hem sunucu, birbirine bağımsız olarak akış gönderebilir. Her iki taraf da aynı anda okuma ve yazma yapabilir. Bu, gerçek zamanlı, etkileşimli uygulamalar için idealdir.

Sunucu Tarafı (.NET):

csharp

public class StreamService : StreamServiceBase
{
    // Bidirectional Streaming
    public override async Task Chat(
        IAsyncStreamReader<Request> requestStream,
        IServerStreamWriter<Response> responseStream,
        ServerCallContext context)
    {
        // Aynı anda hem oku hem yaz
        await foreach (var request in requestStream.ReadAllAsync())
        {
            // İstemciden gelen mesaja göre yanıt gönder
            await responseStream.WriteAsync(new Response
            {
                Id = request.Id,
                Message = $"Echo: {request.Message}",
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });
        }
    }
}

İstemci Tarafı (.NET):

csharp

var client = new StreamServiceClient(channel);

using var streamingCall = client.Chat();

// 1. Sunucudan gelen mesajları dinleyen bir görev başlat
var readTask = Task.Run(async () =>
{
    await foreach (var response in streamingCall.ResponseStream.ReadAllAsync())
    {
        Console.WriteLine($"Sunucu: {response.Message}");
    }
});

// 2. İstemciden sunucuya mesaj gönder
for (int i = 0; i < 5; i++)
{
    await streamingCall.RequestStream.WriteAsync(new Request
    {
        Id = i,
        Message = $"Mesaj {i}"
    });
    await Task.Delay(300);
}

// 3. Akışı tamamla ve okuma görevini bekle
await streamingCall.RequestStream.CompleteAsync();
await readTask;

Kullanım Alanları:

  • Sohbet (chat) uygulamaları

  • Çok oyunculu oyunlar

  • Gerçek zamanlı işbirliği araçları (Google Docs, Figma)

  • Canlı yayın ve etkileşimli yayıncılık

  • IoT cihaz kontrolü ve telemetri


6. gRPC Streaming'de Dikkat Edilmesi Gerekenler

A. Akış Kontrolü (Flow Control)
gRPC, HTTP/2'nin akış kontrolü mekanizmasını kullanır. Sunucu, istemciden daha hızlı veri gönderirse, akış kontrolü ile tampon (buffer) dolar ve sunucu beklemeye başlar. Bu, bellek taşmasını önler.

B. İptal (Cancellation)
Uzun süren akışlarda, istemci veya sunucu bağlantıyı iptal edebilir. Sunucu tarafında context.CancellationToken kontrol edilmelidir.

csharp

public override async Task GetStream(
    Request request,
    IServerStreamWriter<Response> responseStream,
    ServerCallContext context)
{
    while (!context.CancellationToken.IsCancellationRequested)
    {
        // ... veri gönder
    }
}

C. Hata Yönetimi (Error Handling)
Akış sırasında hata oluşursa, RpcException fırlatılır ve akış sonlanır.

csharp

try
{
    // ... akış işlemleri
}
catch (Exception ex)
{
    throw new RpcException(new Status(StatusCode.Internal, ex.Message));
}

D. Zaman Aşımları (Timeouts)
Uzun süren akışlarda, zaman aşımı ayarları dikkatli yapılmalıdır. Deadline veya timeout değerleri uygun şekilde belirlenmelidir.

E. Performans İpuçları:

  • Büyük Mesajlar: gRPC'de tek bir mesaj için varsayılan maksimum boyut 4MB'dir. Daha büyük mesajlar için MaxReceiveMessageSize ve MaxSendMessageSize ayarlanabilir.

  • Akış Boyutu: Akış başına mesaj boyutunu optimize edin. Çok büyük chunk'lar bellek sorunlarına yol açabilir.

  • HTTP/2 Multiplexing: Aynı bağlantı üzerinden birden fazla akış paralel olarak çalışabilir.


7. Ne Zaman Hangi Streaming Modelini Kullanmalısınız?

Senaryo Önerilen Model
Tek bir sorgu, tek bir yanıt Unary RPC
Sunucudan sürekli veri akışı (borsa, log) Server Streaming
İstemciden toplu veri gönderimi (dosya yükleme) Client Streaming
Karşılıklı, gerçek zamanlı iletişim (sohbet, oyun) Bidirectional Streaming
Büyük veri kümelerinin parça parça transferi Server Streaming
IoT telemetri toplama Client Streaming
Canlı işbirliği araçları Bidirectional Streaming

8. gRPC Streaming vs. WebSocket vs. SignalR

Özellik gRPC Streaming WebSocket SignalR
Protokol HTTP/2 + Protobuf WebSocket WebSocket, SSE, Long Polling
Veri Formatı Binary (Protobuf) Metin veya Binary Metin (JSON) veya Binary (MessagePack)
Tip Güvenliği ✅ Güçlü (.proto) ❌ Zayıf 🟡 Orta
Performans Çok Yüksek Yüksek Orta-Yüksek
Tarayıcı Desteği Sınırlı (gRPC-Web) ✅ Evet ✅ Evet
Kod Üretimi ✅ Otomatik ❌ Manuel 🟡 Kısmi
Kullanım Alanı Mikroservisler, M2M Genel gerçek zamanlı Web uygulamaları, .NET ekosistemi

Sonuç

gRPC streaming, modern dağıtık sistemlerde gerçek zamanlı, yüksek performanslı ve tip güvenli iletişim için güçlü bir araçtır. Server Streaming, sunucudan sürekli veri akışı için; Client Streaming, toplu veri gönderimi için; Bidirectional Streaming ise karşılıklı, etkileşimli iletişim için idealdir. .NET ekosisteminde gRPC, Grpc.AspNetCore ve Grpc.Net.Client paketleri ile tam desteklenir. HTTP/2'nin multiplexing ve akış kontrolü özelliklerini kullanarak, ölçeklenebilir ve verimli gerçek zamanlı uygulamalar geliştirebilirsiniz. gRPC-Web ile tarayıcı desteği de giderek güçlenmektedir; bu da gRPC'yi hem iç hem de dış API'ler için cazip bir seçenek haline getirmektedir.

Tüm yazılar Soru ya da yorumun mu var? Yaz