Java ile gRPC hizmeti oluşturma

1. Genel Bakış

gRPC, Google'da geliştirilen, dilden ve platformdan bağımsız bir uzak prosedür çağrısı (RPC) çerçevesi ve araç setidir. Özellikle güçlü bir ikili serileştirme araç seti ve dil olan Protokol Arabellekleri'ni kullanarak bir hizmet tanımlamanıza olanak tanır. Ardından, hizmet tanımınızdan çeşitli dillerde deyimsel istemci ve sunucu saplamaları oluşturmanıza olanak tanır.

Bu codelab'de, gRPC çerçevesini kullanarak bir API'yi kullanıma sunan Java tabanlı bir hizmet oluşturmayı ve ardından oluşturulan gRPC istemci taraflı kaba kodu kullanmak için bir istemci yazmayı öğreneceksiniz.

Neler öğreneceksiniz?

  • Protokol Arabelleği Dili
  • Java kullanarak gRPC hizmeti uygulama
  • Java kullanarak gRPC istemcisi uygulama

Bu eğiticiden nasıl yararlanacaksınız?

Yalnızca okuyun Okuyun ve alıştırmaları tamamlayın

Node.js uygulamaları oluşturma deneyiminizi nasıl değerlendirirsiniz?

Yeni başlayan Orta düzey Uzman

Go uygulamaları oluşturma deneyiminizi nasıl değerlendirirsiniz?

Başlangıç Orta İleri

2. Kurulum ve Gereksinimler

Yönlendirmesiz ortam kurulumu

  1. Cloud Console'da oturum açın ve yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

Proje kimliğini unutmayın. Bu kimlik, tüm Google Cloud projelerinde benzersiz bir addır (Yukarıdaki ad zaten alınmış olduğundan sizin için çalışmayacaktır). Bu codelab'in ilerleyen kısımlarında PROJECT_ID olarak adlandırılacaktır.

  1. Ardından, Google Cloud kaynaklarını kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir.

Bu codelab'i tamamlamak neredeyse hiç maliyetli değildir. Bu eğitimin ötesinde faturalandırma ücreti alınmaması için kaynakları nasıl kapatacağınız konusunda size tavsiyelerde bulunan "Temizleme" bölümündeki talimatları uyguladığınızdan emin olun. Google Cloud'un yeni kullanıcıları 300 ABD doları değerinde ücretsiz deneme programından yararlanabilir.

Google Cloud Shell

Bu codelab bilgisayarınızdan çalıştırılabilir ancak bu codelab'de Cloud'da çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacağız.

Bu Debian tabanlı sanal makine, ihtiyaç duyacağınız tüm geliştirme araçlarını içerir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu nedenle, bu codelab için ihtiyacınız olan tek şey bir tarayıcıdır (Chromebook'ta da çalışır).

  1. Cloud Shell'i Cloud Console'dan etkinleştirmek için Cloud Shell'i etkinleştir 'i a8460e837e9f5fda.png tıklamanız yeterlidir (ortamın sağlanması ve bağlantının kurulması yalnızca birkaç saniye sürer).

b532b2f19ab85dda.png

Screen Shot 2017-06-14 at 10.13.43 PM.png

Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, PROJECT_ID'nize ayarlandığını görürsünüz.

gcloud auth list

Komut çıkışı

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Komut çıkışı

[core]
project = <PROJECT_ID>

Herhangi bir nedenle proje ayarlanmamışsa şu komutu verin:

gcloud config set project <PROJECT_ID>

PROJECT_ID cihazınızı mı arıyorsunuz? Kurulum adımlarında hangi kimliği kullandığınızı kontrol edin veya Cloud Console kontrol panelinde arayın:

2485e00c1223af09.png

Cloud Shell, gelecekteki komutları çalıştırırken faydalı olabilecek bazı ortam değişkenlerini de varsayılan olarak ayarlar.

echo $GOOGLE_CLOUD_PROJECT

Komut çıkışı

<PROJECT_ID>
  1. Son olarak, varsayılan alt bölgeyi ve proje yapılandırmasını ayarlayın.
gcloud config set compute/zone us-central1-f

Çeşitli bölgeler arasından seçim yapabilirsiniz. Daha fazla bilgi için Bölgeler ve Alt Bölgeler başlıklı makaleyi inceleyin.

3. gRPC hizmeti oluşturma

Maven ile yeni bir Java projesi oluşturun:

$ mvn archetype:generate -DgroupId=com.example.grpc \
 -DartifactId=grpc-hello-server \
 -DarchetypeArtifactId=maven-archetype-quickstart \
 -DinteractiveMode=false
$ cd grpc-hello-server

gRPC Tanım Dosyası Ekleme

gRPC'de hizmet yüklerinin (istek ve yanıt) ve hizmet işlemlerinin bir IDL'de (Arayüz Tanımlama Dili) yakalanması gerekir. gRPC, mesaj yüklerini ve işlemleri tanımlamak için Protobuffer 3 söz dizimini kullanır. Hello Request ve Hello Response içeren basit bir Greeting Service için proto dosyası oluşturalım.

Öncelikle yeni proto dosyasını barındıracak yeni bir proto dizini oluşturun:

$ mkdir -p src/main/proto

Ardından yeni bir proto dosyası oluşturun src/main/proto/GreetingService.proto.

Dosyayı düzenlemek için vim,nano, veya emacs simgesini kullanabilirsiniz:

src/main/proto/GreetingService.proto

syntax = "proto3";
package com.example.grpc;

// Request payload
message HelloRequest {
  // Each message attribute is strongly typed.
  // You also must assign a "tag" number.
  // Each tag number is unique within the message.
  string name = 1;

  // This defines a strongly typed list of String
  repeated string hobbies = 2;

  // There are many more basics types, like Enum, Map
  // See https://developers.google.com/protocol-buffers/docs/proto3
  // for more information.
}

message HelloResponse {
  string greeting = 1;
}

// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
  // Define a RPC operation
  rpc greeting(HelloRequest) returns (HelloResponse);
}

gRPC bağımlılıkları ve eklentisi ekleme

Tanımı aldıktan sonra bu dosyadan hem sunucu tarafı kaba kodunu hem de istemci taraflı kaba kodunu oluşturabiliriz. gRPC bağımlılıklarını ve eklentilerini eklemeniz gerekir.

Öncelikle gRPC bağımlılıklarını pom.xml dosyasına ekleyin:

pom.xml

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty-shaded</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-protobuf</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>
    ...
  </dependencies>
  ...
</project>

Ardından eklentiyi ekleyin:

pom.xml

<project>
  ...
  <dependencies>
    ...
  </dependencies>
  <build>
    <extensions>
      <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.6.2</version>
      </extension>
    </extensions>
    <plugins>
      <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.6.1</version>
        <configuration>
          <protocArtifact>com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier}</protocArtifact>
          <pluginId>grpc-java</pluginId>
          <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>compile-custom</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

Fişleri oluşturma

Uygulamayı oluşturduğunuzda eklenti, proto tanımlarını Java koduna dönüştürür.

$ mvn -DskipTests package

Oluşturulan dosyaları görmek için:

$ find target/generated-sources

Hizmet'i uygulama

İlk olarak, greeting işlemini uygulayacak yeni bir GreetingServiceImpl sınıfı oluşturun:

src/main/java/com/example/grpc/GreetingServiceImpl.java

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
  @Override
  public void greeting(GreetingServiceOuterClass.HelloRequest request,
        StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
  // HelloRequest has toString auto-generated.
    System.out.println(request);

    // You must use a builder to construct a new Protobuffer object
    GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder()
      .setGreeting("Hello there, " + request.getName())
      .build();

    // Use responseObserver to send a single response back
    responseObserver.onNext(response);

    // When you are done, you must call onCompleted.
    responseObserver.onCompleted();
  }
}

Sunucuyu uygulama

Son olarak, bir bağlantı noktasında dinlemek ve bu hizmet uygulamasını kaydetmek için bir sunucu başlatmanız gerekir. App sınıfını ve ana yöntemini düzenleyin:

src/main/java/com/example/grpc/App.java

package com.example.grpc;

import io.grpc.*;

public class App
{
    public static void main( String[] args ) throws Exception
    {
      // Create a new server to listen on port 8080
      Server server = ServerBuilder.forPort(8080)
        .addService(new GreetingServiceImpl())
        .build();

      // Start the server
      server.start();

      // Server threads are running in the background.
      System.out.println("Server started");
      // Don't exit the main thread. Wait until server is terminated.
      server.awaitTermination();
    }
}

Son olarak, sunucuyu çalıştırın:

$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App
...
Server Started

4. Hizmetin Kullanımı

Oluşturucu, istemci tarafı saplarının tamamını oluşturmuştur. Laboratuvarın basitliği için aynı Maven projesini kullanacağız ancak yeni bir ana yönteme sahip yeni bir Client sınıfı ekleyeceğiz.

Öncelikle sunucuyu sonlandırmanıza gerek kalmaması için + işaretini tıklayarak yeni bir Cloud Shell oturumu açın:

1ff0fda960b9adfc.png

Yeni oturumda grpc-hello-server dizinine geçin:

$ cd grpc-hello-server

Ardından, yeni Client sınıfını ekleyin:

src/main/java/com/example/grpc/Client.java

package com.example.grpc;

import io.grpc.*;

public class Client
{
    public static void main( String[] args ) throws Exception
    {
      // Channel is the abstraction to connect to a service endpoint
      // Let's use plaintext communication because we don't have certs
      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
        .usePlaintext(true)
        .build();

      // It is up to the client to determine whether to block the call
      // Here we create a blocking stub, but an async stub,
      // or an async stub with Future are always possible.
      GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
      GreetingServiceOuterClass.HelloRequest request =
        GreetingServiceOuterClass.HelloRequest.newBuilder()
          .setName("Ray")
          .build();

      // Finally, make the call using the stub
      GreetingServiceOuterClass.HelloResponse response = 
        stub.greeting(request);

      System.out.println(response);

      // A Channel should be shutdown before stopping the process.
      channel.shutdownNow();
    }
}

Son olarak, istemciyi çalıştırın:

$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client
...
greeting: "Hello there, Ray"

İşte bu kadar. Oldukça basit, değil mi?

5. Akış Hizmeti

Deneyebileceğiniz daha pek çok şey var. Örneğin, proto dosyasına stream anahtar kelimesini istek veya yanıt parametresine ekleyerek kolayca bir yayın hizmeti oluşturabilirsiniz.

src/main/proto/GreetingService.proto

syntax = "proto3";
package com.example.grpc;

...

// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
  // MODIFY HERE: Update the return to streaming return.
  rpc greeting(HelloRequest) returns (stream HelloResponse);
}

Sunucunuzu yalnızca bir yanıt yerine birden fazla yanıt gönderecek şekilde güncelleyin. Bunu birden fazla responseObserver.onNext(...) araması yaparak yapabilirsiniz:

src/main/java/com/example/grpc/GreetingServiceImpl.java

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
  @Override
  public void greeting(GreetingServiceOuterClass.HelloRequest request,
        StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
 
    ...

    // Feel free to construct different responses if you'd like.
    responseObserver.onNext(response);
    responseObserver.onNext(response);
    responseObserver.onNext(response);

    // When you are done, you must call onCompleted.
    responseObserver.onCompleted();
  }
}

İstemci, engelleyici sap yerine eşzamansız bir sap kullanmalıdır. İstemci kodunu güncelleyin ve stub türünü GreetingServiceStub olarak güncellediğinizden emin olun:

src/main/java/com/example/grpc/Client.java

package com.example.grpc;

import io.grpc.*;

// New import
import io.grpc.stub.*;

public class Client
{
    public static void main( String[] args ) throws Exception
    {
      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
        .usePlaintext(true)
        .build();

      // Replace the previous synchronous code with asynchronous code.
      // This time use an async stub:
       GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);

      // Construct a request
      GreetingServiceOuterClass.HelloRequest request =
        GreetingServiceOuterClass.HelloRequest.newBuilder()
          .setName("Ray")
          .build();

      // Make an Asynchronous call. Listen to responses w/ StreamObserver
      stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() {
        public void onNext(GreetingServiceOuterClass.HelloResponse response) {
          System.out.println(response);
        }
        public void onError(Throwable t) {
        }
        public void onCompleted() {
          // Typically you'll shutdown the channel somewhere else.
          // But for the purpose of the lab, we are only making a single
          // request. We'll shutdown as soon as this request is done.
          channel.shutdownNow();
        }
      });
    }
}

Uygulamayı yeniden oluşturun:

$ mvn -DskipTests package

Hem sunucuyu hem de istemciyi kendi Cloud Shell oturumlarında yeniden başlatın.

Sunucuyu başlatmak için:

$ mvn exec:java -Dexec.mainClass=com.example.grpc.App
...
Server Started

İstemciyi başlatmak için:

$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client
...
greeting: "Hello there, Ray"
greeting: "Hello there, Ray"
greeting: "Hello there, Ray"

6. Tebrikler!

İşlediğimiz konular:

  • Protokol Arabelleği Dili
  • Java kullanarak gRPC sunucusu uygulama
  • Java kullanarak gRPC istemcisi uygulama

Sonraki Adımlar:

Görüşlerinizi bizimle paylaşın

  • Lütfen birkaç dakikanızı ayırarak çok kısa anketimizi doldurun.