Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

gRPC Kütüphanesi

gRPC, Google tarafından geliştirilen yüksek performanslı bir RPC çerçevesidir. HTTP/2 üzerinden çalışır ve Protocol Buffers kullanarak veri aktarımını optimize eder. Bu yapı, sunucu ve istemci arasında hızlı ve verimli iletişim sağlar. Çok dilli destek sunarak, farklı sistemlerin kolay entegrasyonunu mümkün kılar. Özellikle mikroservis mimarileri için uygun olan gRPC, ölçeklenebilir ve dil bağımsız iletişim imkanı sunar.
gRPC’nin Genel Tanıtımı
  • gRPC Nedir?: gRPC, Google tarafından geliştirilmiş, uzaktaki bir bilgisayarda bulunan fonksiyonları, sanki yerel bir fonksiyonmuş gibi çağırmanıza olanak sağlayan bir framework’tür.
  • gRPC’nin Farkı: Geleneksel RPC sistemlerinden farklı olarak, gRPC veri iletimini HTTP/2 protokolü üzerinden gerçekleştirir. Bu sayede daha hızlı ve daha verimli veri iletimi sağlanır.
HTTP/2 Protokolü Üzerine
  • HTTP/1.1 vs HTTP/2: HTTP/1.1 protokolü, bir web sayfasının her bir parçası için ayrı ayrı istekler gönderirken, HTTP/2, tüm verileri tek bir bağlantı üzerinden paralel olarak gönderir. Bu, veri iletimini hızlandırır ve daha verimli hale getirir.
  • Multiplexing: HTTP/2’nin sunduğu en önemli özelliklerden biri multiplexing’dir. Bu, tek bir bağlantı üzerinden birden fazla veri akışının paralel olarak gönderilmesine olanak tanır.
gRPC’nin Kullanım Alanları ve Avantajları
  • Veri İletimi: gRPC, veri iletimini metinsel değil, binary (ikili) formatta gerçekleştirir. Bu, özellikle büyük veri setlerinin daha hızlı iletilmesini sağlar.
  • Protobuf (Protocol Buffers): gRPC, verileri iletmek için Google tarafından geliştirilmiş olan Protobuf adlı bir formatı kullanır. Bu format, veriyi sıkıştırır ve daha hızlı iletim sağlar.
  • Mikroservis Mimarisi: gRPC, özellikle mikroservis mimarilerinde kullanışlıdır. Mikroservisler arasındaki iletişimi hızlandırmak ve daha verimli hale getirmek için kullanılabilir.
gRPC’nin Diğer Sistemlerle Karşılaştırılması
  • REST vs gRPC: REST API’leri genellikle dış dünyayla etkileşim için kullanılır ve metinsel veri iletimi yapar. Ancak, gRPC, mikroservisler arasındaki iç iletişimde daha hızlı ve daha etkili olabilir.
  • JSON vs Protobuf: JSON, insan tarafından okunabilir bir format olmasına rağmen, Protobuf daha hızlı ve daha verimlidir. gRPC, Protobuf kullanarak veri iletimini hızlandırır.
gRPC İletişim Türleri
  • Unary RPC: İstemci, sunucuya bir istek gönderir ve tek bir yanıt alır. Bu, klasik bir istek-cevap modeli gibidir.
  • Server Streaming RPC: İstemci, sunucuya bir istek gönderir ve sunucu birden fazla yanıt döndürebilir.
  • Client Streaming RPC: İstemci, sunucuya birden fazla istek gönderir ve sunucu bunları işledikten sonra tek bir yanıt döner.
  • Bidirectional Streaming RPC: Hem istemci hem de sunucu aynı anda veri gönderebilir ve alabilir. Bu tür, çift yönlü veri akışını mümkün kılar.
gRPC’nin Dezavantajları ve Gelecek Potansiyeli
  • Tarayıcı Desteği: gRPC’nin tarayıcı tabanlı desteği sınırlıdır, ancak bu durumun gelecekte değişmesi beklenmektedir.
  • Farklı Platformlar Arasında Kullanım: gRPC, farklı programlama dilleri ve platformlar arasında çalışabilir, bu da esnek ve güçlü bir çözüm olmasını sağlar.

gRPC Kütüphanesi – Veri İletim Türleri

gRPC, Google tarafından geliştirilen ve özellikle mikroservis mimarilerinde kullanılan, yüksek performanslı bir iletişim protokolüdür. gRPC’nin temel amacı, farklı dillerde geliştirilmiş servisler arasında hızlı ve güvenilir veri iletişimi sağlamaktır. Bu makalede, gRPC kütüphanesinin veri iletim türlerini detaylı bir şekilde inceleyeceğiz. Bu türler, farklı senaryolar için optimize edilmiştir ve her birinin kendine özgü kullanım alanları bulunmaktadır.

gRPC Veri İletim Türleri

gRPC’de dört ana veri iletim türü vardır:

  1. Unary (Tekil) RPC
  2. Server Streaming (Sunucu Akışı) RPC
  3. Client Streaming (İstemci Akışı) RPC
  4. Bidirectional Streaming (Çift Yönlü Akış) RPC

Bu veri iletim türlerinin her birini detaylı bir şekilde ele alalım.

1. Unary (Tekil) RPC

Tanım: Unary RPC, istemcinin sunucuya tek bir istek göndermesi ve karşılığında tek bir yanıt alması modeline dayanır. Bu model, geleneksel RESTful API’lerdeki HTTP GET/POST işlemlerine benzer.

Örnek Senaryo: Bir kullanıcı kimlik doğrulama servisi düşünelim. İstemci, kullanıcı adı ve şifreyi içeren bir istek gönderir ve sunucu, doğrulama sonucunu (başarılı veya başarısız) içeren tek bir yanıt döner.

Kod Örneği:

// Proto dosyasında tanımlama
service AuthService {
    rpc Login (LoginRequest) returns (LoginResponse);
}

message LoginRequest {
    string username = 1;
    string password = 2;
}

message LoginResponse {
    string token = 1;
    bool success = 2;
    string message = 3;
}
2. Server Streaming (Sunucu Akışı) RPC

Tanım: Server Streaming RPC modelinde, istemci sunucuya bir istek gönderir ve sunucu, istemciye tek bir yanıt yerine bir veri akışı gönderir. İstemci bu akışı okur ve işlemeye devam eder.

Örnek Senaryo: Bir haber servisi düşünelim. İstemci, belirli bir kategorideki haber başlıklarını talep eder ve sunucu, istemciye bu kategoriye ait tüm haber başlıklarını sıralı bir şekilde gönderir.

Kod Örneği:

// Proto dosyasında tanımlama
service NewsService {
    rpc GetNewsByCategory (NewsRequest) returns (stream NewsResponse);
}

message NewsRequest {
    string category = 1;
}

message NewsResponse {
    string headline = 1;
    string article_url = 2;
}
Sunucu Tarafı Implementasyonu:
public override async Task GetNewsByCategory(NewsRequest request, IServerStreamWriter<NewsResponse> responseStream, ServerCallContext context) {
    var news = GetNewsByCategory(request.Category); // Haber başlıklarını al
    foreach (var article in news) {
        await responseStream.WriteAsync(new NewsResponse {
            Headline = article.Headline,
            ArticleUrl = article.Url
        });
    }
}
3. Client Streaming (İstemci Akışı) RPC

Tanım: Client Streaming RPC modelinde, istemci sunucuya bir veri akışı gönderir ve sunucu bu akış tamamlandığında tek bir yanıt döner. Bu model, sunucunun istemciden toplu veri almasını sağlar.

Örnek Senaryo: Bir dosya yükleme servisi düşünelim. İstemci, büyük bir dosyayı küçük parçalara bölerek sunucuya gönderir. Sunucu, dosya tamamen yüklendiğinde bir yanıt döner.

Kod Örneği:

// Proto dosyasında tanımlama
service UploadService {
    rpc UploadFile (stream FileChunk) returns (UploadResponse);
}

message FileChunk {
    bytes data = 1;
}

message UploadResponse {
    bool success = 1;
    string message = 2;
}
İstemci Tarafı Implementasyonu:
public async Task UploadFile(string filePath, UploadService.UploadServiceClient client) {
    using var call = client.UploadFile();
    byte[] buffer = new byte[4096];
    int bytesRead;
    using (var fileStream = new FileStream(filePath, FileMode.Open)) {
        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0) {
            await call.RequestStream.WriteAsync(new FileChunk { Data = ByteString.CopyFrom(buffer, 0, bytesRead) });
        }
    }
    await call.RequestStream.CompleteAsync();
    var response = await call.ResponseAsync;
    Console.WriteLine($"Upload {(response.Success ? "Succeeded" : "Failed")}: {response.Message}");
}
4. Bidirectional Streaming (Çift Yönlü Akış) RPC

Tanım: Bidirectional Streaming RPC, istemci ve sunucunun birbirine veri akışı gönderebildiği en esnek veri iletim türüdür. İstemci ve sunucu bağımsız olarak veri akışı başlatabilir ve her iki taraf da verileri paralel olarak işleyebilir.

Örnek Senaryo: Bir chat uygulaması düşünelim. Hem istemci hem de sunucu, anlık olarak mesaj gönderip alabilir.

Kod Örneği:

// Proto dosyasında tanımlama
service ChatService {
    rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}

message ChatMessage {
    string user = 1;
    string message = 2;
    int64 timestamp = 3;
}
Çift Yönlü Akış Implementasyonu:
public async Task Chat(ChatService.ChatServiceClient client) {
    using var call = client.Chat();
    var responseTask = Task.Run(async () => {
        await foreach (var response in call.ResponseStream.ReadAllAsync()) {
            Console.WriteLine($"{response.User} at {response.Timestamp}: {response.Message}");
        }
    });

    while (true) {
        var message = Console.ReadLine();
        if (message == "exit") break;
        await call.RequestStream.WriteAsync(new ChatMessage {
            User = "client",
            Message = message,
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
        });
    }
    await call.RequestStream.CompleteAsync();
    await responseTask;
}

gRPC Kütüphanesi Kullanarak Dosya Yükleme ve İndirme Uygulaması

Projemizde bir istemci (client) ve bir sunucu (server) bulunacak. İstemci, bir dosya yüklemek veya indirmek istediğinde sunucuya bir istek gönderir. Sunucu ise bu isteği işler ve dosya transferini gerçekleştirir.

İlk Adım: gRPC Protokolü ve Protobuf Tanımları

gRPC projelerinde iletişimin sağlanabilmesi için öncelikle bir protokol (Protobuf) tanımlaması yapmamız gerekmektedir. Bu tanımlama, istemci ile sunucu arasındaki iletişim sözleşmesini belirler. Dosya yükleme ve indirme operasyonları için aşağıdaki gibi bir Protobuf dosyası (file_transfer.proto) oluşturulabilir:

syntax = "proto3";

option csharp_namespace = "FileTransfer";

message FileInfo {
    string file_name = 1;
    int64 file_size = 2;
    string file_extension = 3;
}

message FileChunk {
    int64 chunk_size = 1;
    bytes content = 2;
    int32 chunk_number = 3;
}

service FileService {
    rpc UploadFile(stream FileChunk) returns (google.protobuf.Empty);
    rpc DownloadFile(FileInfo) returns (stream FileChunk);
}

FileInfo Mesajı: Bu mesaj, dosyanın genel bilgilerini (isim, boyut ve uzantı) içerir.

FileChunk Mesajı: Bu mesaj, dosyanın parça parça transfer edilmesi için kullanılır. Her bir parça, dosyanın belirli bir bölümünü içerir.

FileService Servisi: Bu servis, iki temel işlemi (Upload ve Download) tanımlar. UploadFile fonksiyonu istemciden sunucuya dosya yüklemek için kullanılırken, DownloadFile fonksiyonu sunucudan istemciye dosya indirmek için kullanılır.

gRPC Sunucusunu Oluşturma

Sunucu tarafında, yukarıda tanımlanan servisi implement etmemiz gerekecek. İşte sunucu tarafında FileService servisini implement eden bir örnek:

using System.IO;
using System.Threading.Tasks;
using Grpc.Core;
using Google.Protobuf.WellKnownTypes;

public class FileServiceImpl : FileService.FileServiceBase
{
    private const string UploadDirectory = "UploadedFiles";

    public override async Task<Empty> UploadFile(IAsyncStreamReader<FileChunk> requestStream, ServerCallContext context)
    {
        Directory.CreateDirectory(UploadDirectory);

        FileInfo fileInfo = null;
        FileStream fileStream = null;

        await foreach (var chunk in requestStream.ReadAllAsync())
        {
            if (fileInfo == null)
            {
                fileInfo = new FileInfo
                {
                    FileName = chunk.FileName,
                    FileSize = chunk.FileSize,
                    FileExtension = chunk.FileExtension
                };

                string filePath = Path.Combine(UploadDirectory, fileInfo.FileName + fileInfo.FileExtension);
                fileStream = new FileStream(filePath, FileMode.Create);
            }

            await fileStream.WriteAsync(chunk.Content.ToByteArray(), 0, chunk.Content.Length);
        }

        fileStream?.Close();

        return new Empty();
    }

    public override async Task DownloadFile(FileInfo request, IServerStreamWriter<FileChunk> responseStream, ServerCallContext context)
    {
        string filePath = Path.Combine(UploadDirectory, request.FileName + request.FileExtension);

        if (!File.Exists(filePath))
        {
            throw new RpcException(new Status(StatusCode.NotFound, "File not found"));
        }

        using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        var buffer = new byte[2048];
        int bytesRead;
        int chunkNumber = 0;

        while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            var chunk = new FileChunk
            {
                Content = Google.Protobuf.ByteString.CopyFrom(buffer, 0, bytesRead),
                ChunkSize = bytesRead,
                ChunkNumber = chunkNumber++
            };

            await responseStream.WriteAsync(chunk);
        }
    }
}

Bu örnekte:

  • UploadFile metodu, istemciden gelen dosya parçalarını alır ve sunucuya kaydeder.
  • DownloadFile metodu, sunucudan istemciye dosya parçalarını gönderir.
gRPC İstemcisini Oluşturma

Şimdi, istemci tarafında dosya yükleme ve indirme işlemlerini gerçekleştirelim. İşte istemci tarafında bu işlemleri yapan bir örnek:

using System;
using System.IO;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;

public class FileTransferClient
{
    private readonly FileService.FileServiceClient _client;

    public FileTransferClient(FileService.FileServiceClient client)
    {
        _client = client;
    }

    public async Task UploadFileAsync(string filePath)
    {
        using var call = _client.UploadFile();

        var fileInfo = new FileInfo(filePath);
        byte[] buffer = new byte[2048];
        int bytesRead;

        using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                var chunk = new FileChunk
                {
                    Content = Google.Protobuf.ByteString.CopyFrom(buffer, 0, bytesRead),
                    ChunkSize = bytesRead
                };

                await call.RequestStream.WriteAsync(chunk);
            }
        }

        await call.RequestStream.CompleteAsync();
        await call.ResponseAsync;
    }

    public async Task DownloadFileAsync(string fileName, string destinationPath)
    {
        var request = new FileInfo { FileName = fileName, FileExtension = Path.GetExtension(fileName) };

        using var call = _client.DownloadFile(request);
        await foreach (var chunk in call.ResponseStream.ReadAllAsync())
        {
            using (var fileStream = new FileStream(destinationPath, FileMode.Append))
            {
                await fileStream.WriteAsync(chunk.Content.ToByteArray());
            }
        }
    }
}

Bu istemci kodu:

  • UploadFileAsync metodu ile istemcideki bir dosyayı sunucuya yükler.
  • DownloadFileAsync metodu ile sunucudaki bir dosyayı istemciye indirir.
Kaynakça:

Başlamanın yolu, konuşmayı bırakıp yapmaya başlamaktır.

Walt Disney

Bir sonraki yazıda görüşmek dileğiyle!”

Leave a Reply

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir


10 + 7 = ?