gRPCとマイクロサービス間通信における役割

gRPC(gRPC Remote Procedure Calls)は、Googleによって開発されたモダンでオープンソース、高性能なRPC(Remote Procedure Call)フレームワークです。分散システム間の効率的な通信を容易にするために設計されており、特にマイクロサービスアーキテクチャに適しています。以下は、gRPCおよびマイクロサービス間通信における役割の説明です:

gRPCとは何ですか?

gRPCはプロトコルであり、クライアントとサーバーアプリケーションが透過的に通信できるようにし、分散システムの構築を容易にします。輸送にはHTTP/2を使用し、インターフェース定義言語(IDL)としてProtocol Buffers(Protobuf)を使用し、認証、負荷分散などの機能を提供します。

以下は、gRPCの特徴です:

  1. 言語に依存しない。gRPCはJava、Python、Go、C++など複数のプログラミング言語をサポートしています。
  2. 効率的な通信。Protobufを使用したバイナリシリアル化を行い、JSONなどのテキストベースのフォーマットよりも高速でコンパクトです。
  3. HTTP/2ベース。gRPCはHTTP/2を活用し、多重化、ストリーミング、レイテンシーの低減などの機能を提供します。
  4. 強く型付けされている。サービスとメッセージはProtobufを使用して定義され、タイプセーフティが確保され、エラーが減少します。
  5. ストリーミングサポート。gRPCは、ユニャリ、サーバーストリーミング、クライアントストリーミング、双方向ストリーミングの4種類のストリーミングをサポートしています。

gRPCの動作原理

1. サービスとメッセージの定義

Protobufを使用して、サービスインターフェース(メソッド)と交換されるメッセージの構造を定義します。

ProtoBuf

 

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

2. コードの生成

Protobufコンパイラ(protoc)は、選択したプログラミング言語でクライアントとサーバーのコードを生成します。

ProtoBuf

 

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

3. サーバーの実装

定義されたサービスのサーバー側ロジックを実装します。

4. クライアントの作成

生成されたクライアントコードを使用して、サーバーメソッドを呼び出します。

マイクロサービス通信におけるgRPCの役割

マイクロサービスアーキテクチャでは、アプリケーションを小さく独立したサービスに分割し、ネットワーク経由で通信します。この文脈において、gRPCはその効率性と柔軟性から重要な役割を果たします。

1. 高パフォーマンス

  • gRPCはProtobufを使用したバイナリシリアル化を利用しており、JSONやXMLのようなテキストベースのフォーマットよりも高速でコンパクトです。
  • HTTP/2はマルチプレクシングとヘッダー圧縮を可能にすることで、レイテンシを低減しスループットを向上させます。

2. 強力な契約定義

  • Protobufはサービス間に厳格な契約を強制し、通信エラーの可能性を低減します。
  • サービス定義の変更はバージョニングで管理でき、後方互換性を確保します。

3. ストリーミング機能

  • gRPCは双方向ストリーミングをサポートしており、チャットアプリケーションやライブデータフィードなどのリアルタイム通信に最適です。
  • サーバー側とクライアント側のストリーミングにより、大規模なデータセットや連続したデータフローの効率的な処理が可能です。

4. 相互運用性

  • gRPCは言語に依存しないため、異なる言語で書かれたマイクロサービスがシームレスに通信できます。
  • これは多言語のマイクロサービス環境で特に有用です。

5. 内蔵機能

  • gRPCは、認証、暗号化(TLS経由)、負荷分散などの機能を内蔵でサポートしており、追加のライブラリやツールの必要性を減少させます。

6. スケーラビリティ

  • gRPCの軽量な特性と効率的な通信は、大規模なマイクロサービス展開に適しています。
  • Kubernetesなどのコンテナオーケストレーションプラットフォームともうまく統合されます。

マイクロサービスにおけるgRPCのユースケース

  1. サービス間通信。gRPCは、特にパフォーマンスが重要なシナリオにおけるマイクロサービス間の通信に最適です。
  2. リアルタイムシステム。そのストリーミング機能は、ゲーム、IoT、またはライブ分析などのリアルタイムアプリケーションに適しています。
  3. 多言語環境。マイクロサービスが異なる言語で書かれている場合、gRPCはシームレスな通信を保証します。
  4. クラウドネイティブアプリケーション。gRPCはKubernetesやサービスメッシュ(例:Istio)などのクラウドネイティブ技術ともうまく統合されます。

gRPCの利点

  • 効率性。バイナリシリアル化とHTTP/2により、gRPCはより迅速でリソース効率が良くなります。
  • 型安全性。Protobufは強い型を保証し、ランタイムエラーを減少させます。
  • 言語横断サポート。複数のプログラミング言語で動作します。
  • ストリーミング。リアルタイム通信のための高度なストリーミングパターンをサポートします。

gRPCの課題

  • 複雑さ。Protobuf定義とコード生成が必要なため、gRPCのセットアップはRESTよりも複雑になることがあります。
  • ツール。gRPCサービスのデバッグやテストは、PostmanのようなツールがgRPCに特化していないため、RESTと比較して難しいことがあります。
  • ブラウザサポート。gRPCはブラウザでネイティブにサポートされていないため、ウェブベースのクライアントにはgRPC-Webのようなツールが必要です。

Spring BootとgRPCを使用する理由は?

Spring BootはJavaアプリケーションを構築するための人気のフレームワークであり、gRPCと組み合わせることで、開発者は高性能でスケーラブル、相互運用可能なサービスを作成できます。Spring Bootの自動構成と依存性注入を利用することで、gRPCの統合が簡単になります。

アプリケーションを構築する手順

クライアントがサーバーに名前を送信し、「こんにちは、{name}!」という応答を受け取ることができるシンプルなgRPCサービスGreeterを構築します。以下のように進めます:

  1. gRPCサービスをProtocol Buffersを使用して定義します。
  2. .protoファイルからJavaクラスを生成します。
  3. Spring BootでgRPCサーバーを実装します。
  4. Spring BootでgRPCクライアントを実装します。
  5. テストのためにgRPCクライアントを呼び出すRESTコントローラーを追加します。
  6. アプリケーションを実行して通信をテストします。

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

最初のステップは、Protocol Buffersを使用してgRPCサービスを定義することです。 greeter.protoというファイルをsrc/main/protoディレクトリに作成します:

ProtoBuf

 

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.example.grpc";
option java_outer_classname = "GreeterProto";
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
  string name = 1;
}
message HelloResponse {
  string message = 1;
}

このファイルは以下を定義します:

  • SayHello RPCメソッドを持つGreeterサービス。
  • nameフィールドを含むHelloRequestメッセージ。
  • messageフィールドを含むHelloResponseメッセージ。

2. 依存関係を追加します

Spring BootでgRPCを使用するために、pom.xmlに以下の依存関係を追加します:

XML

 

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
<!-- Spring Boot Web for REST Controller -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- gRPC dependencies -->
    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-spring-boot-starter</artifactId>
        <version>2.14.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-netty-shaded</artifactId>
        <version>1.54.0</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-protobuf</artifactId>
        <version>1.54.0</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-stub</artifactId>
        <version>1.54.0</version>
    </dependency>
    <!-- Protobuf Java Format -->
    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.22.2</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <!-- Protobuf Compiler Plugin -->
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.6.1</version>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:3.22.2:exe:${os.detected.classifier}</protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier}</pluginArtifact>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>compile-custom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

これらの依存関係には以下が含まれます:

  • 基本的なアプリケーション設定のためのSpring Boot Starter。
  • RESTコントローラーサポートのためのSpring Boot Web。
  • サーバーおよびクライアント実装のためのgRPCライブラリ。
  • シリアライズおよびデシリアライズのためのProtobuf。

3. Javaクラスを生成します

.protoファイルからJavaクラスを生成するために、次のMavenコマンドを実行します。

Plain Text

 

mvn clean compile

これにより、GreeterGrpcおよび関連するクラスがtarget/generated-sourcesディレクトリに生成されます。

4. gRPCサーバーを実装する

次に、Spring BootでgRPCサーバーを実装します。 GreeterServiceというクラスを作成してください:

Java

 

package com.example.grpc.server;

import com.example.grpc.GreeterGrpc;
import com.example.grpc.GreeterProto.HelloRequest;
import com.example.grpc.GreeterProto.HelloResponse;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class GreeterService extends GreeterGrpc.GreeterImplBase {
    @Override
    public void sayHello(HelloRequest request, StreamObserver responseObserver) {
        String name = request.getName();
        String message = "Hello, " + name + "!";
        HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();
        // レスポンスを送信
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

このクラスは生成されたGreeterGrpc.GreeterImplBaseを拡張し、sayHelloメソッドを実装して着信リクエストを処理します。

5. gRPCクライアントを実装する

今、Spring BootでgRPCクライアントを実装します。 GreeterClientというクラスを作成してください:

Java

 

package com.example.grpc.client;
import com.example.grpc.GreeterGrpc;
import com.example.grpc.GreeterProto.HelloRequest;
import com.example.grpc.GreeterProto.HelloResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import org.springframework.stereotype.Service;
@Service
public class GreeterClient {
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
    public GreeterClient() {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090)
                .usePlaintext()
                .build();
        this.blockingStub = GreeterGrpc.newBlockingStub(channel);
    }
    public String sayHello(String name) {
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloResponse response = blockingStub.sayHello(request);
        return response.getMessage();
    }
}

このクライアントはgRPCサーバーに接続し、SayHelloメソッドにリクエストを送信します。

6. テスト用のRESTコントローラーを追加する

gRPCクライアントをテストしやすくするために、GreeterClientを呼び出すエンドポイントを公開するRESTコントローラーを追加します。 GreeterControllerというクラスを作成してください:

Java

 

package com.example.grpc.controller;
import com.example.grpc.client.GreeterClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreeterController {

    private final GreeterClient greeterClient;

    @Autowired
    public GreeterController(GreeterClient greeterClient) {
        this.greeterClient = greeterClient;
    }

    @GetMapping("/greet")
    public String greet(@RequestParam String name) {
        return greeterClient.sayHello(name);
    }
}

このコントローラーは、/greetエンドポイントを公開し、nameパラメーターを受け入れてgRPCサーバーからのレスポンスを返します。

7. Spring Bootアプリケーションを作成する

最後に、サーバーとクライアントを実行するSpring Bootアプリケーションを作成してください:

Java

 

package com.example.grpc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GrpcApplication {
    public static void main(String[] args) {
        SpringApplication.run(GrpcApplication.class, args);
    }
}

8. サーバーポートを構成する

application.propertiesに次の構成を追加してください:

Plain Text

 

# gRPCサーバーポート
grpc.server.port=9090

# Spring Bootサーバーポート
server.port=8080

9. アプリケーションを実行する

  1. Spring Bootアプリケーションを起動してください。
  2. gRPCサーバーはポート9090で起動します。
  3. RESTコントローラーはポート8080で利用可能です。

アプリケーションをテストするには、/greetエンドポイントにGETリクエストを送信します:

Plain Text

 

curl http://localhost:8080/greet?name=World

レスポンスは次のようになります:

Plain Text

 

"Hello, World!"

Spring Bootのための適切なgRPCライブラリの選択

gRPC統合が必要なSpring Bootアプリケーションを構築する際、開発者はしばしばいくつかのライブラリの中から選択を迫られます。最もよく議論されるオプションはnet.devh.grpcorg.lognet.grpc、およびorg.springframework.grpcです。

これらのライブラリそれぞれには独自の強み、弱み、使用例があります。これらのライブラリの違い、特徴、そしてプロジェクトにどれを使用すべきかを探りましょう。

1. net.devh.grpc (grpc-spring-boot-starter)

net.devh.grpc、別名grpc-spring-boot-starterは、Spring BootとgRPCを統合するために広く使用されているライブラリです。活発にメンテナンスされており、Spring BootアプリケーションでgRPCサーバーとクライアントを構築するための堅牢な機能セットを提供します。

主な特徴

  • 自動構成。gRPCサーバーとクライアントのセットアップを簡素化します。
  • Spring統合。依存性注入やその他のSpring機能をサポートします。
  • Springセキュリティ。安全な通信のためにSpring Securityと簡単に統合します。
  • ヘルスチェック。Spring Boot Actuatorを介してヘルスチェックを提供します。
  • 同期および非同期通信。両方の通信スタイルをサポートしています。

使用理由

  • アクティブなメンテナンス。ライブラリは積極的にメンテナンスおよび更新されています。
  • 包括的なドキュメント。サポートを提供する大規模なコミュニティにより、十分にドキュメント化されています。
  • 本番環境で使用可能。本番環境で広く使用されています。

使用時期

  • 新しいSpring Bootアプリケーションを構築し、信頼性の高い、機能豊富なgRPC統合が必要な場合。
  • 依存性注入、セキュリティ、およびヘルスチェックなどのSpring Boot機能とシームレスに統合したい場合。

2. org.lognet.grpc (grpc-spring-boot-starter)

org.lognet.grpcは、Spring BootとのgRPC統合のための別のライブラリです。ただし、net.devh.grpcと比較して積極的にメンテナンスされておらず、後者が提供する一部の高度な機能が欠けています。

主な特徴

  • 基本的なgRPCセットアップ。gRPCサーバーおよびクライアントの基本的なサポートを提供します。
  • Spring Boot統合。Spring Bootと連携しますが、機能が少ないです。

使用理由

  • 歴史的な使用。gRPCとSpring Bootの統合の初期のライブラリの1つでした。
  • シンプリシティ。単純なユースケースに適しています。

使用時期

  • 既にこのライブラリを使用している古いプロジェクトに取り組んでいる場合。
  • 新しいプロジェクトにはお勧めできません。保守が限られており、機能も少ないため。

3. org.springframework.grpc(Spring gRPC)

org.springframework.grpcは、gRPCをSpringと統合するための実験的またはコミュニティ主導の取り組みです。これは公式のSpringプロジェクトではなく、net.devh.grpcほど成熟していないか、機能が豊富ではないかもしれません。

主な特徴

  • 基本的なgRPC統合。gRPCサーバーとクライアントの基本サポートを提供します。
  • Springエコシステムに合わせる。Springエコシステムに密接に合わせるように設計されています。

使用理由

  • 実験的な使用。実験やプロジェクトへの貢献に適しています。
  • Springに合わせる。Springに密接に合わせたい場合。

使用タイミング

  • プロジェクトを探索したり貢献したりしている場合にのみ使用してください。
  • 実験的な性質のため、本番環境での使用はお勧めできません。

どちらを使用すべきか?

新しいプロジェクトには

net.devh.grpc(grpc-spring-boot-starter)を使用してください。gRPCをSpring Bootと統合するための最も成熟し、積極的にメンテナンスされ、機能が豊富なオプションです。Spring Bootの機能とのシームレスな統合が、新しいプロジェクトに最適な選択肢です。

既存のプロジェクトに

もしあなたがすでに org.lognet.grpc を使用している場合、より良いサポートと機能のために net.devh.grpc への移行を検討してください。 org.lognet.grpc は古いプロジェクトで動作するかもしれませんが、 net.devh.grpc のようなアクティブなメンテナンスや高度な機能が欠けています。

実験的使用について

Spring gRPC 統合を探求または貢献している場合は、 org.springframework.grpc を検討できます。ただし、その実験的な性質から、プロダクションでの使用は推奨されません。

重要な考慮事項

  • コミュニティサポートnet.devh.grpc はより大きなコミュニティと優れたドキュメントを備えており、ヘルプやリソースを見つけやすくなっています。
  • プロダクションの準備状況net.devh.grpc はプロダクション環境で広く使用されており、安定して信頼性があると考えられています。
  • 使いやすさnet.devh.grpc は自動構成と Spring Boot とのシームレスな統合を提供し、セットアップの複雑さを軽減します。

結論

gRPC はマイクロサービス通信のための強力なツールであり、高いパフォーマンス、強い型付け、ストリーミングのような高度な機能を提供します。 REST に比べて初期設定が多く必要ですが、その効率性とスケーラビリティは現代の分散システムにとって優れた選択肢となります。

マイクロサービスアーキテクチャが複雑になるにつれて、gRPCはサービス間のシームレスな通信を可能にする上でますます重要な役割を果たしています。この記事では、Spring Boot 3を使用してシンプルなgRPCクライアントとサーバーアプリケーションを構築し、Protocol BuffersでgRPCサービスを定義し、Javaクラスを生成し、サーバーとクライアントを実装し、簡単にテストできるようにRESTコントローラーを追加しました。この例は、高性能でスケーラブル、かつ相互運用可能なサービスを構築するためのgRPCの力とシンプルさを示しています。さらに、より複雑なサービス、ストリーミング、またはエラーハンドリングを追加して拡張できます。コーディングを楽しんでください!

GitHubリポジトリ: grpc-client-and-server-with-spring-boot

Source:
https://dzone.com/articles/understanding-grpc-and-its-role-in-microservices-c