1. Giriş
Bu codelab'de, Java ile yazılmış bir rota eşleme uygulamasının temelini oluşturan bir istemci ve sunucu oluşturmak için gRPC-Java'yı kullanacaksınız.
Eğitimin sonunda, haritada belirli koordinatlarda bulunan yerin adını veya posta adresini almak için gRPC kullanarak uzak bir sunucuya bağlanan bir istemciniz olacak. Tam teşekküllü bir uygulama, bir rota üzerindeki önemli yerleri listelemek veya özetlemek için bu istemci-sunucu tasarımını kullanabilir.
Sunucunun API'si, istemci ve sunucu için standart kod oluşturmak üzere kullanılacak bir Protocol Buffers dosyasında tanımlanır. Böylece istemci ve sunucu birbirleriyle iletişim kurabilir. Bu işlevselliği uygulamak için harcayacağınız zamandan ve emekten tasarruf edersiniz.
Oluşturulan bu kod, yalnızca sunucu ile istemci arasındaki iletişimin karmaşıklıklarını değil, aynı zamanda veri serileştirme ve seri durumdan çıkarma işlemlerini de ele alır.
Neler öğreneceksiniz?
- Hizmet API'sini tanımlamak için Protocol Buffers'ı kullanma.
- Otomatik kod oluşturma kullanarak bir Protokol Arabellek tanımından gRPC tabanlı istemci ve sunucu oluşturma.
- gRPC ile istemci-sunucu iletişimi hakkında bilgi sahibi olmanız gerekir.
Bu codelab, gRPC'ye yeni başlayan veya gRPC ile ilgili bilgilerini tazelemek isteyen Java geliştiricilerin yanı sıra dağıtılmış sistemler oluşturmakla ilgilenen herkes için hazırlanmıştır. Daha önce gRPC deneyimi gerekmez.
2. Başlamadan önce
Ön koşullar
- JDK 8 veya sonraki sürümler
Kodu alın
Bu codelab, tamamen sıfırdan başlamanız gerekmemesi için uygulamanın kaynak kodunun tamamlayabileceğiniz bir iskeletini sağlar. Aşağıdaki adımlarda, protokol arabellek derleyici eklentilerini kullanarak standart gRPC kodu oluşturma da dahil olmak üzere uygulamanın nasıl tamamlanacağı gösterilmektedir.
Öncelikle codelab çalışma dizinini oluşturun ve bu dizine gidin:
mkdir grpc-java-getting-started && cd grpc-java-getting-started
Codelab'i indirip ayıklayın:
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-1/codelabs/grpc-java-getting-started/start_here
Alternatif olarak, yalnızca codelab dizinini içeren .zip dosyasını indirebilir ve manuel olarak sıkıştırmasını açabilirsiniz.
Bir uygulamayı yazmayı atlamak isterseniz tamamlanmış kaynak kodunu GitHub'da bulabilirsiniz.
3. Hizmeti tanımlama
İlk adımınız, Protocol Buffers'ı kullanarak uygulamanın gRPC hizmetini, RPC yöntemini, istek ve yanıt mesajı türlerini tanımlamaktır. Hizmetinizde sunulacaklar:
- Sunucunun uyguladığı ve istemcinin çağırdığı
GetFeature
adlı bir RPC yöntemi. GetFeature
yöntemi kullanılırken istemci ile sunucu arasında değiştirilen veri yapıları olanPoint
veFeature
mesaj türleri. İstemci, sunucuya gönderdiğiGetFeature
isteğinde harita koordinatlarınıPoint
olarak sağlar ve sunucu, bu koordinatlarda bulunan her şeyi açıklayan ilgili birFeature
ile yanıt verir.
Bu RPC yöntemi ve mesaj türleri, sağlanan kaynak kodun src/main/proto/routeguide/route_guide.proto
dosyasında tanımlanır.
Protocol Buffers genellikle protobuf olarak bilinir. gRPC terminolojisi hakkında daha fazla bilgi için gRPC'nin Temel kavramlar, mimari ve yaşam döngüsü başlıklı makalesine bakın.
Bu örnekte Java kodu oluşturduğumuz için java_package
dosya seçeneğini ve .proto
içinde Java sınıfı için bir ad belirledik:
option java_package = "io.grpc.examples.routeguide";
option java_outer_classname = "RouteGuideProto";
Mesaj türleri
Kaynak kodun routeguide/route_guide.proto
dosyasında önce Point
mesaj türünü tanımlayın. Point
, haritadaki bir enlem-boylam koordinat çiftini temsil eder. Bu codelab'de koordinatlar için tam sayıları kullanın:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
1
ve 2
sayıları, message
yapısındaki her alan için benzersiz kimlik numaralarıdır.
Ardından, Feature
mesaj türünü tanımlayın. Bir Feature
, Point
ile belirtilen bir konumdaki bir şeyin adı veya posta adresi için string
alanını kullanır:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Hizmet yöntemi
route_guide.proto
dosyasında, uygulamanın hizmeti tarafından sağlanan bir veya daha fazla yöntemi tanımlayan RouteGuide
adlı bir service
yapısı bulunur.
rpc
yöntemini RouteGuide
tanımının içine ekleyin.GetFeature
Daha önce açıklandığı gibi, bu yöntem belirli bir koordinat kümesinden bir konumun adını veya adresini arar. Bu nedenle, belirli bir Point
için GetFeature
işlevinin Feature
döndürmesini sağlayın:
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Bu, tekli bir UPÇ yöntemidir: İstemcinin sunucuya istek gönderdiği ve yanıtın geri gelmesini beklediği basit bir UPÇ'dir (yerel bir işlev çağrısı gibi).
4. İstemci ve sunucu kodu oluşturma
Ardından, .proto
hizmet tanımımızdan gRPC istemci ve sunucu arayüzlerini oluşturmamız gerekir. Bu işlemi, özel bir gRPC Java eklentisiyle birlikte protokol arabelleği derleyicisini protoc
kullanarak yaparız. gRPC hizmetleri oluşturmak için proto3 derleyicisini (hem proto2 hem de proto3 söz dizimini destekler) kullanmanız gerekir.
Gradle veya Maven kullanılırken protoc
derleme eklentisi, derlemenin bir parçası olarak gerekli kodu oluşturabilir. Kendi .proto
dosyalarınızdan nasıl kod oluşturacağınız hakkında bilgi edinmek için grpc-java README dosyasına bakabilirsiniz.
Bu projeyi oluşturmak için codelab'in kaynak kodunda bir Gradle ortamı ve yapılandırması sağladık.
grpc-java-getting-started
dizininde aşağıdaki komutu çalıştırın:
$ chmod +x gradlew $ ./gradlew generateProto
Aşağıdaki sınıflar hizmet tanımımızdan oluşturulur:
Feature.java
,Point.java
ve diğerleri, istek ve yanıt mesajı türlerimizi doldurmak, serileştirmek ve almak için gereken tüm protokol arabelleği kodunu içerir.RouteGuideGrpc.java
,RouteGuide
sunucularının uygulaması için bir temel sınıf (diğer bazı yararlı kodlarla birlikte),RouteGuideGrpc.RouteGuideImplBase
,RouteGuide
hizmetinde tanımlanan tüm yöntemlerle ve istemcilerin kullanması için sap sınıfları içerir.
5. Sunucuyu uygulama
Öncelikle RouteGuide
sunucuyu nasıl oluşturduğumuza bakalım. RouteGuide
hizmetimizin işini yapması için iki bölüm vardır:
- Hizmet tanımımızdan oluşturulan ve hizmetimizin asıl "işini" yapan hizmet arayüzünü uygulama.
- İstemcilerden gelen istekleri dinlemek ve bunları doğru hizmet uygulamasına göndermek için bir gRPC sunucusu çalıştırma.
RouteGuide'ı uygulama
Gördüğünüz gibi, sunucumuzda oluşturulan RouteGuideGrpc.RouteGuideImplBase
soyut sınıfını genişleten bir RouteGuideService
sınıfı var:
private static class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {
...
}
Sunucunuzu özelliklerle başlatmak için aşağıdaki 2 dosyayı sağladık:
./src/main/java/io/grpc/examples/routeguide/RouteGuideUtil.java
./src/main/resources/io/grpc/examples/routeguide/route_guide_db.json
Basit bir RPC uygulamasını ayrıntılı olarak inceleyelim.
Unary RPC
RouteGuideService
, tüm hizmet yöntemlerimizi uygular. Bu durumda, yalnızca GetFeature()
, istemciden Point
mesajı alır ve bilinen yerlerin listesinden ilgili konum bilgilerini Feature
mesajıyla döndürür.
@Override
public void getFeature(Point request, StreamObserver<Feature> responseObserver) {
responseObserver.onNext(checkFeature(request));
responseObserver.onCompleted();
}
getFeature()
yöntemi iki parametre alır:
Point
: İstek.StreamObserver<Feature>
: Sunucunun yanıtıyla birlikte çağıracağı özel bir arayüz olan yanıt gözlemcisi.
Yanıtımızı istemciye döndürmek ve görüşmeyi tamamlamak için:
- Hizmet tanımımızda belirtildiği gibi, istemciye döndürülecek bir
Feature
yanıt nesnesi oluşturup bu nesneyi doldururuz. Bu örnekte, bunu ayrı bir özelcheckFeature()
yönteminde yapıyoruz. Feature
değerini döndürmek için yanıt gözlemcisininonNext()
yöntemini kullanırız.- RPC ile ilgilenmeyi bitirdiğimizi belirtmek için yanıt gözlemcisinin
onCompleted()
yöntemini kullanırız.
Sunucuyu başlatma
Tüm hizmet yöntemlerimizi uyguladıktan sonra, istemcilerin hizmetimizi gerçekten kullanabilmesi için bir gRPC sunucusu başlatmamız gerekir. Standart metnimize ServerBuilder nesnesinin oluşturulmasını dahil ediyoruz:
ServerBuilder.forPort(port), port, RouteGuideUtil.parseFeatures(featureFile)
Hizmeti oluşturucuda oluşturuyoruz:
- Oluşturucunun
forPort()
yöntemini kullanarak istemci isteklerini dinlemek için kullanmak istediğimiz bağlantı noktasını belirtin (joker karakter adresi kullanılır). - Hizmet uygulama sınıfımızın
RouteGuideService
bir örneğini oluşturun ve bunu oluşturucununaddService()
yöntemine iletin. - Hizmetimiz için bir RPC sunucusu oluşturmak üzere oluşturucuda
build()
işlevini çağırın.
Aşağıdaki snippet'te ServerBuilder
nesnesinin nasıl oluşturulduğu gösterilmektedir.
/** Create a RouteGuide server listening on {@code port} using {@code featureFile} database. */
public RouteGuideServer(int port, URL featureFile) throws IOException {
this(Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()),
port, RouteGuideUtil.parseFeatures(featureFile));
}
Aşağıdaki snippet'te, RouteGuide
hizmetimiz için nasıl sunucu nesnesi oluşturduğumuz gösterilmektedir.
/** Create a RouteGuide server using serverBuilder as a base and features as data. */
public RouteGuideServer(ServerBuilder<?> serverBuilder, int port, Collection<Feature> features) {
this.port = port;
server = serverBuilder.addService(new RouteGuideService(features))
.build();
}
Yukarıda oluşturduğumuz sunucuda start
işlevini çağıran bir başlangıç yöntemi uygulayın.
public void start() throws IOException {
server.start();
logger.info("Server started, listening on " + port);
}
Sunucunun tamamlamasını beklemek için bir yöntem uygulayın, böylece hemen çıkmaz.
/** Await termination on the main thread since the grpc library uses daemon threads. */
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
Gördüğünüz gibi, sunucumuzu ServerBuilder
kullanarak oluşturup başlatıyoruz.
Ana yöntemde:
RouteGuideServer
örneği oluşturun.- Hizmetimiz için bir RPC sunucusu etkinleştirmek üzere
start()
numaralı telefonu arayın. blockUntilShutdown()
numaralı telefonu arayarak hizmetin durdurulmasını bekleyin.
public static void main(String[] args) throws Exception {
RouteGuideServer server = new RouteGuideServer(8980);
server.start();
server.blockUntilShutdown();
}
6. İstemciyi oluşturma
Bu bölümde, RouteGuide
hizmetimiz için istemci oluşturma konusunu ele alacağız.
Sap oluşturma
Hizmet yöntemlerini çağırmak için önce bir taslak oluşturmamız gerekir. İki tür saplama vardır ancak bu codelab için yalnızca engelleme saplamasını kullanmamız gerekir. İki tür vardır:
- Bir RPC çağrısı yapan ve sunucunun yanıt vermesini bekleyen, yanıt döndüren veya istisna oluşturan bir engelleyici/eşzamanlı saplama.
- Yanıtın eşzamansız olarak döndürüldüğü, sunucuya engellemeyen çağrılar yapan engellemeyen/eşzamansız bir saplama. Yalnızca eşzamansız saplamayı kullanarak belirli türlerde yayın aramaları yapabilirsiniz.
Öncelikle bir gRPC kanalı oluşturmamız ve ardından bu kanalı kullanarak saplamamızı oluşturmamız gerekir.
Kanalı oluşturmak için doğrudan ManagedChannelBuilder
kullanabilirdik.
ManagedChannelBuilder.forAddress(host, port).usePlaintext().build
Ancak hostname:port
içeren bir dize alan bir yardımcı yöntem kullanalım.
Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()).build();
Artık engelleme saplamamızı oluşturmak için kanalı kullanabiliriz. Bu codelab'de yalnızca engelleme RPC'leri olduğundan .proto
'ımızdan oluşturduğumuz RouteGuideGrpc
sınıfında sağlanan newBlockingStub
yöntemini kullanıyoruz.
blockingStub = RouteGuideGrpc.newBlockingStub(channel);
Hizmet yöntemlerini arama
Şimdi de hizmet yöntemlerimizi nasıl çağırdığımıza bakalım.
Simple RPC
Basit RPC GetFeature
'yi çağırmak, yerel bir yöntemi çağırmak kadar kolaydır.
Bir istek protokol arabelleği nesnesi (bizim durumumuzda Point
) oluşturup doldururuz, bunu engelleme saplamamızdaki getFeature()
yöntemine iletiriz ve Feature
yanıtını alırız.
Hata oluşursa Status
olarak kodlanır. Bu kodu StatusRuntimeException
üzerinden alabiliriz.
Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();
Feature feature;
try {
feature = blockingStub.getFeature(request);
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return;
}
Standart metin, belirtilen noktada bir özellik olup olmadığına bağlı olarak içeriği içeren bir mesajı kaydeder.
7. Yenilikleri inceleyin.
start_here
dizininde aşağıdaki komutu çalıştırın:
$ ./gradlew installDist
Bu işlem, kodunuzu derler, jar dosyası olarak paketler ve örneği çalıştıran komut dosyalarını oluşturur. Bu dosyalar build/install/start_here/bin/
dizininde oluşturulur. Komut dosyaları: route-guide-server
ve route-guide-client
.
İstemci başlatılmadan önce sunucunun çalışıyor olması gerekir.
- Sunucuyu çalıştırın:
$ ./build/install/start_here/bin/route-guide-server
- İstemciyi çalıştırın:
$ ./build/install/start_here/bin/route-guide-client
Aşağıdakine benzer bir çıkış görürsünüz. Zaman damgaları, netlik için çıkarılmıştır:
INFO: *** GetFeature: lat=409,146,138 lon=-746,188,906 INFO: Found feature called "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" at 40.915, -74.619 INFO: *** GetFeature: lat=0 lon=0 INFO: Found no feature at 0, 0
8. Sırada ne var?
- gRPC'nin işleyiş şeklini Introduction to gRPC (gRPC'ye Giriş) ve Core concepts (Temel kavramlar) başlıklı makalelerden öğrenebilirsiniz.
- Temel bilgiler eğitimini inceleyin.
- API referansını inceleyin.