gRPCについて公式のサンプルコードから勉強

- [初めに](#初めに)
  - [記事の内容について](#記事の内容について)
  - [なぜgRPCについて、Pythonで勉強しているのか](#なぜgrpcについてpythonで勉強しているのか)
  - [筆者について](#筆者について)
  - [環境](#環境)
  - [今回の学習にあたり参考にしたページ](#今回の学習にあたり参考にしたページ)
- [gRPCとは](#grpcとは)
  - [gじゃないRPCとは？](#gじゃないrpcとは)
  - [gRPC](#grpc)
- [環境構築](#環境構築)
  - [環境の準備](#環境の準備)
  - [各種インストール](#各種インストール)
- [サンプルの実行](#サンプルの実行)
  - [サンプルのダウンロード](#サンプルのダウンロード)
  - [サンプルコードの実行](#サンプルコードの実行)
  - [サンプルコードへの理解](#サンプルコードへの理解)
    - [greeter\_server.pyの内容](#greeter_serverpyの内容)
    - [greeter\_client.pyの内容](#greeter_clientpyの内容)
    - [helloworld\_pb2.pyの内容](#helloworld_pb2pyの内容)
    - [helloworld.protoの内容](#helloworldprotoの内容)
    - [helloworld\_pb2\_grpc.pyの内容](#helloworld_pb2_grpcpyの内容)
- [次回へ](#次回へ)


# 初めに
## 記事の内容について
- gRPCとはを公式のサンプル(Python)を読んで理解しようという内容
- 筆者の勉強のために残している記事のため、内容の正確性は保証しません
## なぜgRPCについて、Pythonで勉強しているのか
- プライベートで何かを作るのに、マイクロサービスアーキテクチャを採用したい→RPCを使ってみよう
  - RPCの中でも、比較的多言語でライブラリが用意されているgRPCが良さそう→gRPCを使おう
- せっかくのプライベートなので触ったことのない言語にしたい
  - Python？Go？Ruby？→とりあえず、Pythonでやってみるか
## 筆者について
- 社会人4年目のバックエンドエンジニア
  - 周りと比べてほんの少し、インフラ(クラウド)に詳しいくらい
- Java/SpringBootでの開発経験のみ
  - Pythonは`Hello World`を書いた？ことがある程度(なんかAI分野に強いんでしょ？程度)
- 趣味：コーヒーと自作キーボード
  - コーヒーは自宅焙煎したり、自宅に7万くらいのコーヒーサーバーを置いていたりするレベル
  - 自作キーボードは絶賛設計中。この記事も自作キーボードを使用して執筆

## 環境
- 端末：MacBookAir M1
- Python：3.10.6
- pip：23.1.1(多分Pythonに付いてきてるバージョンそのまま)

## 今回の学習にあたり参考にしたページ
- [gRPC公式のpython向けページ](https://grpc.io/docs/languages/python/quickstart/)
- [gRPC Pythonの公式ページ](https://grpc.github.io/grpc/python/grpc.html)
  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)のインストール
  ```
  $ pip install grpcio
  ```
  PythonでgRPC Server/Clientを構築するためのライブラリ
- gRPCツール(grpcio-tools)のインストール
  ```
  $ pip install grpcio-tools
  ```
  gRPC Server/Clientを作るための便利ツールだと思われる

# サンプルの実行
## サンプルのダウンロード
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!
  ```

それっぽい何かが起きた

## サンプルコードへの理解
[執筆時のソースコード](https://github.com/grpc/grpc/tree/a190831789b514e9f740a78b0dcd03fe79bfdd50/examples/python/helloworld)
各ファイルの内容は`{行番号}:{説明}`の形式で内容を記述

### [greeter_server.py](https://github.com/grpc/grpc/blob/a190831789b514e9f740a78b0dcd03fe79bfdd50/examples/python/helloworld/greeter_server.py)の内容
- 24~27:Greeterクラスの実装
  [helloworld_pb2_grpc.py](#helloworld_pb2_grpcpyの内容)のGreeterServicerクラスを継承
  - 26~27:SeyHelloメソッドのオーバーライド
    HelloReplyにmessageを設定
- 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](https://github.com/grpc/grpc/blob/a190831789b514e9f740a78b0dcd03fe79bfdd50/examples/python/helloworld/greeter_client.py)の内容
- greeter_server.pyと大して変わらないので割愛

### [helloworld_pb2.py](https://github.com/grpc/grpc/blob/a190831789b514e9f740a78b0dcd03fe79bfdd50/examples/python/helloworld/helloworld_pb2.py)の内容
おそらくgrpc-toolsで自動生成されるファイル
- 11:ProtocolBuffers用DBの初期化
- 16:[helloworld.proto](#helloworldprotoの内容)を基に、Descriptorを定義
  - Descriptorとは、gRPCでやり取りするバイナリデータの型情報を持つもの。gRPCでやり取りしたデータをプログラムで受け取るために使われる(はず)
- 18,19:builderの設定、16行目で生成したDESCRIPTORをかませている
- 20~30:シリアライズ方法の設定をしている(多分。何やってるか分かっている自信はないが、書かれている内容的そうだろうと思っている。)

### [helloworld.proto](https://github.com/grpc/grpc/blob/a190831789b514e9f740a78b0dcd03fe79bfdd50/examples/protos/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](https://github.com/grpc/grpc/blob/a190831789b514e9f740a78b0dcd03fe79bfdd50/examples/python/helloworld/helloworld_pb2_grpc.py)の内容
おそらくgrpc-toolsで自動生成されるファイル
- 8~22:GreeterStubクラスの定義
  クライアント側で使用するクラス
  - 12~22:コンストラクタ
    gRPCメソッドの設定
    grpc.channel.unary_unary(method,request_serializer,response_serializer)を使用
    [helloworld.proto](#helloworldprotoの内容)で定義した/helloworld.Greeter/SayHelloという名前のgRPCメソッドを定義python側に定義
    requestのSerializerに[helloworld_pb2.py](#helloworld_pb2pyの内容)で定義されたSerializerを設定
    reponseのSerializerも同様
    - unary_unaryとは？
      unaryは単一を意味しているため、一つのメソッド呼び出しに対し、一つの値を返却するrpc関数を定義している(と理解)
- 25~34:GreeterServicerクラスの定義
  サーバ側で使用するクラス
  - 29~34:SayHelloメソッドの定義
    実装されていないメソッドとして、定義し、実装されない場合はErrorを返す
- 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](#helloworldprotoの内容)で定義した、Greeterサービスに38行目でrpc_method_handlerを紐付け
  - 46:serverにrpc_method_handlerを登録
- 51~70:Greeterクラスの定義
  EXPERIMENTAL APIとのこと。実際には使用せず、上記クラスたちを用いて、クライアントを実装することが望ましいと思われる。
  - スタティックなSayHelloメソッドが用意されている。が、使うのは大変そう。
  - ここでは割愛

# 次回へ
実際に自分でgRPCサーバとクライアントを作ってみたい