2019年6月11日火曜日

Ruby で gRPC 超入門

概要

gRPC はハイパフォーマンスな RPC フレームワークです
Protocol Buffers と呼ばれるインタフェース言語を使って呼び出し元の関数などを定義することができます
今回は Ruby でサンプルのコードを動かしてみました

環境

  • macOS 10.14.5
  • Ruby 2.6.2p47
    • grpc 1.21.0

準備

公式からサンプルが提供されているのでそれを元に動かしてみます

  • git clone https://github.com/grpc/grpc
  • cd grpc/examples/ruby/
  • bundle install --path vendor

'bundler', '~> 1.7' になっているので bundler のバージョンが新しい場合はバージョンの部分を削除してください

  • bundle exec ruby greeter_server.rb

でサーバを起動しておきましょう

  • bundle exec ruby greeter_client.rb

別ターミナルでクライアントを起動して "Greeting: Hello world" が返ってくれば OK です
今回のチュートリアルではこれらのサーバーとクライアントコードを修正します

helloworld.proto ファイルの修正

まず proto ファイルを修正します
proto ファイルには RPC で呼び出されるメソッドの引数と返り値を定義してあります

  • vim ../protos/helloworld.proto
syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

コメントの部分は削除しています
いろいろと書いていますが 1 行追記しているだけです
追記した箇所は rpc SayHelloAgain の行になります
message を使って引数と返り値のデータを定義することができます
あとはそれらを使った service を定義すれば OK です

grpc-tools のインストール

作成した proto ファイルからコードを生成してくれるツールです
コマンドとして使うのでグローバルにインストールしましょう

  • gem install grpc-tools

コード生成

では proto ファイルからコードを生成します
実行しているパスは examples/ruby になります

  • grpc_tools_ruby_protoc -I ../protos --ruby_out=lib --grpc_out=lib ../protos/helloworld.proto

(Mac で実行して PATH が通っていない場合は /usr/local/lib/ruby/gems/2.6.0/bin/grpc_tools_ruby_protoc あたりを探してみてください)

-I が proto ファイルを検索するディレクトリを指定します
--ruby_out--grpc_out は生成されるコードを配置するディレクトリを指定します
あとは生成元の proto ファイルのパスを指定すれば OK です

成功すると lib ディレクトリ配下の helloworld_pb.rbhelloworld_services_pb.rb が新たに生成されています

サーバコードを修正する

新たに追加したメソッドをサーバ側で使ってみます

  • vim greeter_server.rb
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(this_dir, 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)

require 'grpc'
require 'helloworld_services_pb'

class GreeterServer < Helloworld::Greeter::Service
  def say_hello(hello_req, _unused_call)
    Helloworld::HelloReply.new(message: "Hello #{hello_req.name}")
  end

  def say_hello_again(hello_req, _unused_call)
    Helloworld::HelloReply.new(message: "Hello again, #{hello_req.name}")
  end
end

def main
  s = GRPC::RpcServer.new
  s.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
  s.handle(GreeterServer)
  s.run_till_terminated_or_interrupted([1, 'int', 'SIGQUIT'])
end

main

コメントの部分は削除しています
追記したのは def say_hello_again メソッドになります
say_hello_again は proto ファイルで定義した rpc SayHelloAgain をスネークケースに変換した名前にしましょう

クライアントコード修正

追加したメソッドをクライアントコードで呼ぶようにしましょう

  • vim greeter_client.rb
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(this_dir, 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)

require 'grpc'
require 'helloworld_services_pb'

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}"
  message = stub.say_hello_again(Helloworld::HelloRequest.new(name: user)).message
  p "Greeting: #{message}"
end

main

コメントは削除しています
main 内の最後の 2 行を追加しています
要するに追加した say_hello_again メソッドをコールしているだけです

動作確認

  • bundle exec ruby greeter_server.rb

でサーバを起動しましょう

  • bundle exec ruby greeter_client.rb

でクライアントを実行し "Greeting: Hello again, world" も新たにレスポンスに追加されれば OK です

grpcurl

クライアント側は grpcurl というコマンドでも確認することができます

  • brew install grpcurl
  • grpcurl -plaintext -d '{"name":"world"}' -proto ../protos/helloworld.proto -import-path ../protos/ localhost:50051 helloworld.Greeter/SayHello

=> { "message": "Hello world" }

こんな感じです
また定義されているサービスの一覧なども確認できます

  • grpcurl -plaintext -proto ../protos/helloworld.proto -import-path ../protos/ localhost:50051 list

=> helloworld.Greeter

  • grpcurl -plaintext -proto ../protos/helloworld.proto -import-path ../protos/ localhost:50051 describe helloworld.Greeter

でコール可能なメソッド定義の一覧を取得できます

最後に

Ruby で gRPC に入門してみました
今回は公式のサンプルとクイックスタートを元に動かしてみただけなので詳しい機能などには触れていません
流れとして

  1. proto ファイルにメソッドを定義
  2. grpc_tools で Ruby のコードを生成
  3. server ファイルでメソッドを実装

しているということが理解できれば OK かなと思います
基本的には生成されたコードには触れずサーバとクライアントコードを変更していく感じなります

参考サイト

0 件のコメント:

コメントを投稿