İçeriğe geç

gRPC ve REST — Aynı Havale, İki Dil

Orta 9 dk Sık karşılaşılır

Önce şunu oku: Servisler Arası İletişim Desenleri

30 saniyede özet

REST çoğu zaman JSON taşır: okunur, her yerden çağrılır ama alan adlarını her mesajda tekrar eder. gRPC protobuf taşır: küçük ve şemalıdır, alanları numarayla eşler. Ad mı numara mı sözleşmedir, onu bilmek kırılmaları önler.

Bir mektup yazarken her bilginin önüne ne olduğunu yazarsın: “tutar: 2500 lira”. Bir resmî form ise yalnızca numaralı kutulardan oluşur; 2 numaralı kutuya tutarı yazarsın. Mektubu herkes okur, form kısadır ama hangi kutunun ne olduğunu bilmek için şablon gerekir.

  1. Bayt: Ödeme servisleri arasındaki çağrıları gRPC'ye taşıdık. Mesajlar yarı yarıya küçüldü!

  2. Sen: Geçen hafta bir alanı yeniden numaralandırmıştınız, değil mi?

  3. Bayt: Evet, düzen olsun diye. Şimdi bazı havalelerde alıcı IBAN'ı boş geliyor, hata da yok!

  4. Bayt: Protobuf'ta sözleşme alanın adı değil, numarası. Gel, iki dilin kurallarına bakalım.

İki biçim, aynı veri

REST çağrıları çoğu zaman JSON taşır: {"amountKurus": 250000, …}. Her mesaj alan adlarını da taşır; okunur ve curl ile denenebilir.

gRPCHTTP/2 üzerinde çalışan, mesajları protobuf ile taşıyan uzak çağrı çerçevesi. Şemadan istemci ve sunucu kodu üretilir; akışları destekler.Sözlükte gör → ise protobufProtocol Buffers: alanları adla değil numarayla taşıyan ikili mesaj biçimi. Küçüktür ve şemayla okunur; numara bir kez verilir, değişmez.Sözlükte gör → taşır. Şemada her alanın bir numarası vardır ve kablodan yalnızca numara ile sıkıştırılmış değer geçer. Bizim havale JSON’da 89 bayt, protobuf’ta 41 bayt.

Kafam karıştı, daha basit anlat

JSON etiketleri de taşır ve okunur. Protobuf yalnızca numaraları taşır ve küçüktür.

Hızlı kontrolBaşlangıç

Protobuf mesajı JSON'a göre neden genellikle daha küçüktür?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

gRPC hangi taşıma protokolünü kullanır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Sözleşme ad mı, numara mı?

Protobuf şemasında to_iban alanının numarası 4'ten 5'e değişti; eski istemciler güncellenmedi. Yeni sunucu bir havale gönderdiğinde eski istemci ne görür? Cevabı göster

Alıcı IBAN’ı boş görür, hata almaz. Eski istemci 5 numarayı tanımadığı için atlar; 4 numaralı alan da gelmediği için boş kalır.

Etiket mektubun, numara formun sözleşmesi.
Adım adım oku
  1. Mektupta her etiket yazılı; herkes okur ama uzun.
  2. Numaralı form kısa; okumak için şablon gerekir.
  3. Bilgi başka numaralı kutuya taşınırsa eski okuyucu boş kutuya bakar.
  4. Etiket mektubun, numara formun sözleşmesidir.

JSON alanları adla eşler: amountKurus adını amountMinor yaparsan eski istemci tutarı bulamaz. Protobuf alanları numarayla eşler: adı değiştirmek zararsızdır, numarayı değiştirmek ise veriyi sessizce kaybettirir.

Bu yüzden protobuf’ta kural nettir: bir numara bir kez verilir ve bir daha değişmez. Kaldırdığın alanın numarasını reserved yaparak yeniden kullanılmasını engellersin.

Kafam karıştı, daha basit anlat

JSON’da adı, protobuf’ta numarayı değiştirme. Yeni bir şey gerekiyorsa yeni bir alan ekle.

Hızlı kontrolOrta

JSON API'de bir alanın adı değişti ve eski istemciler güncellenmedi. Ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Protobuf'ta bir alanın adı değişti, numarası aynı kaldı. Eski istemci ne görür?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Aynı havale, iki protokol

Tohum 561478

Oynat ya da adımla.

Hız
Adım 0

Şu an ne oldu?

Bir mesaj kaç bayt?

REST + JSON

Görevler0/3

  • Aynı havaleyi en az baytla gönderaçık

    İpucu

    Alan adlarını taşımayan biçim.

  • Hiç hata vermeden alıcı IBAN'ını kaybetaçık

    İpucu

    Protobuf'ta neyi asla değiştirmemelisin?

  • Bir alanın adını değiştirip eski istemciyi kıraçık

    İpucu

    Alanları adla eşleyen biçim.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. JSON mesajı 89 bayt.
  2. Protokolü gRPC yap. Aynı havale 41 bayt.
  3. “Bir alanın adını değiştirdi” seç. JSON’da eski istemci kırıldı, gRPC’de kırılmadı.
  4. “Numarasını değiştirdi” seç, gRPC’de kal. Hata yok ama IBAN kayboldu.
  5. “Tarayıcıdan fetch” seç. gRPC için gRPC-Web ve bir proxy gerekiyor.
Hızlı kontrolOrta

Protobuf'ta to_iban alanı 4'ten 5'e taşındı. Eski istemci ne yaşar?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Bir tarayıcı uygulaması gRPC servisini çağırmak istiyor. Ne gerekir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tuzaklar

Tarayıcıdan doğrudan gRPC. Tarayıcılar yerel gRPC’nin ihtiyaç duyduğu HTTP/2 ayrıntılarına erişemez. gRPC-WebTarayıcıların gRPC servislerini çağırabilmesi için kullanılan uyarlama. Tarayıcı gRPC-Web konuşur, bir proxy onu gerçek gRPC'ye çevirir.Sözlükte gör → ve onu çeviren bir proxy gerekir; çoğu ekip dışarıya REST sunar.

Okunamayan mesajlar. Protobuf mesajını curl ya da log’da gözle okuyamazsın. grpcurl gibi araçlar ve şema dosyasının kendisi hata ayıklamanın parçası olur.

Zorunlu alan beklemek: protobuf 3’te gönderilmeyen bir alan varsayılan değerle (0, boş metin) okunur. “Tutar 0 mı, yoksa hiç gönderilmedi mi?” sorusunu şemada ayrıca çözmen gerekir.

Kafam karıştı, daha basit anlat

Tarayıcıya REST, içeride gRPC; okumak için araç kullan; varsayılan değeri eksik değerle karıştırma.

Hızlı kontrolOrta

Protobuf'ta bir alanı kaldırırken numarasını ne yapmalısın?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aşağıdaki örnek bir bankanın ödeme servisinden: protobuf şeması, kaldırılan alan için reserved, Spring ile gRPC servisi ve dışarıya açılan REST uç noktası.

Derinleş · Ödeme servisi: içeride gRPC, dışarıda REST 4 dosya · ~66 satır · ilk okumada atlayabilirsin
Proje dosyaları

src/main/proto/ transfer.proto Şema: her alanın sabit bir numarası; kaldırılan numara reserved, böylece yeniden kullanılamaz.

src/main/proto/transfer.proto
syntax = "proto3";
package bank.transfer.v1;
message Transfer {
int64 id = 1;
int64 amount_minor = 2; // renamed from amount_kurus: same number, wire-compatible
string currency = 3;
string to_iban = 4; // never renumber
reserved 5; // was "channel", removed; its number can never come back
reserved "channel";
}
service TransferService {
rpc Send (Transfer) returns (TransferResult);
}
message TransferResult {
int64 id = 1;
string status = 2;
}

src/main/java/com/bank/transfer/grpc/ TransferGrpcService.java gRPC servisi: servisler arası havale çağrısı.

src/main/java/com/bank/transfer/grpc/TransferGrpcService.java
// Service-to-service: small, schema-checked messages over HTTP/2.
@GrpcService
class TransferGrpcService extends TransferServiceGrpc.TransferServiceImplBase {
private final Transfers transfers;
TransferGrpcService(Transfers transfers) {
this.transfers = transfers;
}
@Override
public void send(Transfer request, StreamObserver<TransferResult> response) {
TransferResult result = transfers.send(request);
response.onNext(result);
response.onCompleted();
}
}

src/main/java/com/bank/transfer/web/ TransferController.java REST uç noktası: tarayıcı ve dış ortaklar için aynı işi JSON ile sunuyor.

src/main/java/com/bank/transfer/web/TransferController.java
// The browser and external partners get the same operation as JSON over REST.
@RestController
@RequestMapping("/api/transfers")
class TransferController {
private final Transfers transfers;
TransferController(Transfers transfers) {
this.transfers = transfers;
}
@PostMapping
TransferResponse send(@RequestBody TransferRequest request) {
return TransferResponse.from(transfers.send(request.toProto()));
}
}

src/test/java/com/bank/transfer/grpc/ WireCompatibilityTest.java Test: şemanın eski bir sürümüyle yazılmış mesaj yeni kodda doğru okunuyor.

src/test/java/com/bank/transfer/grpc/WireCompatibilityTest.java
class WireCompatibilityTest {
@Test
void aMessageWrittenBeforeTheRenameIsReadByTheNewCode() throws Exception {
// Bytes captured from the old schema, where field 2 was called amount_kurus.
byte[] oldBytes = OldTransfer.newBuilder().setId(1).setAmountKurus(250_000).build().toByteArray();
Transfer parsed = Transfer.parseFrom(oldBytes);
assertThat(parsed.getAmountMinor()).isEqualTo(250_000);
}
}

Kendini sına

Şimşek turu1/4

Protobuf mesajı her seferinde alan adlarını da taşır.

Soru 1/3İleri

Proto3'te amount alanı gönderilmezse alıcı ne görür?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 JSON her mesajda alan adlarını taşır ve insan okuyabilir. Protobuf yalnızca alan numaralarını ve sıkıştırılmış değerleri taşır; aynı havale 89 bayt yerine 41 bayt tutar.
  2. 2 JSON alanları adla, protobuf numarayla eşler. JSON'da ad değiştirmek eski istemciyi kırar; protobuf'ta ad değiştirmek zararsızdır ama numara değiştirmek veriyi sessizce kaybettirir.
  3. 3 Tarayıcı yerel gRPC konuşmaz; gRPC-Web ve bir proxy gerekir. Dışarıya REST, servisler arasında gRPC yaygın bir bölüşümdür.
Sonraki kapı Ödeme servisi olayı yayınladı, hata da almadı. Peki olay neden hiçbir servise ulaşmadı? RabbitMQ — Mesaj Hangi Kuyruğa Gider? · 9 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı