Open16

gRPC

しゅんしゅん

https://grpc.io/docs/
https://grpc.io/docs/what-is-grpc/introduction/

  • 分散アプリケーションを作成する文脈で役に立つ

  • クライアント・アプリケーションが、あたかもローカル・オブジェクトであるかのように、別のマシンにあるサーバ・アプリケーションのメソッドを直接呼び出すことができる

  • gRPCサービスはプロトコル・バッファをインタフェース定義言語 (IDL) として使用する

  • protocを使って、プロト定義から好みの言語のデータ・アクセス・クラスを生成できる

しゅんしゅん

サーバとクライアントの「スタブ」の両方が、クライアントからHelloRequestパラメータを受け取り、サーバからHelloReplyを返すSayHello RPCメソッドを持っている

ここでいう「スタブ」がなんのことかはっきりわかってないけど
とりあえず、serverファイルとclientファイルが、同じhelloworld.protoを読み込んでる

helloworld.proto

指示通りhello againを追加してみて、protoの定義とserverとclientからの呼び出しのイメージを掴む

しゅんしゅん
  • gRPC はリモートから呼び 出されるメソッドとそのパラメータと戻り値の型を指定し、サービ スを定義するという考え方
  • gRPCでは、以下の4種類のサービスメソッドを定義することができる
    • 単一のレスポンスを返す単項RPC
      • rpc SayHello(HelloRequest) returns (HelloResponse);
    • サーバ・ストリーミング RPC
      • rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    • クライアント・ストリーミングRPC
      • rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    • 双方向ストリーミング RPC
      • rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

各違いはこの記事の図が超わかりやすい
https://zenn.dev/hsaki/books/golang-grpc-starting/viewer/stream

  • サーバーはサービスによって宣言されたメソッドを実装
    • gRPCインフラストラクチャは、入ってくるリクエストをデコードし、サービスメソッドを実行し、サービス応答をエンコードする
  • クライアントは、サービスと同じメソッドを実装したスタブと呼ばれるローカルオブジェクトを持つ
    • クライアントはローカルオブジェクトのメソッドにパラメータを渡して呼び出すだけ
      • パラメータを適切なプロトコルバッファのメッセージタイプでラップし、リクエストをサーバーに送信し、サーバーのプロトコルバッファの応答を返す
  • その他
    • サーバ側では成功裏に終了した RPC(「すべての応答を送信した! 」)が、クライアント側では失敗した RPC(「応答が期限を過ぎて到着した! 」)があり得る
    • クライアントもサーバーも、いつでもRPCをキャンセルすることができる。ただし、キャンセル前の変更はロールバックはされない
    • metadataとchannelsはよくわからん

https://grpc.io/docs/what-is-grpc/core-concepts/

しゅんしゅん
var PROTO_PATH = __dirname + '/../../protos/route_guide.proto';
var grpc = require('@grpc/grpc-js');
var protoLoader = require('@grpc/proto-loader');
// Suggested options for similarity to existing grpc.load behavior
var packageDefinition = protoLoader.loadSync(
    PROTO_PATH,
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
var protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
// The protoDescriptor object has the full package hierarchy
var routeguide = protoDescriptor.routeguide;

これを行うと、スタブのコンストラクタはrouteguide名前空間(protoDescriptor.routeguide.RouteGuide)にあり、serice記述子(サーバーを作成するために使用される)はスタブのプロパティ(protoDescriptor.routeguide.RouteGuide.service)になります。

よくわからん

しゅんしゅん

これはなんとなくイメージできてたけど
わかりやすく言語化されてるのでメモ

「そのAPIが提供したいサービスをProcedureとしてサーバー上に実装して、それをAPIを使う側であるクライアントコードから直接呼び出すようにする」という発想がRPC(Remote Procedure Call)

しゅんしゅん

これまたわかりやすい

通信方式として、HTTP2を使用。
そこに渡す、引数と戻り値の情報を、Protocol Buffersというシリアライズ方式で変換する

しゅんしゅん

grpc公式のQuick startに書いてある下記手順をやっとかないと、protocのコード自動生成で怒られるよ

go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

以下をzshrcに追記

export PATH="$PATH:$(go env GOPATH)/bin"
しゅんしゅん

gRPCクライアントを実装せずとも
server refrectionをgRPCサーバーに設定したうえで、grpcurlを使えば、grpcメソッドを直接実行できるんだな
server refrectionは、protoに定義されているシリアライズのルールをgRPCサーバーから取得するための機能
gRPCクライアントはprotocコマンドで自動生成されているけどgrpcurlはそうではない
引数をencodeして実行し戻り値をdecodeして読むために知る必要がある

https://zenn.dev/hsaki/books/golang-grpc-starting/viewer/server

しゅんしゅん

hello_grpc.pb.go(server側)に自動生成されていること

  • serverのインターフェース
  • server上でgrpc clientを起動する関数
  • リクエストを送るクライアントを作るコンストラクタ関数
  • クライアントが呼び出せるメソッド一覧をインターフェースで定義
しゅんしゅん

4パターンのメソッドを一通り試せた
双方向ストリーミングを実装して動いてるの見るの嬉しいな

しゅんしゅん

gRPCの場合は「メソッドの呼び出しに成功した場合には、中で何が起ころうともHTTPレスポンスステータスコードは200 OKを返す」

  • gRPCは「メソッドを呼び出し、戻り値を受け取る」ことに関心をおいている
  • 「gRPCがHTTP/2の上に実装されている」という事実を意識しなくて良いように設計されている
  • 「呼び出されたメソッドが正しく処理を実行したか」を知るためにHTTPのステータスコードを見にいくというのはgRPC-likeではない