TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

gRPCが解決する課題と全体像:契約書、コード生成、チャネル、HTTP/2

状態:草案 (2026-10-17)、一部実測。 基準バージョン grpc/grpc v1.84.0 (ドキュメント)、grpc/grpc-go v1.83.2 (コミット 030ee8becb20)。 実測は2026-10-17 03時台 (KST) に小さなクラスターからPrometheusを 読み取る だけで取得しました (クエリは第5節)。 作成規則:実測データを基本とし、測定できなかったものは「未測定」、確認できなかったものは「未確認」と表記します。

目次

1. 直感:電話の代わりにフォーマット

隣のチームに仕事を頼むとき、電話で話せば早いですが誤解が生じます。そのため、会社では フォーマットを作成します。欄の名前と順序、どの欄が 数値であるかが決まっていれば、受け取る側はフォーマットを見るだけで処理でき、フォーマットが少し変わっても(欄が1つ追加されるなど)古いフォーマットを使っている人と引き続き仕事ができます。

gRPCはこのフォーマットを .protoファイルに記述し、そのフォーマットから 両方の言語のコードを自動的に生成します。呼び出す側は client.Hit(ctx, req) のように 普通の関数を呼び出し、その下でライブラリがリクエストをバイト列に変換してHTTP/2接続で送信し、レスポンスを再びオブジェクトに戻します。 Googleが社内で10年以上使っていたRPC基盤(Stubby)の次世代版を2015年3月にオープンソース化することになったのが始まりであり、CNCFには 2017-02-16にインキュベーティング段階として参加しました(grpc.io/about, CNCFプロジェクトページ).

部品 責任 このシリーズでの
IDL(.proto) サービス・メソッド・メッセージの契約。フィールド番号が下位互換性のカギ 第2部
コード生成 (protoc + プラグイン) 言語別のメッセージ型、クライアントスタブ、サーバーインターフェース 第1部 第4節
チャネル (ClientConn) 名前解決、ロードバランス、接続維持、リトライ、deadline 第4・5・7部
HTTP/2トランスポート 1回の呼び出し = 1つのストリーム、5バイトのメッセージプレフィックス、トレーラーのステータスコード 第3部

2. 図解

gRPC 한 번의 호출: .proto 에서 서버 함수까지 rally.proto service·message 정의 protoc·플러그인 언어별 코드 생성 클라이언트 스텁 서버 인터페이스 실행할 때: 클라이언트 프로세스 앱: client.Hit(ctx, req) 스텁: 직렬화 → Invoke 채널 (ClientConn) 이름 풀이(resolver) 부하 분산(LB 정책) 서브채널 1 HTTP/2 연결 서브채널 2 HTTP/2 연결 서버 프로세스 HTTP/2 서버 전송 스트림 하나 = 호출 하나 :path 로 메서드 찾기 역직렬화 → 핸들러 앱 코드 Hit() 응답 반환 굵은 선: TCP 하나 위의 HTTP/2 스트림. 요청은 POST, 응답 끝의 트레일러에 grpc-status 가 실린다. 채널은 오래 살려 두고 여러 호출이 연결을 나눠 쓴다.
図:.protoからサーバー関数まで:コード生成と実行時のレイヤー

3. なぜJSON over HTTP/1.1ではないのか

RESTとJSONでもリモート呼び出しは可能です。gRPCが存在する理由を、契約・バイト列・接続・障害の4つに分けて整理すると次のようになります。

軸 一般的なREST/JSON gRPC 代償
契約 OpenAPIは任意であり、コードと乖離しやすい .protoがコードの信頼できる唯一の情報源(SSOT) ビルドにコード生成ステップが含まれる
バイト列 フィールド名を毎回文字列で送信する フィールド番号 + バイナリ値。第2部の例では21バイト vs JSONは72バイト 人間が直接読めない (第8部のツールが必要)
接続 HTTP/1.1は接続ごとに1リクエスト HTTP/2ストリームにより1つの接続で多数の呼び出し、双方向ストリーミングが可能 L4ロードバランスが接続単位のため偏りが生じる (第5部)
障害 HTTPステータスとレスポンスボディの形式がサービスごとに異なる 17種類のステータスコード、deadline伝播、リトライポリシーがライブラリ側に存在 適切なステータスコードを選択する責任はアプリケーションに残る (第3部)

ブラウザのJavaScript APIではHTTP/2フレームやトレーラーを直接扱えないため、gRPCをそのまま使用することは困難です。そのため、gRPC-WebやHTTP/JSON変換 ゲートウェイといった別のブリッジが存在します (このシリーズでは扱いません)。

4. コード生成が提供するもの

契約書の例です。シリーズを通じてこのサービスを使用します (卓球のラリー1回を記録する仮想的なサービス)。

syntax = "proto3";
package tt.v1;

message Rally { int32 rally_id = 1; string server = 2; repeated int32 hits = 3; bool won = 4; sint32 delta = 5; }
message Score { int32 home = 1; int32 away = 2; }

service Scoreboard {
  rpc Hit(Rally) returns (Score);                 // 단항
  rpc Watch(Rally) returns (stream Score);        // 서버 스트리밍
}

この契約における Hit のメソッドパスは /tt.v1.Scoreboard/Hit です。第3部のフレームの図もこのパスを使用します。

生成されたクライアントスタブが行うことは驚くほど少ないです。実際にprotocを実行せず、grpc-goのリポジトリに含まれる 実際に生成されたファイル (ヘルスチェックサービス)を見ると、1つのメソッドは次のようになっています。

const Health_Check_FullMethodName = "/grpc.health.v1.Health/Check"

func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
	cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
	out := new(HealthCheckResponse)
	err := c.cc.Invoke(ctx, Health_Check_FullMethodName, in, out, cOpts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

出典:grpc/grpc-go v1.83.2 health/grpc_health_v1/health_grpc.pb.go(protoc-gen-go-grpc v1.6.2により生成)、Apache-2.0

5. 実測:小さなクラスターでのgRPC通信

2026-10-17 03:00〜03:04 (KST)、Prometheusに次のクエリを送信しました (Kubernetes APIサーバーのサービスプロキシ経由のGET、読み取りのみ)。

count by (__name__, job) ({__name__=~"grpc_.*|.*_grpc_.*|rpc_.*"})
sum by (grpc_service, grpc_method, grpc_type) (grpc_client_started_total{job="apiserver"})
sum by (operation_type) (kubelet_runtime_operations_total)

メトリックに残ったgRPCサービス名をまとめると次のようになります (値の詳細については第6部)。

誰から → 誰へ gRPCサービス (メトリックラベル) 根拠
kube-apiserver → etcd etcdserverpb.KV·Watch·Lease·Maintenance apiserverの grpc_client_* メトリック
kubelet → containerd runtime.v1.RuntimeService·ImageService kubelet_runtime_operations_total のoperation_type 21種
アプリ → OTel Collector → Tempo OTLP TraceService/Export Collectorの transport="grpc"、エクスポート先 :4317
Tempo内部 /tempopb.Pusher/PushBytesV2, /grpc.health.v1.Health/Check tempo_request_duration_seconds のrouteラベル
Argo CD UI・CLI → argocd-server application.ApplicationService などの114個のメソッド grpc_server_started_total
サイドカー → istiod istio.v1.auth.IstioCertificateService/CreateCertificate istiodの grpc_server_*
hubble-relay → ノードごとのHubble observer.Observer·peer.Peer リレーログ、gRPCプローブ (第5・6部)

名前が etcdserverpb.KV のように protoパッケージ.サービス の形式になっているのは、第4節のパスの規則がそのままメトリックラベルとして引き継がれているからです。 逆にkubeletはgRPCの共通メトリックを使用せず、 list_containers のように独自の名前でカウントしています。同じgRPCであっても、観測方式は実装によって異なります。

6. チャネルの寿命:接続は長く、呼び出しは短く

7. 制限事項

8. 小さなクラスターとのつながり

クラスターを毎日触っていながらgRPCを直接書いたことがない場合でも、実はすでに1日あたり何億回も使用しているという点から確認するとよいでしょう。 コントロールプレーンノードAのetcdは起動以降Rangeを約8,333万回処理しており、8台のkubeletはCRIのリスト取得だけでも合計約6,900万回呼び出していました (第6部)。 次の部では、その呼び出し一つひとつがどのようなバイト列として送信されているのかを見ていきます。

ティティの一言: フォーマットさえしっかり作っておけば、相手がGoだろうとC++だろうと関係ありません。欄の番号だけは変えないようにしてくださいね。番号こそが約束事ですから!

参考資料

すべての資料は2026-10-17に閲覧しました。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます