0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

フロントエンジニアがインフラを理解する【その2】gRPCについて

0
Last updated at Posted at 2026-04-19

こんにちは、おさわです😆
今回は、フロントエンジニアがインフラを理解する【その2】と題しまして、RPCについて学びました。
4月から新しい環境となり、その研修の一環としてチーム開発を同期と進めています。
その中で、「gRPCを使う」ということを言われ、ホゥ...🤨となったので、学習がてらまとめました!

RPC (Remote Procedure Call) とは?

日本語では「遠隔手続き呼出し」と呼びます。

  • RESTの場合: GET /api/users/1 という「場所」にアクセスしてリソースを取得する

  • RPCの場合: getUser(id: 1) という「関数」を、ネットワーク越しに実行する

エンジニアにとっては、URLやHTTPメソッドを意識するよりも「型定義された関数を叩く」感覚に近いため、開発体験が良いのが特徴だそうです🤩

gRPC (Google Remote Procedure Call) とは?

Googleが開発した、モダンで高速なRPCフレームワークです。主に以下の3つの技術要素で成り立っています。(参考:https://grpc.io/)

① Protocol Buffers (Protobuf)

データのシリアライズ(構造化データをバイナリに変換すること)に使われます。
JSONは人間が読める「テキスト」ですが、Protobufは機械が効率よく読める「バイナリ」です。

  • メリット: データサイズが圧倒的に小さく、通信が高速
  • 型安全性: .proto ファイルという設計図を作成し、そこからTypeScriptやGo、Javaなどのコードを自動生成します

1. JSONの場合:冗長なテキスト情報

例えば、ユーザー情報を送る以下のJSONを見てください。

JSON
{
  "id": 101,
  "name": "Yamada"
}

このデータは、コンピュータから見ると非常にムダが多いです。

  • "id" や "name" という**フィールド名(キー)**が毎回送られる

  • { } , : " といった記号もすべて1バイト以上のデータとしてカウントされる

  • 数値の 101 も、テキストとして 1 0 1 の3文字分(3バイト)消費される

このJSONを転送するには、合計で 約30バイト ほど必要になります。

2. Protobufの場合:極限まで削ったバイナリ

Protobufでは、まず .proto という設計図(スキーマ)をクライアントとサーバーの両方が持っていることが前提になります。

Protocol Buffers
message User {
  int32 id = 1;      // idは「1番」のフィールド
  string name = 2;   // nameは「2番」のフィールド
}

この設計図があるおかげで、実際の通信では "id" という文字列を送る必要がなくなります。代わりに「1番のデータは 101 です」「2番のデータは Yamada です」という情報だけを送ります。
上記のデータをProtobufでバイナリ化すると、わずか 11バイト 程度になります。

↓ 具体的にどう変換されるか

  • Tag(1バイト): 「フィールド番号1」であることを示す

  • Value(1バイト): 数値 101

  • Tag(1バイト): 「フィールド番号2」であることを示す

  • Length(1バイト): 文字列の長さ(8文字)

  • Value(8バイト): Yoshioka という生データ

「キーの名前」や「区切り記号」が一切消え、データそのものだけが並ぶのがバイナリの強みです!

なぜ「バイナリ」はフロントエンドに嬉しいのか?

「たかだか数十バイトの差でしょ?」と思うかもしれませんが、大規模なWebアプリではこの差が決定的なパフォーマンスの差になります。

  • パース(解析)が速い: JSONは文字列をスキャンして構造を理解する必要がありますが、バイナリは構造が決まっているため、CPUがそのままメモリに展開でき、解析コストが極めて低いです

  • モバイル回線に強い: 通信量が減るため、電波が不安定な環境や従量課金の環境でユーザー体験が向上します

  • 型安全: 設計図(.proto)からTypeScriptの型を生成できるため、フロントエンドで「APIからどんなデータが来るか」を迷うことがなくなります

② HTTP/2

gRPCは基盤となる通信プロトコルに HTTP/2 を採用しています。

  • 双方向ストリーミング: クライアントとサーバーで同時にデータを送り合える(チャットやリアルタイム通知に強い)
  • 多重化: 一つのコネクションで複数のリクエストを並列処理できる

HTTP/1.1 vs HTTP/2 とバイナリ転送

  • HTTP/1.1 (テキスト): GET /index.html HTTP/1.1 のように、人間が読める文字列でやり取りします。解析に時間がかかり、データの重複も多いです。また、1つのリクエストが終わるまで次のリクエストを送れない(順次処理)。これを避けるためにブラウザは複数のコネクション(ホース)を張りますが、効率が悪いです(Head-of-Line Blocking)

  • HTTP/2 (バイナリ): データを「フレーム」という小さなバイナリ(0と1の塊)の単位に分割します。1つのコネクション(ホース)の中に、複数の「ストリーム」を流せます。HTML、CSS、JS、gRPCのデータを同時に混ぜて送れるため、待ち時間が発生しません

③ インターフェース定義言語 (IDL)

.proto ファイルに「どんな関数があり、どんな引数を受け取るか」を定義します。これにより、フロントエンドとバックエンドの「型」が強制的に一致するため、「APIの仕様が変わってフロントが壊れた」という事故が防げます。

フロントエンドエンジニアが知っておくべき「gRPC-Web」

実は、ブラウザ(JavaScript)はHTTP/2の低レイヤーな操作を完全にはサポートしていないため、gRPCを直接叩くことができません。
そこで使われるのが gRPC-Web です!

  • ブラウザとgRPCサーバーの間に「プロキシ(Envoyなど)」を挟み、ブラウザからのリクエストをgRPCに変換して伝えます

なぜフロント(ブラウザ)からgRPCを呼ぶ際にプロキシが必要なのか

その理由は「ブラウザの制約」にあります。

ブラウザができないこと

gRPCはHTTP/2の非常に細かい制御(特定のバイナリフレームの操作など)を必要としますが、現在のブラウザの fetch や XHR APIでは、そこまで低レイヤーな制御が許されていません。

Envoyによる「翻訳」

そこで、ブラウザとサーバーの間に Envoy を配置します。

  1. フロントエンド: gRPC-Web ライブラリを使用して、HTTP/1.1(またはブラウザ互換のHTTP/2)でリクエストを送ります。データはバイナリですが、HTTPヘッダーなどでラップされています

  2. Envoy (プロキシ): この「ブラウザ用gRPCリクエスト」を受け取り、純粋な「gRPC(HTTP/2バイナリ)」に変換して、バックエンドのgRPCサーバーへ転送します

  3. バックエンド: Envoyからの純粋なgRPCを受け取って処理します

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?