Merhaba arkadaşlar, bugün sizlere microservices mimarisinde başımı ağrıtan bir konudan ve nasıl bir çözüm bulduğumdan bahsedeceğim. Sistemimiz büyüdükçe, servisler arasındaki REST API çağrıları hem yavaşlamaya başladı hem de veri yapılarının tutarlılığını sağlamak kabus haline geldi. "Bu payload'ta `userId` mi `user_id` mi geliyordu?" diye düşünmekten kafayı yemiştim. İşte tam bu noktada gRPC ile tanıştım ve işler değişti.
REST API'de Yaşadığım Sıkıntılar
Öncelikle, klasik JSON over HTTP yaklaşımında neler beni zorluyordu onları paylaşayım. Her servis, kendi endpoint'ini ve döneceği JSON formatını belgeliyordu (Swagger/OpenAPI ile). Fakat bu sadece dokümantasyondu, runtime'da birisi string beklerken number gönderdiğinde hata ancak istek attıktan sonra, karşı taraftan dönen 400 hatasıyla anlaşılıyordu. Ayrıca, özellikle listeleyeceğimiz veriler çok büyüdüğünde, JSON'un parse edilme süresi ve HTTP/1.1'in overhead'i gözle görülür bir gecikmeye sebep oluyordu.
gRPC ve Protocol Buffers ile Tanışma
gRPC, Google'ın geliştirdiği, HTTP/2 üzerinden çalışan, performans odaklı bir RPC (Remote Procedure Call) çerçevesi. Asıl sihirli değnek ise onun tanımlama dili olan Protocol Buffers (protobuf). Protobuf dosyalarında (.proto), servislerinizin metodlarını ve iletişimde kullanacağınız mesaj formatlarını baştan, kesin kurallarla tanımlıyorsunuz. Bu .proto dosyası, hem sunucu hem de istemci tarafı için güçlü, tip-safe (tip güvenliği olan) kod üretmek için kullanılıyor.
Performans Avantajı: Binary ve HTTP/2
gRPC, veriyi JSON gibi metin tabanlı değil, binary (ikili) formatta (protobuf) taşıyor. Bu, boyutu ciddi oranda küçültüyor. Üstelik HTTP/2 sayesinde tek bir TCP bağlantısı üzerinden çoklu (multiplexed) istek gönderebiliyorsunuz, bu da bağlantı kurma maliyetini ortadan kaldırıyor. Sonuç? Bence en çarpıcı fark buydu. Bazı liste endpoint'lerimizde 5-6 kat daha hızlı yanıt süreleri gözlemledik.
Tip Güvenliği (Type Safety) ve Kesin Sözleşme
Bu benim en sevdiğim kısım. .proto dosyası, servisler arasında değişmez bir sözleşme (contract) görevi görüyor. `string userId` olarak tanımladığınız alana, istemci tarafından integer göndermeye çalışırsanız, kodunuz derleme aşamasında (compile-time) hata veriyor[/COLOR]. Runtime'da beklenmedik bir format hatasıyla karşılaşma derdi tarih oluyor. Ayrıca, bir alanın adını değiştirirseniz veya türünü güncellerseniz, bu değişikliği tüm ilgili servislerde yapmazsanız projeleriniz derlenmez. Bu, büyük ekiplerle çalışırken paha biçilmez bir güvenlik ağı.
İşte basit bir .proto dosyası örneği:
Ve bu tanımdan otomatik üretilen Node.js (TypeScript) kodunu kullanmak:
Sonuç ve Düşüncelerim
gRPC, özellikle microservices, mobil uygulama-backend iletişimi veya yüksek performans gerektiren dahili sistemler için REST API'ye kıyasla büyük avantajlar sunuyor. Tabii ki her şey güllük gülistanlık değil; browser tarafında doğrudan destek yok (grpc-web kullanmak gerek), debug etmek JSON kadar kolay değil ve öğrenme eğrisi var. Ancak, tip güvenliği ve performans kazancı, bu bedellere kesinlikle değdi.
Siz microservices projelerinizde hangi iletişim yöntemini tercih ediyorsunuz? REST API ile yaşadığınız performans veya veri tutarlılığı sorunları oldu mu? gRPC'ye geçmeyi düşündünüz mü veya farklı bir teknoloji (GraphQL, Message Queue) mi kullanıyorsunuz? Yorumlarda deneyimlerinizi paylaşın, tartışalım!
Öncelikle, klasik JSON over HTTP yaklaşımında neler beni zorluyordu onları paylaşayım. Her servis, kendi endpoint'ini ve döneceği JSON formatını belgeliyordu (Swagger/OpenAPI ile). Fakat bu sadece dokümantasyondu, runtime'da birisi string beklerken number gönderdiğinde hata ancak istek attıktan sonra, karşı taraftan dönen 400 hatasıyla anlaşılıyordu. Ayrıca, özellikle listeleyeceğimiz veriler çok büyüdüğünde, JSON'un parse edilme süresi ve HTTP/1.1'in overhead'i gözle görülür bir gecikmeye sebep oluyordu.
JavaScript:
// Örnek bir REST isteği ve belirsizlik
fetch('https://api.urunservisim.com/urunler')
.then(response => response.json())
.then(data => {
// data.products mı, data.items mı? price string mi number mı?
console.log(data.something); // Runtime'da hata!
});
gRPC, Google'ın geliştirdiği, HTTP/2 üzerinden çalışan, performans odaklı bir RPC (Remote Procedure Call) çerçevesi. Asıl sihirli değnek ise onun tanımlama dili olan Protocol Buffers (protobuf). Protobuf dosyalarında (.proto), servislerinizin metodlarını ve iletişimde kullanacağınız mesaj formatlarını baştan, kesin kurallarla tanımlıyorsunuz. Bu .proto dosyası, hem sunucu hem de istemci tarafı için güçlü, tip-safe (tip güvenliği olan) kod üretmek için kullanılıyor.
gRPC, veriyi JSON gibi metin tabanlı değil, binary (ikili) formatta (protobuf) taşıyor. Bu, boyutu ciddi oranda küçültüyor. Üstelik HTTP/2 sayesinde tek bir TCP bağlantısı üzerinden çoklu (multiplexed) istek gönderebiliyorsunuz, bu da bağlantı kurma maliyetini ortadan kaldırıyor. Sonuç? Bence en çarpıcı fark buydu. Bazı liste endpoint'lerimizde 5-6 kat daha hızlı yanıt süreleri gözlemledik.
Bu benim en sevdiğim kısım. .proto dosyası, servisler arasında değişmez bir sözleşme (contract) görevi görüyor. `string userId` olarak tanımladığınız alana, istemci tarafından integer göndermeye çalışırsanız, kodunuz derleme aşamasında (compile-time) hata veriyor[/COLOR]. Runtime'da beklenmedik bir format hatasıyla karşılaşma derdi tarih oluyor. Ayrıca, bir alanın adını değiştirirseniz veya türünü güncellerseniz, bu değişikliği tüm ilgili servislerde yapmazsanız projeleriniz derlenmez. Bu, büyük ekiplerle çalışırken paha biçilmez bir güvenlik ağı.
İşte basit bir .proto dosyası örneği:
Kod:
syntax = "proto3";
package urun;
service UrunService {
rpc UrunleriGetir (UrunListeIstek) returns (UrunListeCevap);
}
message UrunListeIstek {
int32 sayfa = 1;
int32 sayfa_boyutu = 2;
}
message UrunListeCevap {
repeated Urun urunler = 1;
int32 toplam_sayfa = 2;
}
message Urun {
string id = 1;
string ad = 2;
double fiyat = 3; // Tipi net: double
bool stokta_var = 4;
}
Ve bu tanımdan otomatik üretilen Node.js (TypeScript) kodunu kullanmak:
Kod:
import { UrunServiceClient } from './generated/urun_grpc_pb';
import { UrunListeIstek } from './generated/urun_pb';
const istek = new UrunListeIstek();
istek.setSayfa(1);
istek.setSayfaBoyutu(20);
// setFiyat("ucuz") YAPAMAZSINIZ! Derleme hatası.
// istek.setFiyat("ucuz"); // HATA: string, number bekleniyor.
client.urunleriGetir(istek, (hata, cevap) => {
const urunler = cevap.getUrunlerList();
const fiyat = urunler[0].getFiyat(); // Tipi kesin: number
});
gRPC, özellikle microservices, mobil uygulama-backend iletişimi veya yüksek performans gerektiren dahili sistemler için REST API'ye kıyasla büyük avantajlar sunuyor. Tabii ki her şey güllük gülistanlık değil; browser tarafında doğrudan destek yok (grpc-web kullanmak gerek), debug etmek JSON kadar kolay değil ve öğrenme eğrisi var. Ancak, tip güvenliği ve performans kazancı, bu bedellere kesinlikle değdi.
Siz microservices projelerinizde hangi iletişim yöntemini tercih ediyorsunuz? REST API ile yaşadığınız performans veya veri tutarlılığı sorunları oldu mu? gRPC'ye geçmeyi düşündünüz mü veya farklı bir teknoloji (GraphQL, Message Queue) mi kullanıyorsunuz? Yorumlarda deneyimlerinizi paylaşın, tartışalım!