LASSIC Media らしくメディア
gRPC API開発を外注で進める進め方と設計
この記事のポイント
- gRPCはHTTP/2ベースの通信フレームワークで、Protocol Buffersによるスキーマ駆動のインターフェース定義が中心にあります。
- REST・GraphQLとは適した用途が異なり、内部マイクロサービス間の通信や双方向ストリーミングが必要な場面で選択肢になります。
- ブラウザから直接呼び出せない制約やゲートウェイでのREST併存など、導入時の論点を把握したうえで外注の委託範囲を整理する必要があります。
目次
gRPCとは — HTTP/2とProtocol Buffersを基盤とするRPCフレームワーク
gRPCとは、Googleが開発しCloud Native Computing Foundation(CNCF)でホストされているオープンソースのRPC(Remote Procedure Call)フレームワークです。gRPC公式サイトは、gRPCを「高性能なオープンソースの汎用RPCフレームワーク」と位置づけ、「1秒あたり数百万のRPCにまでスケールする」設計であるとしています*1。トランスポート層にはHTTP/2を採用しており、公式サイトは「双方向ストリーミングと、認証機能を完全に統合できるプラガブルな仕組みを、HTTP/2ベースのトランスポート上で実現する」と説明しています*1。
gRPCの中核となる考え方について、公式ドキュメントは「gRPCでは、クライアントアプリケーションが、あたかもローカルオブジェクトであるかのように、別のマシン上にあるサーバーアプリケーションのメソッドを直接呼び出せる」と説明しています*2。呼び出すメソッドの引数・戻り値の型やサービスの構造は、既定ではProtocol Buffersという仕組みを使って定義します。公式サイトは「gRPCは既定でProtocol Buffersを使う。これはGoogleが開発した、構造化データをシリアライズするための成熟したオープンソースの仕組みである」としています*2。
もう一つの特徴が言語・プラットフォームを問わない相互運用性です。公式サイトは「さまざまな言語・プラットフォーム向けに、サービスのクライアント・サーバースタブを自動生成する」機能を挙げており*1、単一のインターフェース定義ファイルから複数言語のコードを生成できる点が、異なる言語で実装されたマイクロサービス間の通信基盤として採用される理由の一つになっています。
REST・GraphQLとの使い分け — 内部通信とブラウザ向けの境界線
gRPCとREST・GraphQLは、いずれもクライアント・サーバー間の通信を実現する仕組みですが、得意とする場面が異なります。gRPCはHTTP/2上で動作し、公式サイトが示す「1秒あたり数百万のRPC」という規模のスループットを想定した設計であるため*1、マイクロサービス間のように内部ネットワークで高頻度に呼び出しが発生する通信に向いています。また後述する双方向ストリーミングに標準対応している点も、REST APIには見られない特徴です。
一方でgRPCには、ブラウザから直接呼び出せないという制約があります。gRPC公式ドキュメントは、ブラウザ環境での利用について「gRPC-Webを使うと、この方法で構築されたgRPCサービスに、慣用的なAPIを使ってブラウザからアクセスできるようになる」と説明しており*3、ブラウザ向けには別途gRPC-Webという仕組みと、リクエストを中継するプロキシが必要になることを示しています。同ドキュメントでは構成例として、ブラウザからのリクエストをEnvoyプロキシが受け取り、バックエンドのgRPCサーバーへ転送する構成が紹介されています*3。REST APIやGraphQLのようにブラウザから直接エンドポイントを呼び出す設計に比べると、フロントエンド公開用の窓口としては構成要素が一段増える点が実務上の考慮点です。
この特性から、実務では「外部公開・ブラウザ向けのAPIはREST(またはGraphQL)、内部のマイクロサービス間通信はgRPC」という役割分担が採用されることがあります。GraphQLは複数リソースを1回のクエリで柔軟に取得したいクライアント主導の用途に適し、RESTはリソース単位でのシンプルな設計や外部公開APIの標準的な選択肢として使われます。gRPCはこれらとは異なり、サービス間の内部通信における低レイテンシ性とスキーマの厳密さを重視する場面での選択肢になります。どの方式を選ぶかは、呼び出し元がブラウザか内部サービスか、ストリーミングが必要か、スキーマの厳密な管理が必要かという観点から整理する必要があります。
Protocol Buffersによるスキーマ設計と後方互換性
Protocol Buffersとは、構造化データをシリアライズするための言語非依存・プラットフォーム非依存の仕組みです。Protocol Buffers公式ドキュメントは、これを「言語非依存・プラットフォーム非依存で拡張可能な、構造化データをシリアライズするための仕組み」と定義しています*4。開発者は`.proto`という拡張子のファイルに、メッセージの構造(フィールド名・型・フィールド番号)とサービスのインターフェースを定義します。
この`.proto`ファイルをprotocというコンパイラで処理すると、指定した言語向けのコードが自動生成されます。公式ドキュメントは、生成されるコードについて「ファイルやストリームからデータを取得するユーティリティメソッドや、個々の値を取り出すメソッド」などを備えると説明しており*4、例としてJavaでは値の設定やシリアライズを担う`Builder`クラスが生成される仕組みを紹介しています*4。gRPCではこの`.proto`ファイルにサービスのメソッド定義も含めるため、スキーマ1つからクライアント・サーバー双方のコードをまとめて生成できます。
Protocol Buffersのスキーマ設計で特に重要なのが、フィールド番号を用いた後方互換性の管理です。公式ドキュメントは「フィールド番号は、一度メッセージタイプで使用されると、その用途を変えたり再利用したりすることはできない」と明記しており*4、フィールドを削除する場合は「そのフィールド番号を予約しておくべきである」としています*4。また、メッセージ定義を更新した場合の互換性について「古いコードは新しいメッセージを問題なく読み取り、新しく追加されたフィールドは無視する」「削除されたrepeatedフィールドは空になる」と説明されています*4。この規則に沿ってフィールドを追加・削除すれば、クライアントとサーバーのスキーマバージョンが完全に一致していなくても通信を継続できます。逆に、フィールド番号を再利用したり、型を変更したりすると、送受信するデータの解釈が食い違い、通信の不整合につながる点に注意が必要です。
4種類のRPCと双方向ストリーミングの使いどころ
gRPCの特徴の一つが、1つのメソッド呼び出しにつき1つの応答を返す方式以外に、複数のストリーミング方式を標準でサポートしている点です。gRPC公式ドキュメントは、gRPCで定義できるメソッドの種類を次の4つに分類しています*2。
1つ目は単項RPC(Unary RPC)です。公式ドキュメントは「クライアントが単一のリクエストをサーバーに送り、単一のレスポンスを受け取る」方式と説明しています*2。単純な呼び出し方式で、通常の関数呼び出しに近い形です。2つ目はサーバーストリーミングRPCで、「クライアントがサーバーにリクエストを送り、一連のメッセージを読み取るためのストリームを受け取る」方式です*2。1回のリクエストに対して複数の応答が時間差で返ってくる場面に向きます。
3つ目はクライアントストリーミングRPCで、「クライアントが一連のメッセージを書き込んでサーバーに送信する」方式です*2。センサーデータの逐次送信など、クライアント側から連続的にデータを送りたい場面に対応します。4つ目は双方向ストリーミングRPCで、「両方の側が読み書き可能なストリームを使って一連のメッセージを送り合う」方式です*2。クライアントとサーバーが互いに独立したタイミングでメッセージを送受信できるため、チャットやリアルタイム同期のような双方向のやり取りが必要な処理に適しています。
REST APIは基本的に単項RPCに相当するリクエスト・レスポンス型の通信を前提とした設計が主流であり、ストリーミングを実現する場合はWebSocketなど別の仕組みを組み合わせる必要があります。gRPCはこれら4種類のRPCを同一のフレームワーク・同一のスキーマ定義の枠組みで扱える点が、双方向のリアルタイム通信を伴うシステムを設計する際の判断材料になります。
導入の論点 — 可観測性・エラーモデル・ロードバランシング・ゲートウェイ併存
gRPCを実システムに導入する際は、機能面の理解に加えて運用面の論点を整理しておく必要があります。第一に可観測性です。gRPCはHTTP/2上のバイナリプロトコルで通信するため、REST APIのようにHTTPリクエストの内容をそのまま目視確認することが難しく、ログ・トレーシング・メトリクスの収集方法をあらかじめ設計に組み込む必要があります。サービス間通信が増えるマイクロサービス構成では、どのサービス間の呼び出しで遅延やエラーが発生しているかを追跡できる仕組みの有無が、障害対応の速度を左右します。
第二にエラーモデルです。gRPCはHTTPのステータスコードとは別の独自のステータスコード体系でエラーを表現する設計になっており、REST APIのHTTPステータスコードに慣れたチームは、エラーハンドリングの実装方針をgRPC向けに設計し直す必要があります。エラーの種類ごとにクライアント側でどう処理するかを、実装着手前に取り決めておくことが望まれます。
第三にロードバランシングです。gRPCはHTTP/2の持続的なコネッション上で複数のリクエストを多重化する仕組みのため、従来のHTTP/1.1を前提としたロードバランサーの設定がそのまま流用できない場合があります。コネクションレベルではなくリクエストレベルでの負荷分散を実現する構成を検討する必要があり、利用するインフラ・プロキシがgRPC対応であるかの確認が導入前の工程に含まれます。
第四にAPIゲートウェイでのREST併存です。前述の通りgRPCはブラウザから直接呼び出せないため、外部公開が必要なAPIについては、ゲートウェイ層でRESTやgRPC-Web形式に変換して公開する構成が実務上の選択肢になります。内部はgRPCで統一しつつ、外部向けの窓口だけをREST互換に変換する設計にするか、外部向けAPIは最初からREST/GraphQLで別途用意するかは、システム全体のAPI構成を検討する段階で決めておくべき論点です。
外注の委託範囲と発注準備
gRPCによるAPI開発を外注する場合の委託範囲は、大きく分けて「`.proto`スキーマ設計のみ」「スキーマ設計から実装まで一括」「実装のみ(スキーマは発注側が確定済み)」の3パターンが考えられます。gRPCはスキーマ定義から複数言語のコードを生成する構成のため、スキーマ設計の段階でサービス間のインターフェースが事実上確定します。契約駆動開発のOpenAPIと同様に、スキーマ設計を先に固めてから実装を外注する進め方は、フロント・バックエンドならぬサービス間の並行開発を可能にします。
発注側の準備としては、まず対象とするサービス間通信の範囲(どのサービスとどのサービスの間でgRPCを使うか)を明確にする必要があります。既存のマイクロサービス構成がある場合は、サービス間の呼び出し関係と、それぞれの呼び出しが単項RPCで十分か、ストリーミングが必要かを棚卸ししておくと、外注先が`.proto`ファイルを設計する際の精度が上がります。また、外部公開が必要なAPIが含まれる場合は、ゲートウェイでのREST変換が必要になる可能性があるため、公開範囲と非公開範囲の区分もあわせて整理しておく必要があります。
可観測性・エラーモデル・ロードバランシングといった運用面の要件についても、発注前にどこまでを外注先の設計範囲に含めるかを取り決めておくことが望まれます。特に既存のログ収集基盤・監視基盤がある場合、gRPC通信をその基盤に統合する作業が発生するため、既存インフラとの接続方式を要件として明示しておくと、外注先の見積もり精度が上がります。スキーマレビューを誰が最終承認するか、フィールド番号の管理ルール(削除時の予約運用等)を誰が管理するかといった体制面の取り決めも、発注前に固めておくべき事項です。
まとめ:gRPC API開発外注の判断軸
本稿では、gRPCによるAPI開発・導入の特徴と外注時の論点を整理しました。要点は3つに集約されます。第一に、gRPCはHTTP/2を基盤としProtocol Buffersでスキーマを定義するRPCフレームワークであり、内部マイクロサービス間の通信や双方向ストリーミングが必要な場面に適する一方、ブラウザから直接呼び出すにはgRPC-Webとプロキシが必要という制約があります。第二に、Protocol Buffersのフィールド番号管理を正しく運用すれば、クライアント・サーバーのバージョンが完全一致していなくても後方互換性を保てます。第三に、外注時は可観測性・エラーモデル・ロードバランシング・ゲートウェイでのREST併存といった運用面の論点を発注前に整理し、委託範囲(スキーマ設計のみ/一括/実装のみ)を明確にしておくことが実務上の前提になります。
よくある質問
gRPCとREST APIはどちらを選ぶべきですか。
用途によって異なります。ブラウザから直接呼び出す外部公開APIにはRESTやGraphQLが向いており、内部のマイクロサービス間で低レイテンシな通信やストリーミングを必要とする場合はgRPCが選択肢になります。両方を併用し、ゲートウェイ層で変換する構成も実務では採用されます。
gRPCをブラウザから直接呼び出すことはできますか。
gRPC公式ドキュメントによれば、ブラウザからgRPCサービスにアクセスするにはgRPC-Webという仕組みと、リクエストを中継するプロキシ(Envoy等)が必要です。gRPCの標準的な実装をそのままブラウザから呼び出すことはできません。
Protocol Buffersのスキーマを変更すると既存のクライアントは動かなくなりますか。
Protocol Buffers公式ドキュメントが示す規則(フィールド番号を再利用しない、削除時は番号を予約する等)に沿って変更すれば、古いクライアントは新しいメッセージのうち認識できるフィールドだけを読み取り、新しいフィールドは無視するため、後方互換性を保てます。規則に反した変更を行うとデータの解釈が食い違うおそれがあります。
gRPCの4種類のRPCはすべて使う必要がありますか。
必須ではありません。単項RPCのみで要件を満たせるサービスも多くあります。連続的なデータ送信やリアルタイムの双方向通信が必要な場合に限り、サーバーストリーミング・クライアントストリーミング・双方向ストリーミングを選択的に使う設計が一般的です。
gRPCのスキーマ設計だけを外注し、実装は内製することはできますか。
可能です。`.proto`ファイルによるスキーマ定義と実装は分離できるため、スキーマ設計のみを外部パートナーに委託し、生成されたスタブへの実装は内製するという分担が成立します。この場合はフィールド番号の管理ルールとレビュー体制を発注前に明確にしておく必要があります。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Google/CNCF「grpc.io公式サイト(トップページ)」(https://grpc.io/)
- *2 出典:Google/CNCF「gRPC Documentation – Introduction to gRPC」「Core concepts, architecture and lifecycle」(https://grpc.io/docs/what-is-grpc/introduction/、https://grpc.io/docs/what-is-grpc/core-concepts/)
- *3 出典:Google/CNCF「gRPC Documentation – gRPC-Web (Basics tutorial)」(https://grpc.io/docs/platforms/web/basics/)
- *4 出典:Google「Protocol Buffers Documentation – Overview」(https://protobuf.dev/overview/)