gRPCの紹介

gRPCの概要

1. 前書き

gRPC is a high performance, open source RPC framework initially developed by Google.ボイラープレートコードを排除し、データセンター内およびデータセンター間でポリグロットサービスを接続するのに役立ちます。

2. 概要

このフレームワークは、リモートプロシージャコールのクライアントサーバーモデルに基づいています。 A client application can directly call methods on a server application as if it was a local object.

この記事では、以下の手順を使用して、gRPCを使用して一般的なクライアントサーバーアプリケーションを作成します。

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

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

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

  4. クライアントアプリケーションを作成し、生成されたスタブを使用してRPC呼び出しを行う

姓と名の代わりに挨拶を返す単純なHelloServiceを定義しましょう。

3. Mavenの依存関係

grpc-nettygrpc-protobufgrpc-stubの依存関係を追加しましょう。


    io.grpc
    grpc-netty
    1.16.1


    io.grpc
    grpc-protobuf
    1.16.1


    io.grpc
    grpc-stub
    1.16.1

4. サービスの定義

まず、サービスspecifying methods that can be called remotely along with their parameters and return typesを定義します。

これは、protocol buffersを使用して.protoファイルで実行されます。 また、ペイロードメッセージの構造を記述するためにも使用されます。

4.1. 基本設定

サンプルHelloServiceHelloService.protoファイルを作成しましょう。 基本的な構成の詳細をいくつか追加することから始めます。

syntax = "proto3";
option java_multiple_files = true;
package org.example.grpc;

最初の行は、このファイルで使用される構文をコンパイラに伝えます。 デフォルトでは、コンパイラーはすべてのJavaコードを単一のJavaファイルに生成します。 2行目はこの設定を上書きし、すべてが個々のファイルに生成されます。

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

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

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

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

これにより、要求ペイロードが定義されます。 ここで、メッセージに入る各属性は、そのタイプとともに定義されます。

タグと呼ばれる一意の番号を各属性に割り当てる必要があります。 This tag is used by the protocol buffer to represent the attribute instead of using the attribute name.

したがって、属性名firstNameを毎回渡すJSONとは異なり、プロトコルバッファは数値1を使用してfirstNameを表します。 応答ペイロードの定義は、リクエストに似ています。

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

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. ProtocolBufferCompilerの使用

Download the compilerを選択し、READMEファイルの指示に従います。

次のコマンドを使用して、コードを生成できます。

protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/HelloService.proto

5.2. Mavenプラグインの使用

開発者は、コード生成をビルドシステムと緊密に統合する必要があります。 gRPCは、Mavenビルドシステムにprotobuf-maven-pluginを提供します。


  
    
      kr.motd.maven
      os-maven-plugin
      1.6.1
    
  
  
    
      org.xolstice.maven.plugins
      protobuf-maven-plugin
      0.6.1
      
        
          com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}
        
        grpc-java
        
          io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}
        
      
      
        
          
            compile
            compile-custom
          
        
      
    
  

os-maven-plugin拡張機能/プラグインは、$\{os.detected.classifier}のようなさまざまな便利なプラットフォーム依存プロジェクトプロパティを生成します

6. サーバーの作成

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

  • HelloRequest.java –HelloRequest型定義を含む

  • HelloResponse.java *–*これにはHelleResponseタイプ定義が含まれます

  • HelloServiceImplBase.java *–*これには、サービスインターフェイスで定義したすべての操作の実装を提供する抽象クラスHelloServiceImplBaseが含まれます

6.1. サービスの基本クラスのオーバライド

default implementation of the abstract class HelloServiceImplBase is to throw runtime exceptionio.grpc.StatusRuntimeExceptionは、メソッドが実装されていないことを示しています。

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

public class HelloServiceImpl extends HelloServiceImplBase {

    @Override
    public void hello(
      HelloRequest request, StreamObserver 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>として受け取ります。これは、応答オブザーバーであり、サーバーがその応答で呼び出すためのコールバックです。

このようにthe client gets an option to make a blocking call or a non-blocking call

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 provides a channel construct which abstracts out the underlying details

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("example")
          .setLastName("gRPC")
          .build());

        channel.shutdown();
    }
}

次に、hello()への実際のリモート呼び出しを行うために使用するスタブを作成する必要があります。 The stub is the primary way for clients to interacts with the server.自動生成スタブを使用する場合、スタブクラスにはチャネルをラップするためのコンストラクターがあります。

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

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

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

8. 結論

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

いつものように、ソースover on GitHubが見つかります。