こんばんわ、hisayukiです。
FirestoreとFaunaDBの比較を見ていてFirestoreにはgRPCがあると書かれていたのですが、そもそもgRPCって何?ってなったので調べてみました。
結論
Webアプリケーションで使うのはもう少し先になるかも
- gRPCは異なるウェブサービス間でRPCを実現するフレームワークである
- HTTP/2を使った高速な通信が使えるようになる
- REST APIのようなURLとJSONベースのやり取りではなく、メソッド呼び出しのような感覚でバックエンドを呼び出せる
- ブラウザから直接は使えないので、間にReverseProxy(envoy等)を建てる必要がある
gRPCとは?
概要
gRPC は、RPCを実現するためにGoogleが開発した通信プロトコルの1つです。
ProtcolBuffersを使ってデータをシリアライズし、通信にHTTP/2が使えるということで高速通信を実現できます。
そしてRESTやJSON-RPCとは異なり厳格な型付ができます!!
![](https://contents.hisa-tech.site/2020/02/11110455/https___qiita-image-store.s3.amazonaws.com_0_33668_9fc8e280-e182-6902-7864-6392382d64a5.png)
そもそもRPCって??
RPCはRemote Procedure Callの略です。
クライアント側がメソッドを実行するのと同じような感覚で、サーバーサイドのメソッドを実行できるようになるイメージです。
REST APIのように実装ルールが統一されていないような仕組みを脱却するために、近年注目を浴びているようですね。
まだ、そこまで浸透はしてませんが国内だとメルカリやクックパッドなどが取り入れられてるようです❗
Protocol Buffersの概要
Google製のインターフェース定義言語(Interface Definition Language)で.proto
ファイルにAPIの期待する入力形式、出力形式を定義します。
言語やプラットフォームに依存せずに、構造化データをシリアライズ化します。
現在「prot3 version」までバージョンが進んでいます。
コードの自動生成機能
独自の定義ファイル(.proto)
に通信元と通信先のインターフェースを明記します。
Protocol Bufferコンパイラのprotoc
で、明記した定義ファイル(.proto)
をコンパイルします。
protocのには使用したい言語に応じて設定できるプロパティがあります。
ちなみにGolangの場合はこのような感じになります。
protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld
--go_out
の部分が言語ごとに設定するプロパティになります。
このプロパティを使いたい言語用のプロパティにしてコンパイルをすることで、使いたい言語のソースコードを自動生成します。
以下の言語が自動生成をサポートしております。
サポートされている言語
- Android
- C#
- C++
- Go
- Java
- Node.js
- Objective-C
- PHP
- Python
- Ruby
- Dart (beta)
結構幅広くサポートされており、こちらのページからQuickStartも提供されています。
メリット
実装より既約
定義ファイル(.proto)
に静的型付言語のような記述で、何をRequestとして受り、何をResponseとして返すのか。
Requestとして受け取るものは何で、中身のデータ型はなんなのか。
処理後のResponseとして返すものは何で、中身のデータ型はなんなのか。
ここまで実装前に予め既約として.proto
に書いておけます。
そして.proto
から実装用コードをジェネレートするので、DocumentsやSchemeのメンテが遅れていくことを防ぎます。
変更の適用についても、先に.proto
を修正しないとコードの自動生成に反映されません。
一番はJSONのような中身のデータの型が解らないデータではなく、定義の段階で中身のデータの型を決めれることが個人的には一番素晴らしい機能だと思ってます。
HTTP/2により通信が高速
HTTP/1.1ではステートレスが大前提なので、都度Cookieや独自のTokenを送る必要がありました。
HTTP/2ではHPACK圧縮という方式を用いてヘッダフィールドの圧縮を行っています。
これにより、初回以降の送信ははヘッダ差分のみとなります。
HTTP/2についての詳しい話はこちらがわかりやすかったです。
シリアライズにより通信が高速
送信データをProtocol Buffersでバイナリベースにすることで転送量そのものが削減されています。
モバイルユーザーに対しても優しい仕様になります。
デメリット
シリアライズされているのでデバッグしづらい
高速化されてる副作用みたいなものですが、デシリアライズしないと何書いてあるのかわかりませんw
そのため、従来のREST APIのようにcurlやAPI用のテスティングツールだけではデバッグは難しそう。
ただ、最近はgRPC向けのデバッグツールも増えてきてるみたいです🤔
ブラウザはHTTP/2が使えない
ブラウザはgRPCを直接使うことができないため、ブラウザからリバースプロキシまでの間はHTTP/1.1での通信になるります。
そのためリバースプロキシを使って、通信規格の変更をする必要があります。
![](https://contents.hisa-tech.site/2020/02/11114632/a2df8d44c7fce76fd956c704711a79ae-png.png)
構成としてはこんなような感じ。
リバースプロキシからの通信はgRPCが使えるのでHTTP/2での通信が可能です。
ここではenvoyを使ってますが、nginxでやる方法もあるみたいです。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fcdn.qiita.com%2Fassets%2Fpublic%2Farticle-ogp-background-412672c5f0600ab9a64263b751f1bc81.png?ixlib=rb-4.0.0&w=1200&mark64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTk3MiZoPTM3OCZ0eHQ9Z1JQQy1XZWIlRTMlODElQUVQcm94eSVFMyU4MiU5Mk5naW54JUUzJTgxJUFCJUUzJTgxJTk3JUUzJTgxJUE2JUUzJTgxJUJGJUUzJTgxJTlGJnR4dC1hbGlnbj1sZWZ0JTJDdG9wJnR4dC1jb2xvcj0lMjMyMTIxMjEmdHh0LWZvbnQ9SGlyYWdpbm8lMjBTYW5zJTIwVzYmdHh0LXNpemU9NTYmcz01YzI5MDg2NTQ3M2ZmZTYxNTIwZDgxZjY3MDFmMjY5NA&mark-x=142&mark-y=57&blend64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZoPTc2Jnc9NzcwJnR4dD0lNDBNb3JpeDE1MDAmdHh0LWNvbG9yPSUyMzIxMjEyMSZ0eHQtZm9udD1IaXJhZ2lubyUyMFNhbnMlMjBXNiZ0eHQtc2l6ZT0zNiZ0eHQtYWxpZ249bGVmdCUyQ3RvcCZzPTBmYjhmNGVhNjRhZTRmMmQ5NTFlM2MxMWY0ZDQwMGRk&blend-x=142&blend-y=486&blend-mode=normal&s=57d17d7a329ebb1dc114c15b4f48c574)
まとめ
思想的には面白いし、通信についての速度は確実に早くなるので使ってみたい。
だが、既存に組み込むのはなしかなぁ
確かにURLの設計とかDocuments整備とかは楽になりそうだけど、それでもフロントエンドからの通信に使うことは RESTに比較して難しい。
次回作とか自分の勉強でやってみるのはありだけど、既存に組み込むのは今の所なしかなぁ・・・
まずはマイクロサービス化して、機能をContainer単位で分けて、そのあとにContainer間通信する場合には使ってみたいかも。
あと、現段階の個人の知見だとGraphQLのが使いやすそうって感じもあります。
コメント