gRPCの紹介

1前書き

  • gRPC は、当初Googleによって開発された高性能のオープンソースRPCフレームワークです。

2概要

フレームワークは、リモートプロシージャコールのクライアントサーバーモデルに基づいています。クライアントアプリケーションは、ローカルアプリケーションのようにサーバーアプリケーションのメソッドを直接呼び出すことができます。

この記事では、gRPCを使用して典型的なクライアントサーバーアプリケーションを作成するために次の手順を使用します。

  1. .proto ファイルにサービスを定義する

  2. プロトコルバッファコンパイラを使用してサーバーとクライアントのコードを生成する

  3. 生成されたサービスを実装して、サーバーアプリケーションを作成します.

インタフェースとgRPCサーバの生成 。生成されたスタブを使用してRPC呼び出しを行い、クライアントアプリケーションを作成します。

姓と名の代わりにグリーティングを返す単純な HelloService を定義しましょう。

3 Mavenの依存関係

grpc-netty 、https://search.maven.org/classic/#searchを追加しましょう。 %7Cga%7C1%7Ca%3A%22grpc-protobuf%22[grpc-protobuf]およびhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22grpc-stub%22[grpc依存関係:

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.16.1</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.16.1</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.16.1</version>
</dependency>

4サービスの定義

私たちはサービスを定義することから始めます。 リモートで呼び出すことができるメソッドとそれらのパラメータと戻り値の型を 指定する

これは .proto ファイルでリンク:/google-protocol-buffer[プロトコルバッファ]を使って行われます。それらはペイロードメッセージの構造を記述するためにも使用されます。

4.1. 基本構成

サンプルの HelloService 用に HelloService.proto ファイルを作成しましょう。

基本的な設定の詳細をいくつか追加することから始めます。

syntax = "proto3";
option java__multiple__files = true;
package org.baeldung.grpc;

1行目は、このファイルで使用されている構文をコンパイラに伝えます。デフォルトでは、コンパイラはすべてのJavaコードを単一のJavaファイルに生成します。

2行目はこの設定を上書きし、すべてが個々のファイルに生成されます。

最後に、生成されたJavaクラスに使用したいパッケージを指定します。

4.2. メッセージ構造の定義

次に、メッセージを定義します。

message HelloRequest {
    string firstName = 1;
    string lastName = 2;
}

これはリクエストペイロードを定義します。ここでメッセージに入る各属性はその型と共に定義されます。

タグと呼ばれる固有の番号を各属性に割り当てる必要があります。このタグは、属性名を使用するのではなく、属性を表すためにプロトコルバッファによって使用されます。

そのため、毎回属性名 firstName を渡すJSONとは異なり、プロトコルバッファは firstName を表すために1を使用します。応答ペイロードの定義は要求と似ています。

同じタグを複数のメッセージタイプにわたって使用できることに注意してください。

message HelloResponse {
    string greeting = 1;
}

4.3. サービス契約の定義

最後に、サービス契約を定義しましょう。 HelloService に対して、 hello() オペレーションを定義します。

service HelloService {
    rpc hello(HelloRequest) returns (HelloResponse);
}

hello() 操作は、単項要求を受け入れ、単項応答を返します。 gRPCはまた、リクエストとレスポンスの先頭に stream キーワードを付けることでストリーミングをサポートします。

5コードの生成

ここで、 HelloService.proto ファイルをプロトコルバッファコンパイラ protoc に渡してJavaファイルを生成します。これを引き起こすには複数の方法があります。

5.1. プロトコルバッファコンパイラの使用

コンパイラをダウンロードして READMEファイルの指示に従います。

次のコマンドを使用してコードを生成することができます。

protoc -I=$SRC__DIR --java__out=$DST__DIR $SRC__DIR/HelloService.proto

5.2. Mavenプラグインの使用

開発者としては、コード生成をビルドシステムと緊密に統合する必要があります。 gRPCはhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.xolstice.maven.plugins%22%20AND%20a%3A%22protobuf-maven-plugin%22[Mavenビルドシステム用の protobuf-maven-plugin ]

<build>
  <extensions>
    <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.6.1</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.3.0:exe:${os.detected.classifier}
        </protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>
          io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}
        </pluginArtifact>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>
            <goal>compile-custom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22kr.motd.maven%22%20AND%20a%3A%22os-maven-plugin%22 [os-maven- extension/pluginは $ \ {os.detected.classifier} のような様々なプラットフォーム依存のプロジェクトプロパティを生成します。

6. サーバーを作成する

どの方法をコード生成に使用するかに関係なく、次のキーファイルが生成されます。

  • HelloRequest.java - HelloRequest 型定義を含みます

  • HelloResponse.java - これは HelleResponse タイプを含みます

定義 HelloServiceImplBase.java - ** これは抽象クラスを含む

サービスインタフェースで定義したすべての操作の実装を提供する HelloServiceImplBase

6.1. サービス基底クラスの上書き

抽象クラス HelloServiceImplBase のデフォルト実装は、メソッドが実装されていないことを示すランタイム例外** io.grpc.StatusRuntimeException をスローします。

このクラスを拡張し、サービス定義に記載されている hello() メソッドをオーバーライドします。

public class HelloServiceImpl extends HelloServiceImplBase {

    @Override
    public void hello(
      HelloRequest request, StreamObserver<HelloResponse> responseObserver) {

        String greeting = new StringBuilder()
          .append("Hello, ")
          .append(request.getFirstName())
          .append(" ")
          .append(request.getLastName())
          .toString();

        HelloResponse response = HelloResponse.newBuilder()
          .setGreeting(greeting)
          .build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

hello() の署名と HellService.proto ファイルに記述した署名を比較すると、 HelloResponse が返されないことがわかります。その代わりに、2番目の引数を StreamObserver <HelloResponse> として受け取ります。これは、応答オブザーバであり、サーバーがその応答を使って呼び出すためのコールバックです。

このようにして、クライアントはブロッキングコールまたは非ブロッキングコールを行うためのオプションを取得します。

gRPCはオブジェクトを作成するためにビルダーを使用します。 HelloResponse.newBuilder() を使用し、グリーティングテキストを設定して HelloResponse オブジェクトを作成します。このオブジェクトをresponseObserverの onNext() メソッドに設定して、クライアントに送信します。

最後に、 onCompleted() を呼び出してRPCの処理が終了したことを指定する必要があります。そうしないと接続がハングし、クライアントはさらに情報が来るのを待つだけになります。

6.2. gRPCサーバーの実行

次に、受信リクエストをリスンするためにgRPCサーバーを起動する必要があります。

public class GrpcServer {
    public static void main(String[]args) {
        Server server = ServerBuilder
          .forPort(8080)
          .addService(new HelloServiceImpl()).build();

        server.start();
        server.awaitTermination();
    }
}

ここでも、ビルダーを使用してポート8080でgRPCサーバーを作成し、定義した HelloServiceImpl サービスを追加します。 start() はサーバを起動します。この例では、サーバーをフォアグラウンドで実行し続けてプロンプトをブロックするために awaitTermination() を呼び出します。

7. クライアントを作成する

  • gRPCは、接続、接続プーリング、負荷分散などの基本的な詳細を抽象化する** チャネル構成を提供します。

ManagedChannelBuilder を使用してチャンネルを作成します。ここでは、サーバーアドレスとポートを指定します。

暗号化せずにプレーンテキストを使用します。

public class GrpcClient {
    public static void main(String[]args) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
          .usePlaintext()
          .build();

        HelloServiceGrpc.HelloServiceBlockingStub stub
          = HelloServiceGrpc.newBlockingStub(channel);

        HelloResponse helloResponse = stub.hello(HelloRequest.newBuilder()
          .setFirstName("Baeldung")
          .setLastName("gRPC")
          .build());

        channel.shutdown();
    }
}

次に、実際に hello() へのリモート呼び出しを行うために使用するスタブを作成する必要があります。 スタブは、クライアントがサーバーと対話するための主要な方法です 自動生成スタブを使用するとき、スタブクラスはチャンネルをラップするためのコンストラクタを持ちます。

ここでは、ブロッキング/同期スタブを使用して、RPC呼び出しがサーバーからの応答を待ち、応答を返すか例外を発生させるようにします。 gRPCによって提供されるスタブには他に2つのタイプがあり、それらは非ブロッキング/非同期呼び出しを容易にします。

最後に、 hello() RPC呼び出しを行います。ここでは HelloRequest を渡します。自動生成されたセッターを使用して、 HelloRequest オブジェクトの firstName lastName 属性を設定できます。

サーバーから返された HelloResponse オブジェクトを返します。

8結論

このチュートリアルでは、サービスの定義とgRPCにすべての定型コードの処理を任せることによって、2つのサービス間の通信の開発を容易にするためにgRPCを使用する方法を見ました。

いつものように、あなたはソースhttps://github.com/eugenp/tutorials/tree/master/grpc[over on GitHub]を見つけるでしょう。