目次
gRPCの紹介
gRPCは、HTTP2プロトコル標準の設計と開発に基づいて、デフォルトでprotobufデータシリアル化プロトコルを使用し、複数の開発言語をサポートする、Googleが立ち上げた高性能のオープンソースの汎用RPCフレームワークです。gRPCは、サービスを正確に定義するための簡単な方法を提供し、クライアントとサーバー用の信頼できる関数ライブラリを自動的に生成します。
gRPCクライアントは異なるサーバー上のリモートプログラムを直接呼び出すことができ、その姿勢はローカルプログラムを呼び出すように見えます。分散アプリケーションとサービスを構築するのは簡単です。多くのRPCシステムと同様に、サーバーは定義されたインターフェイスの実装とクライアントの要求の処理を担当し、クライアントはインターフェイスの説明に従って必要なサービスを直接呼び出します。クライアントとサーバーは、それぞれgRPCでサポートされている異なる言語で実装できます。
gRPCは、次の4種類のサービスメソッドの定義をサポートしています。
- シングルRPCは、通常の関数呼び出しと同様に、クライアントがサーバーに要求を送信し、サーバーから応答を取得することを意味します。
rpc SayHello(HelloRequest) returns (HelloResponse){
}
- サーバー側のストリーミングRPC、つまり、クライアントはサーバーに要求を送信して、一連のメッセージを読み取るためのデータストリームを取得します。クライアントは、メッセージがなくなるまで、返されたデータストリームから読み取りを続けます。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
- クライアントストリーミングRPC、つまり、クライアントは、提供されたデータストリームを使用して、一連のメッセージを書き込み、サーバーに送信します。クライアントがメッセージの書き込みを終了すると、サーバーがこれらのメッセージを読み取って応答を返すのを待ちます。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
- 双方向ストリーミングRPC、つまり、両側が読み取りおよび書き込みデータストリームを介して一連のメッセージを送信できます。これらの2つのデータストリーム操作は互いに独立しているため、クライアントとサーバーは任意の順序で読み取りと書き込みを行うことができます。たとえば、サーバーはすべてのクライアントメッセージを待ってから応答を書き込むか、最初にメッセージを読み取ることができます。別のメッセージ、または読み取りと書き込みを組み合わせる他の方法。各データストリーム内のメッセージの順序は維持されます。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
protobuf
protobufとは
プロトコルバッファは、(データ)通信プロトコル、データストレージなどに使用できる、言語に依存せず、プラットフォームに依存せず、拡張可能なシリアル化された構造化データ方式です。データ構造を定義し、特別に生成されたソースコードを使用して、さまざまなデータストリームでさまざまな言語の構造データを簡単に読み書きできます。古いデータ構造からコンパイルされたデータを破棄することなく、データ構造を更新することもできます。 。展開手順。一般に、XMLに簡単に類推できます。ここでの類推は、主にデータ通信およびデータストレージアプリケーションシナリオでのシリアル化の類推を指します。protobufの3つの特性は次のように要約されます。
- 言語に依存せず、プラットフォームに依存しない: ProtoBufは、Java、C ++、Python、およびその他の言語をサポートし、複数のプラットフォームをサポートします
- 柔軟性と効率性: XMLよりも小さく(3〜10倍)、高速(20〜100倍)、シンプル
- 優れたスケーラビリティと互換性:元の古いプログラムに影響を与えたり破壊したりすることなく、データ構造を更新できます
構成のダウンロード
この記事はMac環境の構成に基づいています。まず、次のURLにアクセスしてダウンロードしてください:https://github.com/protocolbuffers/protobuf/releases
Java言語の最新バージョンを選択するだけです。ここに3.13.0をインストールしました。ダウンロードが完了したら、解凍してから、環境を構成する必要があります。
1.まず、protobufインストールディレクトリ、つまりprotobuf-3.13.0ディレクトリに移動します。
2.以下のコマンドをそれぞれ実行します
./configure --prefix=/Users/xxxxx/protoBuf/protobuf-3.13.0
make
make install
注:-prefixの後のディレクトリは、protobufインストールディレクトリです.makeコマンドで次のエラーが表示された場合:
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
次に、次のコマンドを実行してxcodeコマンドラインを再インストールし、上記の手順に戻ってmakeを再実行します。
xcode-select --install
それでも問題が解決しない場合は、実行してください
sudo xcode-select -switch /
make installコマンドを実行した後、次のステップはprotocの環境変数を構成することです。
vi ~/.bash_profile
次に、次のステートメントを挿入します
export PROTBUF=/Users/xujia/xxxxx/protoBuf/protobuf-3.13.0
export PATH=$PROTBUF/bin:$PATH
構成ファイルを再実行します
source ~/.bash_profile
このとき、protoc --versionを使用して次のバージョン番号を実行および出力し、構成が完了したことを示します。
libprotoc 3.13.0
コンパイル
環境変数を構成した後、protobufを検証する必要があります。最初に、.protoファイルを作成する必要があります。検証を容易にするための小さなデモを次に示します。
syntax = "proto3"; // 定义语法类型,通常proto3好于proto2,proto2好于proto1,如果不指定,默认使用proto2,必须位于第一行
package hello; // 定义作用域
option java_package = "grpc.demo";
service Hello { // 定义服务
rpc SayHello (HelloRequest) returns (HelloResponse) {}
}
message HelloRequest { // 定义消息体
string name = 1;
}
message HelloResponse {
string message = 1;
}
次に、ファイルをインストールディレクトリのexamplesフォルダーに配置します。次のコマンドを実行すると、現在のディレクトリにgrpcフォルダーが表示され、対応するjavaファイルがそこにあります。
protoc ./demo1.proto --java_out=./
シンプルなケース
このケースは、単一のサービスメソッドのみを示しています。.protoファイルは上記の小さなデモを使用します。まず、.protoファイルをプロジェクトに移動します。.protoファイルで指定されたJavaパッケージパスは、で指定されたものと一致している必要があることに注意してください。プロジェクト。プロジェクト図は次のとおりです。表示:
Maven構成
grpc jarパッケージの依存関係を導入し、protobufプラグインの依存関係も導入して、grpcコードをMavenの方法で生成できるようにする必要があります。下の<protoSourceRoot>タグのパスは、上の赤いタグのパスと一致している必要があることに注意してください。
<properties>
<grpc.version>1.23.0</grpc.version>
<protobuf.version>3.13.0</protobuf.version>
</properties>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<build>
<!-- ${os.detected.classifier} 变量由${os.detected.name} 和 ${os.detected.arch} 组成
https://github.com/trustin/os-maven-plugin -->
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
<protoSourceRoot>src/main/proto</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
grpc関連のクラスを生成する
2つの方法があります。1つはターミナルでコマンドを使用することです。
mvn protobuf:compile
mvn protobuf:compile-custom
もう1つは、Mavenのプラグインをクリックすることです。本質は同じです。
実行後、生成されたクラスをターゲットディレクトリに表示できます
サーバーを書く
package grpc.demo;
import grpc.demo.HelloGrpc;
import grpc.demo.HelloOuterClass.HelloRequest;
import grpc.demo.HelloOuterClass.HelloResponse;
import io.grpc.stub.StreamObserver;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class HelloServer {
private Server server;
private void start() throws IOException {
int port = 50051;
server = ServerBuilder.forPort(port)
.addService(new HelloImpl())
.build()
.start();
System.out.println("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// jvm关闭前执行
System.err.println("*** shutting down gRPC server since JVM is shutting down");
try {
HelloServer.this.stop();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
System.err.println("*** server shut down");
}));
}
private void stop() throws InterruptedException {
if (server != null) {
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
}
}
/**
* 阻塞等待主线程终止
* @throws InterruptedException
*/
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
final HelloServer server = new HelloServer();
server.start();
server.blockUntilShutdown();
}
/**
* 服务实现类
*/
private class HelloImpl extends HelloGrpc.HelloImplBase{
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
HelloResponse helloResponse = HelloResponse.newBuilder().setMessage("Hello "+request.getName()+", I'm Java grpc Server").build();
responseObserver.onNext(helloResponse);
responseObserver.onCompleted();
}
}
}
サーバーを実行した後、コンソール出力
Server started, listening on 50051
クライアントを書く
package grpc.demo;
import io.grpc.ManagedChannel;
import grpc.demo.HelloGrpc;
import io.grpc.ManagedChannelBuilder;
import grpc.demo.HelloOuterClass.HelloRequest;
import grpc.demo.HelloOuterClass.HelloResponse;
import java.util.concurrent.TimeUnit;
public class HelloClient {
/**
* 远程连接管理器,管理连接的生命周期
*/
private final ManagedChannel channel;
/**
* 远程服务存根
*/
private final HelloGrpc.HelloBlockingStub blockingStub;
public HelloClient(String host, int port) {
// 初始化连接
channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
// 初始化远程服务存根
blockingStub = HelloGrpc.newBlockingStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
public String sayHello(String name) {
// 构造服务调用参数对象
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
// 调用远程服务方法
HelloResponse response = blockingStub.sayHello(request);
return response.getMessage();
}
public static void main(String[] args) throws InterruptedException {
HelloClient client = new HelloClient("127.0.0.1", 50051);
String content = client.sayHello("Java client");
System.out.println(content);
client.shutdown();
}
}
クライアントを実行した後、コンソール出力
Hello Java client, I'm Java grpc Server
この時点でサーバーから応答が取得されていることを説明します