【gRPC】gRPCと周辺知識(Protocol Buffer, HTTP/2)を軽くまとめてみた

#はじめに
最近マイクロサービスが流行っていますが、システムを分割するようなアーキテクチャだと、APIの構築で考慮することがたくさんあります。

- データモデル(JSON, XML, Binary)
- エンドポイント
- 呼び出し方
- エラーハンドリング
- APIの効率(1回の呼び出しでどれくらいのデータを取得するか)
- レイテンシー
- スケーラビリティ
- ロードバランシング
- 多言語に対する内部の操作性
- 認証、監視、ロギング

APIで最も一般的なのはRESTですが、Goを採用してマイクロサービスを開発している会社だと大体gRPCを使っているという話を聞きました。
最近Goを勉強し始めたので、今後のためにgRPCとその周辺知識を調べてまとめました。

#gRPCとは
gRPCは、RPC(クライアントがサーバのプログラムをネットワーク経由で呼び出して実行するプロトコル)を実現するために、Googleで開発されたオープンソースのフレームワークです。
Protocol Bufferを使ってデータをシリアライズし、高速な通信を実現することができます。

また、gRPCでは、Protocol Bufferを使ってmessageやserviceなどのAPI仕様を`.proto`ファイルに定義する必要があります。
`.proto`ファイルは様々な言語に対応しており、サーバとクライアントで必要なソースコードのひな形をそれぞれ生成することができます。
そのため、これを活用することで、多言語でつくられているようなマイクロサービスをより簡単につくることができるようになります。

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/96257fe1-7481-66c2-1048-59e6bbe8dd05.png)
<a href="https://www.grpc.io/docs/guides/">What is gRPC?</a>

#Protocol Bufferを使う理由
gRPCでProtocol Bufferを使用するのには以下の理由があります。

- 言語に依存せずコードを生成できる
- データをバイナリで扱い効率的にシリアライズできる
- たくさんのデータを運ぶのに便利
- APIの追加が楽

Protocol BufferでAPIのスキーマを考える際は、データとリクエストレスポンスはmessage、RPCのエンドポイントはserviceで定義します。
![スクリーンショット 2022-01-22 10.31.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/0216e129-3fa3-9457-9ccf-68c94aeb0c9c.png)

データをシリアライズする際、JSONだとテキストフォーマットで読みやすい代わりに、パースする際にCPUのリソースを使います。
一方、Protocol Bufferはバイナリフォーマットで機械語の表現に近いため、サイズが小さい上にCPUのリソース消費もJSONほど高くありません。

したがって、gRPCでProtocol Bufferを使うことで、スマホのように性能の低いCPUの端末でも、ネットワーク帯域を節約した効率的で速い通信、およびシリアライズを行うことができます。

#HTTP/2とは
HTTP/2(RFC7540)では、従来のHTTPを踏襲しながら、以下のように既存の問題点を解決してネットワークリソースの効率化を実現します。

- レイテンシーの削減(1つのTCP接続で並列処理を実現)
- ラウンドトリップの削減(サーバプッシュでクライアントの1回リクエストに対して複数のレスポンスを返す)
- 送受信のデータ量の削減(バイナリデータを使用)
- パケットサイズの縮小(ヘッダ圧縮)
- セキュア(SSLデフォルト)

なお、WebサーバとWebブラウザがHTTP/2に対応していれば自動的にHTTP/2の通信を行うため、利用者側がHTTP/2を意識する必要はありません。

#gRPCの特長
gRPCにはいくつかの特長があります。

##スケーラビリティ
gRPCでは、サーバはデフォルトで非同期処理を行います。
つまり、リクエストがきてもスレッドをブロックしないため、並列に万単位のリクエストを受けることができます。
一方、クライアントでは必要なパフォーマンスによって非同期処理と同期処理のどちらかを選択します。

##セキュリティ
gRPCではデフォルトでSSLの使用が推奨されます。
また、Interceptorを用いた認証制御も行うことができます。

##様々なAPIのタイプ
gRPCにはAPIのタイプがいくつかあります。
Unaryは、RESTのように1つのリクエストに対して1つのレスポンスがサーバから返ってくるようなAPIのタイプです。
~Streamingのものが、リクエストやレスポンスが複数で返ってくるようなタイプとなります。
><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/32b32c5e-9736-e7c5-92a4-cb10936208b7.png" width="800">
<a href="https://www.youtube.com/watch?v=pzxy25ho5WY">4 Types of API in gRPC</a>

各APIの定義をProtocol Bufferで定義すると以下のようになります。
リクエストとレスポンスの前に`stream`とつけることで、Streamingに対応します。
![スクリーンショット 2022-01-21 22.02.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/aec95483-0505-3639-48fb-8c1f7fa67f82.png)

##RESTとの比較
RESTと比較すると以下のようになります。

|   | gRPC | REST |
|:-:|:-:|:-:|
|スキーマ|Protocol Buffer|JSON|
|プロトコル|HTTP/2(低レイテンシー)|HTTP1.1(高レイテンシー)|
|APIタイプ1|双方向+非同期|クライアント→サーバ|
|APIタイプ2|Stream対応|Request/Response|
|APIタイプ3|API志向|CRUD志向(POST/GET/PUT/DELETE)|
|コード生成|Protocol Buffer|OpenAPI/Swagger|

#参考資料

https://www.udemy.com/share/101Zo03@bvwLx4Pfhb9GJwv8-yp7hIOkEPW-gTF6ZLs3c4cbUcF1EFDdh4n2NJM8mDAuDcHN/

https://qiita.com/hitochan777/items/7ecc11e77fa89be009d3

https://qiita.com/muroon/items/053131e3f29f22b94034

https://qiita.com/disc99/items/cfca50a32240284578bb