Tutorial Advent Calendar 2020の21日目を担当させていただきます、エンジニアの寺田です。リモートワーク中は寒さに負けないようずっと暖房をつけているので電気代が気になる今日このごろです。
会社のプロダクトのなかで一部gRPCが使われてる箇所があったのですが、そもそもRPCってなんぞやって状態でしたので、勉強してみることにしました。
まずgRPCを勉強しようと思った時に、不明な用語があったのでそれらを整理してから進めることにしました。
RPCとは
まずRPCは、Remote Procedure Call(遠隔手続き呼び出し)の略で、プログラムから別のアドレス空間にあるサブルーチンや手続きを実行することを可能にする技術のこと。
でgRPCは、Google社内で使われていたRPCフレームワークがOSS化され、gRPCと名前がついたもののことだそうです。
ちなみにgRPCのgはGoogleのgではないです。バージョン毎にいろいろg縛りの言葉がついてるようです。
ここに書いてました。
[https://grpc.github.io/grpc/core/md_doc_g_stands_for.html:title]
Protocol Buffersとは
gRPCはデータをProtocol Buffersにシリアライズしてやりとりを行う。
Protocol BuffersもGoogleが開発したフォーマットで、XMLとの比較で、3〜10倍小さく、20〜100倍高速であると主張しているとのこと。
ProtocolBuffersは、protoファイルを作成します。
ファイルをコンパイルすると任意の言語用のコードを自動で作成してくれます。
GoやRubyなど様々な言語に対応しています。
現在はproto3です(いつから3なのか、2との違いは何なのかちゃんと調べてない)
試してみる
公式のチュートリアルの通りにやってみます。
まずサンプルをダウンロードし、ディレクトリ移動
$ git clone -b v1.34.0 https://github.com/grpc/grpc
$ cd grpc/examples/ruby
サーバーを起動する。
$ ruby greeter_server.rb
別のターミナルを開いてクライアントを起動する
$ cd grpc/examples/ruby
$ ruby greeter_client.rb
# 結果が帰ってくる
"Greeting: Hello world"
どういう仕組みかコードを確認してみます。
まずサーバーとして起動したgreeter_server.rb
を確認する。
# GreeterServer is simple server that implements the Helloworld Greeter server.
class GreeterServer < Helloworld::Greeter::Service
# say_hello implements the SayHello rpc method.
def say_hello(hello_req, _unused_call)
Helloworld::HelloReply.new(message: "Hello #{hello_req.name}")
end
end
# main starts an RpcServer that receives requests to GreeterServer at the sample
# server port.
def main
s = GRPC::RpcServer.new
s.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
s.handle(GreeterServer)
# Runs the server with SIGHUP, SIGINT and SIGQUIT signal handlers to
# gracefully shutdown.
# User could also choose to run server via call to run_till_terminated
s.run_till_terminated_or_interrupted([1, 'int', 'SIGQUIT'])
end
mainでRPCサーバーを0.0.0.0:50051で起動し、ハンドラーにGreeterServer
を設定しています。GreeterServe
はsay_hello
というメソッドを持ち、Helloworld::HelloReply.new(message: "Hello #{hello
req.name}")
を実行します。戻り値として Hello + パラメータで渡されたhelloreqのnameプロパティを返します。(Helloworldモジュールはexamples/ruby/lib/helloworld_services_pb.rbに定義されている。)
クライアント側のコード
def main
stub = Helloworld::Greeter::Stub.new('localhost:50051', :this_channel_is_insecure)
user = ARGV.size > 0 ? ARGV[0] : 'world'
message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message
p "Greeting: #{message}"
end
gRPCのスタブを生成し、say_helloメソッドに"world"を渡しています。こうやってサーバー側のメソッドを呼び出しているんですね。
サーバーは受け取った文字列に"Hello"を付けてクライアントに戻します。
クライアントはサーバから帰ってきた文字列にGreetingを付加して出力しています。クライアントの実行結果が"Greeting: Hello world"となるのはこういう仕組みだったんですね。
所感
チュートリアルをやって軽くコードを読んだだけですが、クライアントからサーバーのメソッドを呼び出すという概要は理解できました。
チュートリアルの最初の最初をやっただけなので、protoファイルの作り方やストリーミング など、もっと学習していこうと思います。
参考にさせていただいた資料
[https://booth.pm/ja/items/1315322:embed:cite]
[https://grpc.io/docs/languages/ruby/basics/:embed:cite]