gRPC

Google が開発した高性能な RPC フレームワークで、Protocol Buffers を用いた効率的なサービス間通信を実現する

RPC
gRPC」の技術書を見る →

gRPC とは

gRPC は、Google が 2015 年にオープンソースとして公開した高性能な RPC (Remote Procedure Call) フレームワークである。HTTP/2 上で Protocol Buffers (protobuf) を使い、言語に依存しない型安全な API 契約をサービス間で共有する。クライアントはローカル関数を呼び出すかのようにリモートサーバーのメソッドを実行できる。

Google 社内では Stubby という汎用 RPC 基盤が 10 年以上にわたってデータセンター内外のサービス接続に使われてきた。2015 年 3 月にその次世代版をオープンソースとして作る判断がなされ、生まれたのが gRPC である。2017 年 2 月に CNCF (Cloud Native Computing Foundation) に受け入れられ、2026 年 8 月時点では Incubating 段階のプロジェクトとして開発が続いている。

REST API との比較

REST API との主な違いを以下に比較する。

観点gRPCREST API
プロトコルHTTP/2HTTP/1.1 or HTTP/2
データ形式Protocol Buffers (バイナリ)JSON (テキスト)
スキーマ.proto ファイル (必須)OpenAPI (任意)
ストリーミング双方向対応非対応 (SSE で片方向)
ブラウザ対応gRPC-Web 経由ネイティブ対応
コード生成自動生成 (多言語)手動 or ツール
ペイロードサイズ小さい (バイナリ)大きい (テキスト + キー名)
人間の可読性低い (バイナリ)高い (JSON)

protobuf はフィールド名の代わりに .proto で決めたフィールド番号を送り、整数を可変長で詰める。そのため同じ内容の JSON よりペイロードは小さくなりやすいが、縮み方はデータの形に強く依存する。数値や列挙が多い構造では差が大きく、長い自由文字列が中身の大半を占めるペイロードでは文字列本体がそのまま残るのでほとんど変わらない (HTTP の圧縮を併用すると差はさらに縮む)。安定して効くのはむしろ、キー名の解析が要らないぶんシリアライズ/デシリアライズの CPU コストが低いことだ。マイクロサービス間で秒間数万リクエストを処理する経路では、この差が積み上がる。

Protocol Buffers の定義

Protocol Buffers の定義の例を示す。

syntax = "proto3";

service OrderService {
  rpc CreateOrder (CreateOrderRequest) returns (Order);
  rpc GetOrder (GetOrderRequest) returns (Order);
  rpc ListOrders (ListOrdersRequest) returns (stream Order);  // Server Streaming
}

message CreateOrderRequest {
  string customer_id = 1;
  repeated OrderItem items = 2;
}

message Order {
  string id = 1;
  string customer_id = 2;
  OrderStatus status = 3;
  int64 total_cents = 4;  // 金額はセント単位の整数で表現
}

enum OrderStatus {
  PENDING = 0;
  CONFIRMED = 1;
  SHIPPED = 2;
}

.proto ファイルから TypeScript、Go、Java、Python など各言語のクライアント/サーバーコードが自動生成される。契約が 1 か所に集まるため、Go や Java のような静的型付け言語ではフィールド名や型の食い違いをビルド時に検出できる。Python のような動的型付け言語では生成コードを使っても検出は実行時になるので、契約違反を早く止めたい層をどの言語で書くかは設計判断になる。

4 つの通信パターン

4 つの通信パターンを以下にまとめる。

パターン方向用途
Unary1 リクエスト → 1 レスポンス通常の API 呼び出し (REST と同等)
Server Streaming1 リクエスト → N レスポンスログストリーム、検索結果の逐次返却
Client StreamingN リクエスト → 1 レスポンスファイルアップロード、センサーデータの一括送信
Bidirectional StreamingN リクエスト ↔ N レスポンスチャット、リアルタイム同期

REST API では実現が難しい双方向ストリーミングが、gRPC ではネイティブにサポートされている。

採用の判断基準

gRPC が適するケース

  • バックエンドのマイクロサービス間通信 (高スループット、低レイテンシが求められる)
  • 多言語環境 (Go のサービスと TypeScript のサービスが通信する)
  • ストリーミングが必要な場面 (リアルタイムデータ、大量データの逐次処理)
  • 厳密な API 契約が必要な場面 (型安全性、後方互換性の管理)

REST API が適するケース

  • ブラウザとの直接通信 (gRPC-Web は追加のプロキシが必要)
  • 外部パートナーへの API 公開 (JSON の方が広く理解されている)
  • シンプルな CRUD API (gRPC のセットアップコストが見合わない)
  • デバッグのしやすさを重視する場面 (JSON は人間が読める)

実務では、外部向けは REST API、内部のサービス間通信は gRPC というハイブリッド構成が一般的だ。

.proto ファイルの管理

チーム間で .proto ファイルを共有する方法が運用上の重要な課題になる。

  • モノレポ: 全サービスの .proto を 1 つのリポジトリで管理。変更の影響範囲が一目で分かる
  • 専用リポジトリ: .proto ファイルだけを管理するリポジトリを作り、各サービスが参照する
  • Buf Registry: Buf (protobuf のツールチェーン) のレジストリで .proto をパッケージとして配布する

後方互換性の管理も重要だ。互換性を壊すのはフィールド名ではなくフィールド番号の扱いで、削除したフィールドの番号を別の意味で使い回すと、更新前のバイナリが古い解釈のまま読んでしまう。削除したフィールドは reserved で番号と名前を封じておく。既存フィールドの型を変えるのも破壊的変更だ。一方 proto3 に required は無く、フィールドを足すこと自体は互換性を壊さない。buf breaking コマンドで CI に互換性チェックを組み込む。

実践的な知識は関連書籍でも得られる。

この記事は役に立ちましたか?

関連用語

関連する記事