本日のテキストでは、gRPCとRESTについて詳しく見ていきたいと思います。これらは現代で最もよく使われるAPI作成手法の2つです。
I will start with a short characteristic of both tools — what they are and what they can offer. Then I will compare them according to seven categories, in my opinion, most crucial for modern-day systems.
カテゴリーは以下の通りです。
- 基盤となるHTTPプロトコル
- サポートされているデータ形式
- データサイズ
- スループット
- 定義
- 採用の容易さ
- ツールサポート
理由
「API」と聞くと、多くの人はすぐにREST APIを思い浮かべるでしょう。しかし、RESTはAPI構築のためのさまざまなアプローチの1つに過ぎません。万能の解決策ではありません。他にも方法があり、RPC(リモートプロシージャコール)がその1つであり、gRPCはRPCを扱うための最も成功しているフレームワークである可能性が高いです。
かなり成熟した効率的な技術であるにも関わらず、gRPCはまだ新しいと見なされています。したがって、特定のユースケースでは便利であるにも関わらず、RESTほど広く採用されていません。
このブログ記事を書く主な理由は、gRPCを普及させ、それが輝くユースケースを指摘することです。
RESTとは何か?
REST、または表現型状態転送は、おそらくAPIを公開するアプリケーションを作成する最も一般的な方法です。それはHTTPを基盤とした通信媒体として使用しています。そのため、キャッシングなどのHTTPのすべての利点を活用できます。
さらに、その発想からステートレスであるため、RESTはクライアントとサーバーの簡単な分離を可能にします。クライアントはサーバーが公開するインターフェースだけを知っていればサーバーと効果的に通信でき、サーバーの実装については何ら依存しません。クライアントとサーバーの通信はリクエストとレスポンスに基づいており、各リクエストはクラシックなHTTPリクエストです。
RESTはプロトコルでもツールでもなく(ある程度)、アプリケーションを構築するためのアーキテクチャ的なアプローチです。RESTアプローチに従うサービスは、RESTFulサービスと呼ばれます。アーキテクチャとして、RESTはユーザーに対していくつかの制約を課します。特に:
- クライアント-サーバー通信
- ステートレス通信
- キャッシング
- ユニフォームインターフェース
- 階層化されたシステム
- コードの要求
RESTの2つの重要な概念は:
- エンドポイント:特定のリソースを表す一意のURL(Uniform Resource Locator);インターネット上で特定の操作やデータ要素にアクセスする方法と見なすことができます
- リソース:特定のURLの下に利用可能な特定のデータ
さらに、REST APIの「プロフェッショナリズム」の度合いを説明するモデルであるリチャードソン成熟モデルがあります。このモデルは、特定のAPIが持つ特性のセットに基づいて、REST APIを3つのレベル(または4つ、レベル0をカウントするかによって)に分類します。
そのような特性の1つは、RESTエンドポイントがURLに名詞を使用し、リソースを管理するための正しいHTTPリクエストメソッドを使用することです。
- 例: DELETE user/1 の代わりに GET user/deleteById/1
HTTPメソッドとそれに関連するアクションについては、次のようになります。
- GET – 特定のリソースまたはリソースのコレクションを取得
- POST – 新しいリソースを作成
- PUT – リソース全体をupsert
- PATCH – 特定のリソースの部分的な更新
- DELETE – idによる特定のリソースの削除
成熟モデルは、それ以上に多くを指定しており、例えば、ハイパーメディアと呼ばれる概念があります。ハイパーメディアは、データの表示とクライアントが行うアクションの制御を結びつけます。
A full description of the maturity model is out of the scope of this blog — you can read more about it here.
免責事項: この段落で言及されている多くの事柄は、ここで説明されているよりも微妙です。RESTは非常に大きなトピックであり、一連の記事に値します。それでも、ここにあるすべては、一般的に知られている最高のRESTのベストプラクティスに合致しています。
gRPCとは何ですか?
これは、比較的古い概念であるリモートプロシージャコール(RPC)の別の実装です。Googleの人々によって作られたため、名前に「g」が含まれています。これはおそらくRPCを扱うための最も最新で効率的なツールであり、CNCFインキュベーションプロジェクトでもあります。
gRPCはGoogleのProtocol Buffersをシリアル化フォーマットとして使用し、HTTP/2をトランスポートメディアデータとして利用しますが、JSONをデータレイヤーとして機能させることも可能です。
gRPCの基本的な構成要素は以下の通りです:
- メソッド: gRPCの基本的な構成要素であり、各メソッドは入力を受け取り出力を返すリモートプロシージャコールです。それは、選択したプログラミング言語でさらに実装された単一の操作を実行します。現時点では、gRPCは4種類のメソッドをサポートしています:
- ユニアリ: 古典的なリクエスト-レスポンスモデルで、メソッドは入力を受け取り出力を返します
- サーバーストリーミング: メソッドは入力としてメッセージを受け取り、出力としてメッセージのストリームを返します。gRPCは個々のRPC呼び出しごとにメッセージの順序付けを保証します。
- クライアントストリーミング: メソッドは入力としてメッセージのストリームを受け取り、それらを処理し、メッセージが残らなくなるまで処理し、出力として単一のメッセージを返します。上記と同様に、gRPCは個々のRPC呼び出しごとにメッセージの順序付けを保証します。
- 双方向ストリーミング: この方法はストリームを入力として受け取り、ストリームを出力として返します。これにより、2つの読み取りと書き込みストリームを効果的に使用します。両方のストリームは独立して動作し、ストリームレベルでのメッセージの順序付けが保持されます。
- サービス: サービスは一連のメソッドを表し、各メソッドはサービス内で固有の名前を持つ必要があります。サービスはまた、セキュリティ、タイムアウト、リトライなどの機能も記述します。
- メッセージ: メソッドの入力または出力を表すオブジェクトです。
gRPC APIの定義は、上記の3つの基本構成要素を含む.protoファイルの形で書かれます。さらに、gRPCは.protoファイルからクライアントおよびサービスコードを生成するプロトコルバッファコンパイラを提供します。
サーバーサイドのメソッドは自由に実装できますが、APIの入出力契約には従わなければなりません。
クライアント側では、クライアント(またはスタブ)と呼ばれるオブジェクトがあります。これはHTTPクライアントのように、サーバーのすべてのメソッドを知っており、リモートプロシージャの呼び出しとその応答の返却を担当します。
比較
基盤となるHTTPプロトコル
これは最初のカテゴリであり、おそらく最も重要なものです。その影響は他のカテゴリにも見られます。
一般的に、RESTはリクエスト-レスポンスベースであり、HTTP/1.1をトランスポートメディアとして使用します。そのため、WebSocket(詳細はこちら)やストリーミング、より長期間の接続など、異なるプロトコルを使用する必要があります。
また、RESTをストリーミングのように見せるためのいくつかの不格好なコードを実装することもできます。さらに、HTTP/1.1 RESTを使用する場合、リクエスト-レスポンス交換ごとに1つの接続が必要です。このようなアプローチは、長期間実行されるリクエストや、ネットワーク能力が限られている場合に問題となる可能性があります。
もちろん、HTTP/2を使用してRESTライクのAPIを構築することもできますが、すべてのサーバーやライブラリがHTTP/2をサポートしているわけではありません。したがって、他の場所で問題が発生する可能性があります。
一方、gRPCはHTTP/2のみを使用します。これにより、1つのTCP接続を介して複数のリクエスト-レスポンスペアを送信できます。このようなアプローチは、アプリケーションのパフォーマンスを大幅に向上させる可能性があります。
- 結果: gRPCのわずかな勝利
サポートされているデータ形式
REST APIがHTTP/1.1を使用するデフォルトのケースを想定すると、多くの形式をサポートできます。
RESTは一般的にメッセージ形式やスタイルに制限を課しません。基本的には、プレーンな古いテキストにシリアル化できるすべての形式が有効です。特定のシナリオに最適な形式を使用できます。
RESTアプリケーションでデータを送信するための最も人気のある形式は間違いなくJSONです。XMLは多数の古い/レガシーアプリケーションのために2番目になります。
ただし、RESTをHTTP/2で使用する場合、サポートされるのはバイナリ交換形式のみです。この場合、ProtobufやAvroを使用できます。もちろん、このようなアプローチには欠点もありますが、これについては以下のポイントで詳しく説明します。
一方、gRPCはデータ交換に2つの形式のみをサポートします。
- Protobuf — デフォルト
- JSON — 古いAPIとの統合が必要な場合
JSONを試すことに決めた場合、gRPCはメッセージのエンコーディング形式としてJSONを使用し、メッセージ形式としてGSONを使用します。さらに、JSONを使用するには、いくつかの追加の設定が必要です。gRPCのドキュメントでその方法について説明しています。
- 結果:RESTの勝利です。より多くの形式をサポートしているためです。
データサイズ
デフォルトで、gRPCはバイナリデータ交換形式を使用し、これによりネットワーク上で送信されるメッセージのサイズが大幅に削減されます:研究によると、バイト単位で約40〜50%のサイズが小さくなります。以前のプロジェクトからの私の経験では、さらに50〜70%少なくなることもあります。
上記の記事では、JSONとProtobuffの間の比較的詳細なサイズ比較を提供しており、著者はJSONとバイナリファイルの生成に使用できるツールも提供しています。そのため、彼の実験を再実行して結果を比較することができます。
記事のオブジェクトはかなりシンプルですが、一般的なルールは、JSONの埋め込みオブジェクトが多く、構造が複雑なほど、Protobufに比べて重くなるということです。Protobufに対して50%のサイズ差は、良いベースラインです。
差異は、RESTのためのバイナリ交換形式を利用することで最小限に抑えるか、または排除することができます。しかし、RESTful APIを実行するための最も一般的で最もサポートされている方法ではありませんので、他の問題が発生する可能性があります。
- 結果:デフォルトの場合、gRPCの勝利;バイナリデータ形式を両方使用する場合、引き分け。
スループット
再び、RESTの場合、すべては基盤となるHTTPプロトコルとサーバーに依存します。
デフォルトの場合、HTTP/1.1に基づくRESTでは、最も高性能なサーバーであっても、特にJSONを使用する際のシリアル化および逆シリアル化オーバーヘッドを加えると、gRPCのパフォーマンスには勝てません。ただし、HTTP/2に切り替えると差異は縮小します。
最大スループットについては、どちらの場合も、HTTPはトランスポート媒体であるため、無限にスケールする可能性があります。したがって、すべては私たちが使用しているツールとアプリケーションで正確に何を行っているかに依存します。設計上の制限はありません。
- 結果:デフォルトの場合、gRPC;バイナリデータとHTTP/2を両方使用する場合、引き分けまたはgRPCのわずかな勝利。
定義
この部分では、両方のアプローチでメッセージとサービスをどのように定義するかを説明します。
ほとんどのRESTアプリケーションでは、リクエストとレスポンスをクラス、オブジェクト、または特定の言語がサポートする構造として宣言します。そして、シリアル化および逆シリアル化のための提供されたライブラリに依存して、JSON/XML/YAML、または必要なフォーマットを使用します。
さらに、REST API定義からSwaggerを使用して選択したプログラミング言語でコードを生成するツールを作成する取り組みが進行中です。しかし、これらはアルファバージョンにあるため、まだいくつかのバグや小さな問題が発生する可能性があり、それらを使用することが難しくなる場合があります。
RESTアプリケーションのバイナリ形式とノンバイナリ形式の間にはほとんど違いがありません。どちらの場合もルールはほぼ同じです。バイナリ形式の場合、特定の形式に必要な方法ですべてを定義するだけです。
さらに、私たちは基盤となるライブラリまたはフレームワークからのメソッドまたはアノテーションを通じてRESTサービスを定義しました。このツールはまた、他の設定とともにそれを外部に公開する責任があります。
gRPCの場合、Protobufがデフォルトであり、事実上唯一の定義の書き方です。メッセージ、サービス、メソッドをすべて.protoファイルで宣言する必要があります。つまり、その点は非常にシンプルです。
そして、gRPCが提供するツールを使用してコードを生成し、私たちはメソッドを実装するだけです。その後、すべてが意図した通りに動作するはずです。
さらに、Protobufはインポートをサポートしているため、設定を複数のファイルに分散させることが比較的簡単です。
- 結果:ここに勝者はいません。ただの説明と私からのアドバイスです。どちらのアプローチが最もあなたに合っているかを選ぶだけです。
採用の容易さ
この部分では、現代のプログラミング言語で各アプローチのライブラリ/フレームワークサポートを比較します。
一般的に、ソフトウェアエンジニアとしての短いキャリアで遭遇した各プログラミング言語(Java、Scala、Pythonなど)には、RESTライクなアプリケーションを作成するための少なくとも3つの主要なライブラリ/フレームワークがあり、オブジェクト/クラスにJSONをパースするための同様の数のライブラリも存在します。
加えて、RESTはデフォルトで人間が読める形式を使用するため、初心者にとってデバッグや作業が容易です。これは新機能の提供のペースにも影響を与え、コード内で発生するバグとの戦いに役立ちます。
要するに、RESTスタイルのアプリケーションのサポートは少なくとも非常に良いです。
Scalaでは、tapirと呼ばれるツールも存在します—私はしばらくの間、そのメンテナーの一人としてその楽しさを味わいました。TapirはHTTPサーバーを抽象化し、複数のサーバーで動作するエンドポイントを書くことができます。
gRPC自体は8つ以上の人気のあるプログラミング言語用のクライアントライブラリを提供しています。これらのライブラリはgRPC APIを作成するために必要なすべてを含んでおり、通常は十分です。また、Java(Spring Boot Starter経由)およびScala用のより高い抽象化を提供するライブラリも知っています。
もう一つの点は、RESTが今日世界標準として認識され、サービス構築の入り口となっているのに対し、RPCや特にgRPCは、ある程度古い技術であるにも関わらず、まだ新奇なものと見なされていることです。
- 結果: RESTはより広く採用され、多くのライブラリやフレームワークが存在するため
ツールサポート
ライブラリ、フレームワーク、そして一般的な市場シェアについては上記で触れたので、ここでは両スタイルの周辺ツールについて触れたいと思います。テスト、パフォーマンス/ストレステスト、そしてドキュメントのためのツールです。
自動化テスト/テスト
まず、RESTの場合、自動化テストを構築するためのツールは、さまざまなライブラリやフレームワークに組み込まれており、またREST-assuredのようにこの唯一の目的で構築された別個のツールもあります。
gRPCの場合、スタブを生成してテストに使用することができます。さらに厳密に行う場合は、生成されたクライアントを別のアプリケーションとして使用し、リアルなサービスのテストの基盤とすることができます。
gRPCの外部ツールサポートについては、以下のものがあることを知っています。
- PostmanアプリgRPCのサポート
- JetBrainsのIDEで使用されるHTTPクライアントは、最小限の設定でgRPCをサポートすることもできます。
- 結果一: RESTの勝利ですが、gRPCの状況は改善しています。
パフォーマンステスト
ここでは、JMeterやGatlingのようなツールにより、REST APIのストレステストが比較的簡単に行えるため、RESTには大きな利点があります。
残念ながら、gRPCにはそのようなサポートはありませんでした。Gatlingの開発者たちが現在のGatlingリリースにgRPCプラグインを含めていることを知っていますので、状況は改善されつつあります。
しかしまだ、ghzという1つの非公式プラェグインとライブラリしかありませんでした。これらは良いものですが、RESTのサポートレベルとは同じではありません。
- 結果二: RESTの勝利ですが、gRPCの状況は再び改善しています。;)
ドキュメント
APIドキュメントの場合、再びOpenAPIとSwaggerが業界全体で広く採用され、事実上の標準となっているため、RESTの勝利です。ほとんどすべてのRESTライブラリが、最小限の労力でまたはそのままでスワガドキュメントを公開できます。
残念ながら、gRPCにはこのようなものはありません。
しかし、問題はgRPCがこのようなツールを必要とするかどうかです。gRPCはその設計からRESTよりも記述的であるため、追加のドキュメンテーションツールは.
一般的に、APIの記述を伴う.protoファイルは、REST APIコードを作成するためのコードよりも宣言的でコンパクトであるため、gRPCからの追加のドキュメンテーションは必要ないかもしれません。答えはあなたに任せます.
- 結果3: RESTの勝利; しかし、gRPCのドキュメンテーションの問題は未解決です.
全体的な結果:
A significant victory for REST
概要
最終スコアテーブルは次のようになります.

スコアは両スタイル間で均等に分割され、それぞれ3つの勝利と明確な勝者のいない1つのカテゴリがあります.
銀の弾丸は存在しない: どのカテゴリがあなたのアプリケーションに最も重要かを考え、それらの多くで勝利したアプローチを選ぶべきです – 少なくとも私の推薦です.
私の好みについては、最後のプロジェクトでかなりうまく機能したので、可能であればgRPCを試してみたいと思います。それは古き良きRESTよりも優れた選択かもしれません.
RESTをgRPCより選ぶか、または他の技術的な問題に直面する必要がある場合は、お知らせください。私には助言できるかもしれません.
お時間をいただきありがとうございます。