Bu yazımızda ana hatlarıyla gRPC nedir, nerden gelmiştir, microservice mimarileri için nasıl kullanılır gibi konulara değinerek örnek bir uygulama üzerinde inceleyeceğiz.
gRPC open source olarak google tarafından geliştirlen ve ilk olarak 2015 yılında tanıtılan bir remote-procedure-call(RPC) kütüphanesidir. Transport için HTTP/2 prokolünü kullanır ve yine google tarafından ilk olarak şirket içi projelerde kullanılmak üzere geliştirilen bir binary serialization protocol'ü olan Protocol Buffers(protobuf) kullanarak serialize/deserialize edilmiş binary-message exchange yapabilen bir altyapı sunmaktadır. Protobuf temelde bir binary serialization protocol'üdür ve düşük CPU kullanımı ile yüksek performans gösterebilmesiyle öne çıkmaktadır. Özellikle son yıllarda IoT uygulamalarının kullanımının yaygınlaşmasıyla birlikte çok daha küçük avuç içi kadar teknolojik cihazlar arası iletişim söz konusu olduğundan gRPC IoT cihazlar arası iletişim için kullanılabilecek ilk seçeneklerden biri olarak görülmekte.
gRPC artık günümüzde Microservice mimarilerindede kullanılmakta. Microservice mimarisi üzerine bir yapı tasarladığınızda ve oldukça fazla sayıda service'iniz olduğunu düşünürsek, sürekli olarak bu microservice'ler arası veya service-to-3rd party uygulamalar arası bir iletişim sözkonusu olacaktır. Özellikle Restful service'ler yani çoğunlukla external bir client tarafından consume edilen yapılar için daha uygundur ve RESTful servisler daha çok human-optimized edilmiş text-based mesajlaşmaya dayandığından aslında internal service-to-service iletişim için en ideal seçenek değildir. Bunun yerine service-to-service internal communication için gRPC kullanmak son zamanlarda oldukça tercih edilir bir seçenek haline gelmekte ve nerdeyse bütün yazılım dillerini desteklediğinden Cloud Native Computing Foundation (CNCF) tarafından da benimsenerek gRPC'nin yeni evi olarak kabul edilmekte.
Örnek bir case üzerinden çalışma şekline bakacak olursak; bir e-ticaret sitesi geliştirdiğimizi düşünelim ve satmış olduğumuz bir ürün için müşteri iade isteğine bulunmak istiyor. gRPC Interface Definition Contract'lar tanımlayarak client-server arasındaki iletişimi http2 protocol’ü kullanılarak süreç tamamlanıyor. Sonrasında refund işleminin yapıldığına dair bilgilendirme NotifyCustomerClient'a iletilerek müşteri bilgilendiriliyor.
Yukarıda görüldüğü üzre, client'tan bir iade isteği geliyor ve bu istek proto formatında olan contract RefundService'e iletiliyor ve sonrasında kendi business'larını process ettikten sonra response'u client'a iletiyor. Bu contract dosyalarında herhangi bir değişiklik söz konusu olduğunda hem client hemde service tarafı bu değişiklikleri almak zorundadır.
gRPC'nin konseptlerine ve desteklediği client-server iletişim tiplerine bakacak olursak;
Unary RPC
Yukarıdaki refund örneğimize karşılık gelen, client'ın tek bir request atıp karşılığında bir response aldığı iletişim tipi.
Server streaming RPC
Server'ın client'tan request alıp geriye response stream dönmeye başladığı iletişim tipi.
Client streaming RPC
Server streaming'in tam tersi olarak client birden çok message gönderir ve server bu message'ları process ettikten sonra client'a tek bir response döner.
Bidirectional streaming RPC
Hem client'ın hemde server'ın karşılıklı message streaming yapabildi��i iletişim tipi.
Cancelling an RPC
Client yada server istedikleri bir anda RPC'yi cancel edebilirler ve bu hemen anlık olur.
Deadlines/Timeouts
gRPC client'lara bir timeout süresi set edebilmelerini ve server'larında herhangi bir RPC'nin timeout olup olmadığını sorgulayabilmelerine olanak sağlar.
Creating gRPC Service
Bu kadar terminolojiden sonra biraz practice yapalım ve yukarıda görselde bahsettiğimiz refund örneği üzerinden asp.net core 3.1 kullanarak bu yazımızı örneklendirelim. İlk olarak vs'da create new project deyip bir RefundService adında bir gRPC Service projesi oluşturalım.
Projemizi oluşturduktan sonra solution'a bakacak olursak; Yeni bir gRPC projesi oluşturduğunuzda default olarak vs'da GreeterService adında örnek bir gRPC implementation'ı ile birlikte gelmekte.
Görüldüğü üzre proje aslında bir GreeterService sınıfı ve bu sınıf için tanımlı olan greet.proto contract dosyasından oluşmakta. Daha doğrusu greet.proto dosyasında bulunan tanımlamalara göre generate edilen sınıflar GreeterBase ve GreeterService sınıfları projede yer almakta.
Startup.cs içerisine bakacak olursak projenizde gRPC kullanabilmek için uygulama service'lerine gRPC'yi eklemeniz gerekmekte ve sonrasında Configure metodu içerisinde oluşturmuş olduğumuz service-endpoint mapping'i endpointRouting'e tanımlamalıyız.
Add gRPC
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
Create refund.proto
refund.proto dosyasının içerisine metotlarımızı tanımlamaya başlayalım. RefundService'inde 2 metod bulunuyor, Refund() ve NotifyCustomer() metodları. Bunlardan Refund metodu Unary RPC tipinde işlem görürken, NotifyCustomer metodu Server Streaming RPC türünde hizmet verecektir.
syntax = "proto3";
option csharp_namespace = "RefundService";
package Refund;
service RefundService {
rpc Refund (RefundRequest) returns (RefundReply){}
rpc NotifyCustomer (NotifyRequest) returns (stream NotifyReply){}
}
message RefundRequest {
string orderId = 1;
double amount = 2;
string customerid = 3;
}
message RefundReply {
string message = 1;
}
message NotifyRequest {
}
message NotifyReply {
string orderId = 1;
string customerid = 2;
string message = 3;
}
Implement RefundService
RefundService sınıfına bakacak olursak; yukarıda tanımladığımız 2 metodun implementasyonunun bulunduğu kod bloklarından oluşan bi servis sınıfı olacaktır. Refund metodu müşterinin istekte bulunduğu iade işlemini tamamlarken NotifyCustomer metodu müşteriye iade işlemi ile ilgili bildirim göndermeden sorumlu metot görevi görecektir.
public class RefundService : global::RefundService.RefundService.RefundServiceBase
{
private readonly IRefundManager _refundManager;
public RefundService(IRefundManager refundManager)
{
_refundManager = refundManager;
}
public override Task<RefundReply> Refund(RefundRequest request, ServerCallContext context)
{
Console.WriteLine("CustomerId: " + request.Customerid + "\tOrderId: " + request.OrderId + "\tAmount:" + request.Amount + " refunded");
return Task.FromResult(new RefundReply
{
Message = "Reply from RefundService " + request.OrderId + " Refunded",
});
}
public override async Task NotifyCustomer(NotifyRequest request, IServerStreamWriter<NotifyReply> responseStream, ServerCallContext context)
{
while (!context.CancellationToken.IsCancellationRequested)
{
var refunds = _refundManager.GetRefundList();
foreach (var item in refunds)
{
var reply = new NotifyReply { OrderId = item };
await responseStream.WriteAsync(reply);
}
}
}
}
gRPC Service uygulamamız artık hazır tek yapmamız gereken uygulamayı çalıştırmak. Run ettikten sonra console'da aşağıdaki gibi service ile ilgili info-log'lar göreceksinizdir.
Sunucu, varsayılan ayarlara göre HTTPS (ve HTTP kullanarak 5000) kullanarak 5001 numaralı port'u dinlemeye başlayacaktır. RefundService uygulamamız artık hazır ve bir sonraki yazımızda yeni client'lar tanımlayarak Refund ve NotifyCustomer metotlarını consume edebiliriz.
Bu yazımızın sonuna gelmiş olduk. Özetleyecek olursak; gRPC nedir ne gibi amaçlar için kullanılır, en basit haliyle Asp.Net Core kullanılarak bir gRPC Service nasıl oluşturulur öğrenmiş olduk. Bir sonraki yazımızda bu servis metotları için client uygulamaları yazacağız. gRPC ile ilgili çok daha fazla örnek dotnet uygulamalarını bu sayfada bulabilirsiniz.
Source