なるべく詳しく調べるgRPC入門👨‍💻

# はじめに
以前から、[Firestoreのリアルタイム同期にgRPCが使われている](https://qiita.com/namusyaka/items/71cf27fd3242adbf348c#google-firestore)ことや、（仕事でよく使う）Google CloudでgRPCの知識を求められる機会が多く、知的好奇心と必要性の両輪でgRPCへの学びの機運が高まっていたため学んだことを備忘録的に残しておきます。

# gRPC入門
## 概要
gRPCはGoogle発、Remote Procedure Call（RPC）のフレームワークです。 
マイクロサービス間通信に利用していたGoogle社内の技術「Stubby」を汎用化して作られました。

>Googleにおけるアプリケーション開発では、スケーラブルなマイクロサービス型のアーキテクチャーが基本となっており、サービス間の通信処理を担うコンポーネントとして、Stubbyと呼ばれる独自のRPCライブラリーが利用されてきました。gRPCは、このライブラリーをオープンソースとして再実装したもので、さまざまなプログラミング言語で使用することができます。
>
>[第24回　マイクロサービス・システムにおけるgRPCの役割（前編） (中井悦司)](https://www.school.ctc-g.co.jp/columns/nakai2/nakai224.html)

何だか難しい言い回しが続きますが、前述の通りgRPCは通信を行うためのフレームワークです。
「Protocol Buffers」と呼ばれる定義ファイルをもとにサーバやクライアントの実装コードを自動生成でき、その自動生成したコードを介して通信を行うことができます[^1]。
コードを自動生成できるため、他言語間で通信を行うのも容易く、アプリケーションの実装と技術的な実装が疎結合になります。

通信の足回り（プロトコル）には、従来より利用されてきたHTTP/1.xをより効率化したHTTP/2を用いています。

全体感を把握するための図解としては下記の図が非常に分かりやすいです。
Protocol Buffersによってクライアントとサーバのコードを生成し、HTTP/2を用いて通信を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/3e2c7bf6-68fa-56cf-1c9f-83b7160cdefe.png)
[Building a gRPC Server in Go](https://sahansera.dev/building-grpc-server-go/)

主な利用用途はもちろんマイクロサービスだとは思いますが、他にも[Google Cloud Client Librariesの裏側で用いられていたり](https://github.com/googleapis/googleapis#overview)、モバイルアプリに組み込んで使うことも挙げることができます。

>The main usage scenarios:
>- Low latency, highly scalable, distributed systems.
>- Developing mobile clients which are communicating to a cloud server.
>- Designing a new protocol that needs to be accurate, efficient and language independent.
>- Layered design to enable extension eg. authentication, load balancing, logging and monitoring etc.
>
>[What is gRPC? - FAQ](https://grpc.io/docs/what-is-grpc/faq/#why-would-i-want-to-use-grpc)

本番環境をgRPCに移行していくユースケースを知りたい方は、下記の動画およびスライドが非常に分かりやすくオススメです。

https://event.cloudnativedays.jp/cndt2020/talks/14

https://speakerdeck.com/south37/real-world-migration-from-http-to-grpc-number-cndt2020

:::note info
### gRPCの「g」って何？
gRPCの「g」の意味合いはリリース毎に異なっています。
Googleの「g」かと思いきや、例えば`1.1`であれば`good`を表しています。

>'g' stands for something different every gRPC release:
>
>1.0 'g' stands for 'gRPC'
>1.1 'g' stands for 'good'
>1.2 'g' stands for 'green'
>...
>
>[g_stands_for.md](https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md)
:::

## Remote Procedure Call（RPC, 遠隔手続き呼び出し）
gRPCはRPCフレームワークです。RPCとは一体何なのでしょうか？
平たく言ってしまえば、RPCとは「異なる場所にある関数（手続き）を呼び出すためのしくみ」です。
Protocol Buffers（protoファイル）上で通信に用いる関数等を定義しコンパイルすると、各プログラミング言語向けのソースコードが自動生成されます。
自動生成されたソースコード内のメソッドをクライアントで利用すると、メソッドの裏側ではサーバへの通信が行われますがクライアントはそのことを意識する必要はありません（透過的）。
この仕組みは「関数を呼び出し戻り値を受け取る」関数呼び出しと相似の関係になっています。
RPCでは通信が透過的に取り扱われ、（遠隔にある）サーバ上の関数を呼び出すようにして通信を行うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/ae97197d-cc0f-c857-2cda-1a33f45f006d.png)
[What is gRPC? - Overview](https://grpc.io/docs/what-is-grpc/introduction/#overview)

ref. [RPCの具現化であるgRPC](https://zenn.dev/hsaki/books/golang-grpc-starting/viewer/rpc)

## gRPCとREST APIの差分
REST APIもOpenAPI Specification（Swagger）を用いればソースコードの自動生成が行えますし、gRPCと類似な部分を感じる方も多いかと思います。
ざっくりカテゴライズすると、gRPCもREST APIも、アプリケーションレイヤのひとつ上の層に位置する「クライアントとサーバ間の通信ルール」ですので、利用シーンの位置付けは被る部分も多いかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/c464d2bb-62d1-d876-6cc9-13f019a7448e.png)
[なぜポストREST APIが求められるのか？　REST APIがカバーできない2つの要因とその対策](https://kageura.hatenadiary.jp/entry/2018/01/11/%E3%81%AA%E3%81%9C%E3%83%9D%E3%82%B9%E3%83%88REST_API%E3%81%8C%E6%B1%82%E3%82%81%E3%82%89%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%8B%EF%BC%9F_REST_API%E3%81%8C%E3%82%AB%E3%83%90%E3%83%BC%E3%81%A7%E3%81%8D)

その上で、思想としてREST APIはリソース指向[^2]ですがgRPCは読んで字の如くRPCである点や、前者が主にデータ表現にJSONを用いるのに対して、後者はProtocol Buffersによるバイナリデータを取り扱う点、そもそもREST APIがHTTP/1.1以前の思想であるためgRPCのようにストリーミングを取り扱わない点、といった違いがあるかなと思います。

>　マイクロサービスの呼び出しには、REST APIもよく利用されますが、REST APIが既存のHTTP(S)プロトコルをそのまま利用しているのに対して、gRPCでは、HTTP/2プロトコルをベースとして、マイクロサービスの連携に必要なさまざまな機能が実装されています。具体的には、アプリケーションレイヤーでのフロー制御、多段階にわたるサービス呼び出しの連携、ロードバランスとフェイルオーバー、双方向のストリーミング通信などがあります。
>
>[第24回　マイクロサービス・システムにおけるgRPCの役割（前編） (中井悦司)](https://www.school.ctc-g.co.jp/columns/nakai2/nakai224.html)

>gRPC vs REST
>gRPC
>
>Protocol Buffers - smaller,faster.
>HTTP/2(lower latency).
>Bidirectional & Async.
>Stream Support.
>API oriented (no constraints-free design).
>Code Generation through Protocol Buffers in any language-1st class citizen.
>RPC based gRPC does the plumbing for us.
>
>REST
>
>JSON- text based, slower, bigger
>HTTP1.1 (higher latency)
>Client -> Server requets only
>Request/Response support only
>CRUD oriented(Create-Retrieve-Update-Delete/POST GET PUT DELETE)
>Code generation through OpenAPI/Swagger(add-on)-2nd class citizen
>HTTP verns based- we have to write the plumbing or use a 3rd party library
>
>[Understanding gRPC](https://www.vineethweb.com/post/grpc/)

- [gRPCチュートリアル - 他のプロトコルとの比較](https://github.com/ymmt2005/grpc-tutorial#%E4%BB%96%E3%81%AE%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB%E3%81%A8%E3%81%AE%E6%AF%94%E8%BC%83)
- [スターティングgRPC_読書メモ - gRPCとRESTの違い](https://gist.github.com/gushernobindsme/4b93ab305baa9088452b2932019a4db3#grpc-%E3%81%A8-rest-%E3%81%AE%E9%81%95%E3%81%84)
- [Why is gRPC better/worse than REST? 
](https://grpc.io/docs/what-is-grpc/faq/#why-is-grpc-betterworse-than-rest)
- [gRPCと従来のREST APIの比較](https://www.integrate.io/jp/blog/grpc-vs-rest-how-does-grpc-compare-with-traditional-rest-apis-ja/)

## gRPCの二大要素技術
gRPCは通信プロトコルとしてHTTP/2を利用し、データのシリアライズにProtocol Buffersを利用しています。

>gRPC は transport の機能は完全に HTTP/2 に任せて、より上位のレイヤーの関心ごとに注力できる様になっています。
>
>[gRPC Internal - gRPC の設計と内部実装から見えてくる世界](https://www.wantedly.com/companies/wantedly/post_articles/219429)

>By default, gRPC uses Protocol Buffers
>
>[What is gRPC? - Overview](https://grpc.io/docs/what-is-grpc/introduction/#overview)

ここからはgRPCの二大要素技術であるHTTP/2とProtocol Buffersについてざっくりとまとめていきます。

### HTTP/2
HTTP/2登場前に広く利用されていた（今も広く利用されている）HTTP/1.1に関して、Webが大規模化するとともに様々な問題が表出してきました。
一例を挙げると、ネットワーク通信の利用やプロトコルの仕組みが非効率であるために生じるレイテンシーの問題等です。

>HTTP/1.1の問題点のおさらい
>
>1. HTTP Head of line Blocking
>2. ネットワーク通信の利用が非効率
>3. 曖昧でテキスト処理が煩雑
>
>[HTTP/2からQUICへ続くWebプロトコルの進化](https://www.iij.ad.jp/dev/tech/techweek/pdf/151111_4.pdf)

そんな状況を打破するべく、HTTP/1.1登場の16年後、パフォーマンス向上を目指してリリースされたのがHTTP/2です。
HTTP/2はgRPCのStubbyに続きGoogleが起源でして、Google発のプロトコルSPDYをもとに標準化されました。

>世界はさらにGoogleに依存または支配されていくことを示唆するような亜種の批判もあります。このプロトコルはここ30年間に開発されたプロトコルと同様の手法でIETFによって開発されました。しかしながら我々はSPDYにおけるGoogleのすばらしい仕事を認めています。それは新しいプロトコルがデプロイできるということを証明しただけでなく、それによりどのような効果が得られるのかを示す数値も提供しました。
>
>[http2 explained - プロトコルはGoogleによって作られた](https://http2-explained.haxx.se/ja/part8#841-purotokoruhagoogleniyotterareta)

HTTP/1.1との互換性を保つことを優先しつつパフォーマンスを向上させるため、ひとつのTCPコネクション上で複数の仮想的なコネクション（ストリーム）を確立したり、通信はバイナリベースで行う等の大きな仕様変更を導入しました。

>・ストリーム（1.1のパイプラインに近いもの）を使ってバイナリデータを多重に送受信する仕組みに変更
・ストリーム内での優先順位設定や、サーバーサイドからデータ通信を行うサーバーサイドプッシュを実装
・ヘッダーが圧縮されるようになった
>
>[Real World HTTP ミニ版](https://www.oreilly.co.jp/books/9784873118789/)

https://ninjinkun.hatenablog.com/entry/2019/07/03/092541

:::note info
### バイナリベースって何？
HTTP/1.xはテキストベース、HTTP/2はバイナリベースのプロトコルだと言われています。

HTTP/1.xであれHTTP/2であれ、通信を行うためにはまずTCPコネクションを張ります。
TCP上では任意のメッセージを送り合うことができますが、ルールがないとクライアントもサーバもお互いメッセージを解釈できないので、HTTPという仕様を定め、メッセージの形式を決めています。

HTTP/1.xだと、**メッセージをテキストで表現し、改行位置等に意味を持たせています**。
「Status-Lineは一行目」「:の後に空白を許可」「改行で区切る」等の**テキストの記述方法に関するルール**を定めることで、メッセージをパースし情報を取り出すことができるわけです。
実際に[HTTPサーバを自作](https://qiita.com/opengl-8080/items/ca152658a0e52c786029)すると分かるかと思いますが、HTTP1.xに準拠したサーバは、受け取ったテキストをルールに従いパースしてヘッダ等の情報を取り出していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/84de99d0-499a-d39d-60a3-cd46aa4bedfd.png)
[Goならわかるシステムプログラミング 第6回 - GoでたたくTCPソケット（前編)](https://ascii.jp/elem/000/001/276/1276572/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/c627e1f7-2500-3309-9e3a-e7c298974d12.png)
[HTTP/2からQUICへ続くWebプロトコルの進化](https://www.iij.ad.jp/dev/tech/techweek/pdf/151111_4.pdf)

一方で、HTTP/2はメッセージを**テキストではなくバイナリでやりとりする仕様**になっており、バイナリの並び順自体にルールを定めていることから「バイナリベース」のプロトコルと呼ばれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/2f39fb82-5f79-2521-9165-acfea704d63f.png)
[HTTP/2からQUICへ続くWebプロトコルの進化](https://www.iij.ad.jp/dev/tech/techweek/pdf/151111_4.pdf)

バイナリベースはテキストに比べて効率的な表現ができるため、小さな容量で多くの情報をやりとりできるメリット等を持ちます。

>バイナリプロトコルは、小さな容量で転送でき、より効率的に解析できます。そして最も重要なのは HTTP/1.x のようなテキストプロトコルと比較して、間違いを少なくできることです。なぜなら、テキストプロトコルは、空白の処理や大文字と小文字の区別、改行コード、空白のリンクといったものに対応する多くのアフォーダンスを持っているからです。
>
>[HTTP/2 Frequently Asked Questions](https://http2.info/faq.html#why-is-http2-binary)
:::

:::note info
### gRPCの双方向通信とHTTP/2の関係性
gRPCはWebSocketのような双方向通信（Bidirectional streaming RPC）を行うことができます。
双方向通信をどのように実現しているのかと言えば、そもそもgRPCの通信プロトコルであるHTTP/2が持つ「ストリーム」は双方向であるとRFCに記載されており、その性質をそのまま流用しているようです。
そんな双方向なストリームを複数個制御することで、gRPCは双方向なデータ送受信を行っています。

>Yes, bidirectional streaming is native to HTTP/2. You can read RFC-7540 for the details of how the protocol works, but basically it allows you to create several streams on a single TCP connection, and each stream can send data in either direction independently of each other.
>
>[How does grpc achieve "bidirectional streaming rpc" like a websocket?](https://stackoverflow.com/questions/71687321/how-does-grpc-achieve-bidirectional-streaming-rpc-like-a-websocket)

>Client- and server-side stream processing is application specific. Since the two streams are independent, the client and server can read and write messages in any order.
>
>[Core concepts, architecture and lifecycle - Bidirectional streaming RPC](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc)

>HTTP/2にて触れた「ステートフルなストリーム」と「多重化されたストリームを複数個制御すること」により、双方向なデータ送受信を行うことができる。
>
>[HTTP/2における双方向通信とgRPCとこれから](https://qiita.com/namusyaka/items/71cf27fd3242adbf348c)
:::

:::note info
### HTTP/2のサーバプッシュに対する誤解
HTTP/2には「サーバプッシュ」と呼ばれる仕様があります。
「プッシュ」と聞くとWebSocket等の代替のようにも聞こえますが、現状は限定的な機能にとどまっています。
現状のサーバプッシュは「キャッシュプッシュ」であり、主にブラウザのキャッシュにコンテンツを先回りでお届けするような用途で用いられています。
[gRPCにおいてもサーバプッシュの機能は使われていません](https://qiita.com/muroon/items/053131e3f29f22b94034#%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5)。


>”キャッシュプッシュ”とも呼ばれている機能です。
>
>[http2 explained](https://http2-explained.haxx.se/ja/part6)

>ブラウザがページをリクエストすると、サーバーは応答でHTMLを送信し、JavaScript、画像、CSSの送信を開始する前に、ブラウザがHTMLを解析し、すべての埋め込みアセットに対してリクエストを発行するのを待つ必要があります。
>
>サーバープッシュを使用すると、サーバーは、クライアントが必要と考える応答をキャッシュに「プッシュ」することで、このラウンドトリップの遅延を回避できる可能性があります。
>
>[HTTP/2 Frequently Asked Questions](https://http2.github.io/faq/#whats-the-benefit-of-server-push)

>HTTP/2 push is called push, but it has nothing to do with notifications pushed from the server. It is just a more or less a sensible way of reducing application load time by saving round-trips.
>
>[Using a single HTTP/2 connection for bidirectional (and symmetric) communication](https://stackoverflow.com/questions/34026694/using-a-single-http-2-connection-for-bidirectional-and-symmetric-communication)

>As good as HTTP/2 features are, it’s not exactly what we were looking for. It turns out Pushes are only processed by the browser and do not bubble up to your client code. 
>
>[Our journey from WebSockets to HTTP/2](https://building.lang.ai/our-journey-from-websockets-to-http-2-4d069c54effd)

>All server push streams are initiated via PUSH_PROMISE frames
>
>[High Performance Browser Networking](https://hpbn.co/http2/)
:::

### Protocol Buffers
gRPCが利用するHTTP/2はバイナリベースのプロトコルですので、データをバイナリで表現する必要があります。
gRPCはProtocol Buffersを用いてデータをバイナリに変換（シリアライズ）しています。

改めて「Protocol Buffersとは何ぞや」ですが、データの通信および永続化のためのシリアライズフォーマットです。
protoファイル（foo.proto）に関数やメッセージを定義しコンパイルすると、各プログラミング言語向けのソースコードを生成してくれます。
生成したソースコードを使って、データのシリアライズ / デシリアライズを行うことができる上に、シリアライズしたデータをやりとりする関数を利用することもできます。

>Protocol Buffers は端的にいえば、言語+コンパイラ+ライブラリの3つの要素から構成される serialization mechanism です。Protocol Buffers は独自の Inteface Definition Language（IDL）を持っており、その言語を利用して構造化データを message 型として記述すると、コンパイラ（protoc）が各プログラミング言語向けの実装を生成してくれます。その自動生成されたコードを Protocol Buffers ライブラリとともに利用することで、効率的な binary format への serialize/deserialize が行えます。
>
>[gRPC Internal - gRPC の設計と内部実装から見えてくる世界](https://www.wantedly.com/companies/wantedly/post_articles/219429)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/2d29f9b6-e270-a41e-4dd4-f021bb651e50.png)
[Protocol Buffers 入門](https://www.slideshare.net/yuichi110/protocol-buffers-61413028)

Protocol Buffersの初出が2008年7月、gPRCは2016年8月です。
出自からそもそもProtocol BuffersはgRPCと独立した技術なので、gRPC以外と併用することができます。
諸々の考慮は必要かもしれませんが、例えばRedisのようなインメモリキャッシュにデータを保存する際にProtocol Buffersを使うといったことも可能です（[How to store protobuffer object in redis cache?](https://stackoverflow.com/questions/33170799/how-to-store-protobuffer-object-in-redis-cache)）。
Google社内では各ストレージにデータを保存する形式としてProtocol Buffersを採用している事例も多いようです。

>Google の内部の RPC は Protocol Buffers 形式でやり取りをされ、ストレージにも Prrotocol Buffers 形式でデータが保存され、データ解析パイプラインや mobile client との通信も Protocol Buffers 形式で行われている
>
>[gRPC Internal - gRPC の設計と内部実装から見えてくる世界](https://www.wantedly.com/companies/wantedly/post_articles/219429)

## gRPC-Web
WebにおけるJavaSctiptがHTTP/2のストリームを取り扱うAPIを持っていないこと等もあり（？）、ブラウザは直接gRPCを取り扱うことができません。

> In general HTTP/2 should be transparent in its use to web pages and web applications and so there is no need to implement low level HTTP/2 streams and connection details.
>
>[How to implement HTTP/2 stream connection in browser?](https://stackoverflow.com/questions/52273174/how-to-implement-http-2-stream-connection-in-browser)

>HTTP/2 supports bidirectional stream but you don't have access to this stream from JavaScript
>
>[What is the meaning of - HTTP2 doesn't provide API used by the clients, while websockets do?](https://stackoverflow.com/questions/72575271/what-is-the-meaning-of-http2-doesnt-provide-api-used-by-the-clients-while-we)

それでもWeb（ブラウザ）でgRPCを取り扱いたいニーズはあり、生み出されたのがgRPC-Webです。
簡単に言ってしまえば**ブラウザからのHTTP通信をgRPCに変換するプロキシを準備してブラウザとgRPCサーバを繋げる仕組み**がgRPC-Webです。
対応プロキシはEnvoyやNGINX等です。
プロキシへのリクエスト形式は規定されているので、Protocol BuffersによってgRPC-Web向けの実装を自動生成することで仕様に準拠したリクエストを行うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287774/6e870fe0-2bff-dcad-8b30-a194a22d6b24.png)

[gRPC-WEBを使ったWEBアプリ開発/Development web-app with gRPC-WEB](https://speakerdeck.com/dojineko/development-web-app-with-grpc-web)

Bidirectional streaming RPCをサポートしていない等、通常のgRPCとは異なる部分もあります。

https://github.com/grpc/grpc-web/blob/master/doc/roadmap.md

## まとめと今後の予定
gRPCに入門しました。
gRPCの裏側を知っていく内にHTTP3やQUIC等にも興味が出てきたので、今後キャッチアップしていこうと思います。

https://gihyo.jp/admin/serial/01/http3/0001

[^1]: あくまでデフォルトではProtocol Buffersを用いるだけであり、他の技術を利用することもできます。「By default, gRPC uses Protocol Buffers」[What is gRPC? - Overview](https://grpc.io/docs/what-is-grpc/introduction/#overview)
[^2]: リソースに対する操作をHTTPメソッドで記述する考え方