Go

gRPC Gateway + REST で外部公開し、k6 を用いた並列ストリーム負荷試験で スループット × 可観測性

はじめに

マイクロサービスの普及により、gRPC を使った高速なサービス間通信が一般的になりました。しかし、外部のクライアントやサードパーティとの連携では、依然として REST API が求められることが多く存在します。そのため、gRPC サービスを外部公開するには gRPC-Gateway を活用して REST API を提供するアプローチが有効です。

本記事では、以下の3点を中心に解説します:

  1. gRPC-Gateway による gRPC サービスの REST 化の実装方法
  2. k6 を使った並列ストリームによる負荷試験の設計と実行
  3. OpenTelemetry と Prometheus による可観測性の確保と可視化

最終的に、スループットやレイテンシ、エラー率といったパフォーマンスメトリクスを収集・分析し、システムのボトルネックを明らかにします。


背景と技術選定

gRPC

  • HTTP/2 をベースとした高効率な RPC プロトコル
  • 双方向ストリームや圧縮などの機能により、リアルタイム通信にも適する

gRPC-Gateway

  • Protocol Buffers の定義から自動的に REST API を生成
  • REST クライアントと gRPC サーバ間のプロキシとして動作

k6

  • JavaScript でテストシナリオを記述可能
  • 高負荷にも耐える軽量設計
  • CLI とグラフ表示ツールで開発者フレンドリー

システム構成図

以下の図は、本記事で扱うアーキテクチャ構成を表しています。

  • k6: クライアントから HTTP/1.1 経由でリクエストを送信
  • gRPC-Gateway: REST リクエストを gRPC に変換
  • gRPC Server: 双方向ストリーム対応の gRPC サービスを実行

gRPC サービスの実装 (Go)

まず、proto ファイルを用いて以下のように双方向ストリームを定義します。

service EchoService {
  rpc EchoStream(stream EchoRequest) returns (stream EchoResponse);
}

message EchoRequest {
  string message = 1;
}

message EchoResponse {
  string reply = 1;
  int64 timestamp = 2;
}

サーバ側では、一定間隔で受信したメッセージに対してレスポンスを返す処理を行います。


gRPC-Gateway の設定とビルド

gRPC-Gateway を利用するには、以下のツールが必要です:

  • protoc
  • protoc-gen-go
  • protoc-gen-grpc-gateway

REST エンドポイントを以下のように定義できます:

option (google.api.http) = {
  post: "/v1/echo"
  body: "*"
};

これにより、/v1/echo という REST API 経由で gRPC サービスが呼び出されます。


k6 による負荷試験の設計

以下のスクリプトは、100ユーザで 30 秒間並列に POST リクエストを送信し続ける k6 の負荷試験スクリプトです。

import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
  vus: 100,
  duration: '30s',
};

export default function () {
  let res = http.post('http://localhost:8080/v1/echo', JSON.stringify({ message: "hello" }), {
    headers: { 'Content-Type': 'application/json' },
  });
  check(res, {
    'status was 200': (r) => r.status === 200,
  });
  sleep(1);
}

k6 によって得られるメトリクス(例:平均レスポンス時間、スループット、エラー率)は、REST API 経由でのパフォーマンス測定に非常に有効です。


可観測性の実装

使用技術

  • OpenTelemetry (Tracing + Metrics)
  • Prometheus (時系列メトリクス収集)
  • Grafana (可視化)

メトリクス例

  • リクエスト数/秒
  • レイテンシ (p50, p95, p99)
  • エラー率
  • gRPC 処理時間

OpenTelemetry を使用することで、gRPC の内部処理のトレーシングも実現可能です。Grafana によって、負荷中の傾向を一目で把握できます。


実験結果(例)

  • スループット: 約 2,500 req/sec
  • p95 レイテンシ: 135ms
  • エラー率: 0.2%

※ CPU やネットワーク帯域により結果は異なります。負荷分散の構成によりさらなる改善が可能です。


考察

REST over gRPC のパフォーマンス

REST 経由の呼び出しは HTTP/1.1 を使うため、gRPC の持つ HTTP/2 の利点を活かしきれない側面があります。しかし、gRPC-Gateway によって簡便に REST 化できるメリットは大きく、外部公開や互換性の確保に役立ちます。

k6 の活用

k6 による並列テストでは、接続数上限や帯域に注意しながらシナリオ設計することが重要です。シンプルな POST だけでなく、ストリーム負荷のエミュレーションも可能です。

可観測性の意義

OpenTelemetry によるトレーシングとメトリクス収集を導入することで、パフォーマンス問題の原因分析が容易になります。特に、スロークエリや処理ボトルネックの特定に有効です。


今後の展望

gRPC-Web 対応:ブラウザクライアントへの対応強化

通常の gRPC は HTTP/2 に依存しており、ブラウザ環境では WebSocket を利用しない限り直接利用することができません。そこで登場するのが gRPC-Web です。gRPC-Web は HTTP/1.1/2 上で動作する軽量プロトコルであり、JavaScript などのブラウザベースのクライアントでも gRPC サービスを呼び出せるようになります。

  • gRPC-Web は主に一方向通信(Unary)に対応し、ストリーミングには限定的
  • Envoy や gRPC-Web proxy を用いることで、gRPC を Web 環境でも活用可能
  • Web UI とのシームレスな連携により、SPA(Single Page Application)との統合がスムーズに

将来的には、Web フロントエンドとバックエンド間の通信も gRPC ベースに統一する構成が現実的になります。

サービスメッシュ連携:Envoy や Istio によるトラフィック制御とトレーシングの一元化

サービスメッシュ(例:Istio, Linkerd)を導入することで、トラフィックの制御や observability をインフラレイヤーで管理できるようになります。

  • Envoy がデフォルトのデータプレーンプロキシとして動作し、gRPC のトラフィックを詳細に制御可能
  • トレーシングやメトリクス収集 は、Istio + Prometheus + Jaeger で構成することで完全に統合可能
  • リトライ・レート制限・サーキットブレーカ などの高度な制御もコードレスで導入できる

gRPC は HTTP/2 ベースであるため、Envoy を介した通信の最適化に親和性が高く、マイクロサービスアーキテクチャにおいては今後の基盤技術として極めて重要です。

CI/CD への統合:k6 を自動化テストの一部に組み込み、性能退化の検知を早期化

モダンなソフトウェア開発では、継続的インテグレーション(CI)および継続的デリバリー/デプロイメント(CD)が不可欠です。k6 は CLI ベースかつ非インタラクティブな実行環境に対応しているため、CI/CD パイプラインに統合しやすいという特長があります。

以下のような構成が一般的です:

  • GitHub Actions や GitLab CI/CD などのジョブ内で k6 スクリプトを実行
    • サービスのビルド・デプロイ後、E2E テストや負荷試験を自動で走らせる
    • 例: k6 run -e BASE_URL=https://staging.example.com load_test.js
  • しきい値チェックによるテスト失敗の制御
    • k6 の thresholds 機能を使い、p95 レイテンシやエラー率などに制限を設けることで、性能劣化を CI レベルで検出可能
    • 例: p95 レイテンシ > 500ms の場合は CI を fail させる
  • 結果の可視化と履歴管理
    • 出力結果を JSON や InfluxDB 形式で保存し、Grafana や k6 Cloud で可視化
    • 長期的な性能トレンドのモニタリングにも応用可能

このように、CI/CD に k6 を組み込むことで「コードの変更による性能退化の早期発見」が可能になり、パフォーマンス品質の高い継続的デリバリーが実現します。


実装リポジトリ

本記事の内容は以下の GitHub リポジトリで動作検証可能な状態で実装されています:

👉 https://github.com/lancelot89/go-blog-examples/tree/feature/04-grpc-gateway-k6-observability

Docker Compose、Makefile、README を含めた一貫した構成により、誰でも簡単にローカルで gRPC-Gateway, k6, OpenTelemetry を使った構成を試すことができます。

まとめ

  • gRPC-Gateway によって、gRPC サービスを REST API として簡単に外部公開できる
  • k6 によって、並列負荷シナリオの柔軟な設計と実行が可能
  • OpenTelemetry + Prometheus + Grafana により、スループットとレイテンシの詳細な可視化が実現

本構成は、高パフォーマンスなサービスを外部連携しつつも、開発者体験と可観測性を両立させる理想的なアプローチです。


次回予告

次回の記事では、gRPC-Web を実際にフロントエンド(Next.js)と連携して構築する方法について詳しく解説します。REST API を使わず、gRPC-Web を通じて Web UI から gRPC サービスにアクセスする構成を実現することで、より高速かつ型安全なアプリケーション開発が可能になります。

  • gRPC-Web のセットアップ方法
  • Envoy を使ったプロキシ設定
  • Next.js からの gRPC 通信の実装例

gRPC を「ブラウザの世界」に持ち込む第一歩として、ぜひご期待ください。

  • この記事を書いた人

ふくまる

機械設計業をしていたが25歳でエンジニアになると決意して行動開始→ 26歳でエンジニアに転職→ 28歳でフリーランスエンジニアに→ 現在、34歳でフリーランス7年目 Go案件を受注中 Go,GCPが得意分野

-Go