初めに
記事の内容について
- gRPCとはを公式のサンプル(Python)を読んで理解しようという内容
- 筆者の勉強のために残している記事のため、内容の正確性は保証しません
なぜgRPCについて、Pythonで勉強しているのか
- プライベートで何かを作るのに、マイクロサービスアーキテクチャを採用したい→RPCを使ってみよう
- RPCの中でも、比較的多言語でライブラリが用意されているgRPCが良さそう→gRPCを使おう
- せっかくのプライベートなので触ったことのない言語にしたい
- Python?Go?Ruby?→とりあえず、Pythonでやってみるか
筆者について
- 社会人4年目のバックエンドエンジニア
- 周りと比べてほんの少し、インフラ(クラウド)に詳しいくらい
- Java/SpringBootでの開発経験のみ
- Pythonは
Hello World
を書いた?ことがある程度(なんかAI分野に強いんでしょ?程度)
- Pythonは
- 趣味:コーヒーと自作キーボード
- コーヒーは自宅焙煎したり、自宅に7万くらいのコーヒーサーバーを置いていたりするレベル
- 自作キーボードは絶賛設計中。この記事も自作キーボードを使用して執筆
環境
- 端末:MacBookAir M1
- Python:3.10.6
- pip:23.1.1(多分Pythonに付いてきてるバージョンそのまま)
今回の学習にあたり参考にしたページ
- gRPC公式のpython向けページ
-
gRPC Pythonの公式ページ
Macで見ると表記がめちゃくちゃ崩れていて、読むのに少し苦労した…
gRPCとは
gじゃないRPCとは?
- Remote Procedure Call(遠隔手続き呼び出し)の頭文字をとったもの
- 外部から関数を呼び出す的な感じと理解
- マイクロサービス化した際に、サービス間通信とかで使われる
- JSON-RPCやgRPCといったようにいろんな種類がある
gRPC
- Googleが開発したRPC
- データをバイナリでやり取りする
- HTTP/2とProtocol Buffersを使用
- Protocol Buffersはデータのシリアライズの仕様兼、ライブラリ。ここ深掘りするともう一つ記事書けそうなくらい、中身深そう。
- シリアライズとは、ざっくりいうと実行中に生成されたオブジェクトをバイナリorテキストデータに変換すること。
- なんか高速。らしい。
環境構築
環境の準備
Prerequisites
・Python 3.7 or higher
・pip version 9.0.1 or higher
とのこと、筆者の環境は特に更新は不要だった
各種インストール
- gRPCライブラリ(grpcio)のインストール
PythonでgRPC Server/Clientを構築するためのライブラリ
$ pip install grpcio
- gRPCツール(grpcio-tools)のインストール
gRPC Server/Clientを作るための便利ツールだと思われる
$ pip install grpcio-tools
サンプルの実行
サンプルのダウンロード
gRPC公式さんの方でサンプルコードを準備していくれているっぽい
# Clone the repository to get the example code:
$ git clone -b v1.54.0 --depth 1 --shallow-submodules https://github.com/grpc/grpc
# Navigate to the "hello, world" Python example:
$ cd grpc/examples/python/helloworld
ちょっと気になったので確認してみたが、他にも下記言語のサンプルが入っていた
- java(android)
- C++
- node
- Objective-C
- PHP
- Ruby
他にもprotos
というディレクトリがあるが、こちらについては後述
サンプルコードの実行
- gRPCサーバの起動
$ python greeter_server.py Server started, listening on 50051
- gRPCクライアントの起動(↑とは別terminal)
$ python greeter_client.py Will try to greet world ... Greeter client received: Hello, you!
それっぽい何かが起きた
サンプルコードへの理解
執筆時のソースコード
各ファイルの内容は{行番号}:{説明}
の形式で内容を記述
greeter_server.pyの内容
- 24~27:Greeterクラスの実装
helloworld_pb2_grpc.pyのGreeterServicerクラスを継承- 26~27:SeyHelloメソッドのオーバーライド
HelloReplyにmessageを設定
- 26~27:SeyHelloメソッドのオーバーライド
- 30~37: Serveメソッドの定義
サーバの起動メソッド- 31:サーバがListenするポート番号を変数として定義
- 32:worker数10でserverインスタンスを作成
- python/grpcのworkerの概念に自信はないが、おそらく10リクエストまでは並列でさばけると思われる
- 33:24行目で実装したGreeterクラスを32行目で作成したserverインスタンスに登録
- 34:serverインスタンスにポートを登録
- 35:サーバ起動
- 36:サーバが起動した旨のログを表示
- 37:sigtermが送られるまで待機?
- 40~42:python起動時の制御。Loggingの設定と、サーバ起動メソッドの呼び出し
greeter_client.pyの内容
- greeter_server.pyと大して変わらないので割愛
helloworld_pb2.pyの内容
おそらくgrpc-toolsで自動生成されるファイル
- 11:ProtocolBuffers用DBの初期化
- 16:helloworld.protoを基に、Descriptorを定義
- Descriptorとは、gRPCでやり取りするバイナリデータの型情報を持つもの。gRPCでやり取りしたデータをプログラムで受け取るために使われる(はず)
- 18,19:builderの設定、16行目で生成したDESCRIPTORをかませている
- 20~30:シリアライズ方法の設定をしている(多分。何やってるか分かっている自信はないが、書かれている内容的そうだろうと思っている。)
helloworld.protoの内容
- そもそもprotoファイルとは?
- インターフェース記述ファイル
- ProtocolBuffersでやり取りする方法、やり取りするデータについて定義
- こういうデータを使用して、この関数呼び出したら、こいつ返すよ。が書かれたファイル。
- 15:version指定
- 17~20:各言語向けoption設定。
- 深掘りしたいが、今回はPythonなので、一旦ノータッチ。いつかPythonのoptionを使用したり、JavaでgRPCを使う時が来たら記事化したい
- 22:package定義
- 同名のgRPCサービスを定義できるようにするため、パッケージの概念がある
- 25~30:RPCで使用するサービスのイターフェース定義
- 27:SayHello RPCを定義。HelloRequestを受け取り、HelloReplyを返却する
- 29:SayHelloStream RPCを定義。HelloRequestStreamを受け取り、StreamでHelloReplyを返却する
- 33~35:HelloRequestメッセージを定義
- 34:要素として、string型のnameのみを持つ。
- 38~40
- 39:要素として、string型のmessageのみを持つ。
helloworld_pb2_grpc.pyの内容
おそらくgrpc-toolsで自動生成されるファイル
- 8~22:GreeterStubクラスの定義
クライアント側で使用するクラス- 12~22:コンストラクタ
gRPCメソッドの設定
grpc.channel.unary_unary(method,request_serializer,response_serializer)を使用
helloworld.protoで定義した/helloworld.Greeter/SayHelloという名前のgRPCメソッドを定義python側に定義
requestのSerializerにhelloworld_pb2.pyで定義されたSerializerを設定
reponseのSerializerも同様- unary_unaryとは?
unaryは単一を意味しているため、一つのメソッド呼び出しに対し、一つの値を返却するrpc関数を定義している(と理解)
- unary_unaryとは?
- 12~22:コンストラクタ
- 25~34:GreeterServicerクラスの定義
サーバ側で使用するクラス- 29~34:SayHelloメソッドの定義
実装されていないメソッドとして、定義し、実装されない場合はErrorを返す
- 29~34:SayHelloメソッドの定義
- 37~47:add_GreeterServicer_to_serverメソッドの定義
- 38:rpc_method_handlerへの登録
SayHelloという名前でunary_unary_rpc_handlerを登録。やっていることは12~22行目とほぼ一緒 - 45:generic_handlerへのrpc_method_handlerの登録
helloworld.protoで定義した、Greeterサービスに38行目でrpc_method_handlerを紐付け - 46:serverにrpc_method_handlerを登録
- 38:rpc_method_handlerへの登録
- 51~70:Greeterクラスの定義
EXPERIMENTAL APIとのこと。実際には使用せず、上記クラスたちを用いて、クライアントを実装することが望ましいと思われる。- スタティックなSayHelloメソッドが用意されている。が、使うのは大変そう。
- ここでは割愛
次回へ
実際に自分でgRPCサーバとクライアントを作ってみたい