本文へスキップ
gRPC 入門(C# / .NET)— ASP.NET Core で始める高速な RPC 通信のアイキャッチ画像
Architecture

gRPC 入門(C# / .NET)— ASP.NET Core で始める高速な RPC 通信

公開: 更新: 約6分で読めます

マイクロサービスが当たり前になり、サービス間をどう繋ぐかが設計の要になっています。REST/JSON は手軽ですが、大量の内部通信では速度・型安全・ストリーミングの面で物足りない場面が出てきます。そこで定番になっているのが gRPC です。.NET は gRPC を第一級でサポートしており、ASP.NET Core だけで高速な RPC サーバーとクライアントを短時間で作れます。本記事では、gRPC の基礎から .proto の定義・サーバー実装・クライアント呼び出し・4つの通信方式までを、手を動かせる形で解説します。

gRPC とは何か

gRPC は Google が公開している RPC(Remote Procedure Call)フレームワークです。ネットワーク越しのメソッド呼び出しを、あたかもローカルの関数呼び出しのように書けます。特徴は大きく3つあります。HTTP/2 を土台にした多重化・双方向ストリーミング、Protocol Buffers(Protobuf)によるバイナリシリアライズ、そして .proto という契約からサーバー/クライアントのコードを自動生成することです。

gRPC と REST/JSON の比較。プロトコル・データ形式・コード生成・ストリーミング・ブラウザ対応の違い。
gRPC と REST の主な違い。公開 API やブラウザ直結は REST、サービス間の高速・型安全な通信は gRPC が向く。

ポイントは どちらが優れているかではなく、用途が違うということです。ブラウザから直接叩く公開 API は今も REST が扱いやすい一方、サービス間の内部通信やリアルタイム連携では gRPC の速度と型安全が効いてきます。実際、.NET の gRPC は言語横断ベンチマークでも上位のスループットを記録しています。

.proto で「契約」を定義する

gRPC の出発点は .proto ファイルです。ここに サービス(メソッド)とメッセージ(データ構造)を宣言すると、そこからサーバーとクライアントのコードが生成されます。まずは典型的な挨拶サービスを定義します。

syntax = "proto3";

option csharp_namespace = "GrpcGreeter";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

各フィールドの末尾の数字(= 1)はフィールド番号で、バイナリ上での識別子になります。名前ではなく番号で管理するため、フィールド名の変更や順序変更に強い(後方互換を保ちやすい)のが Protobuf の利点です。

.protoからコード生成し、サーバーとクライアントを実装する流れの図解。
.proto を書けば、サーバー基底クラスとクライアントは自動生成される。型はコンパイル時に保証される。

.NET では Grpc.Tools パッケージがビルド時に生成を担います。プロジェクトに .proto を追加し、csproj で対象と役割(Server / Client / Both)を指定するだけです。

<ItemGroup>
  <Protobuf Include="Protos/greet.proto" GrpcServices="Server" />
</ItemGroup>

サーバーを実装する(ASP.NET Core)

生成された Greeter.GreeterBase を継承し、メソッドを override するだけでサービスが完成します。ビジネスロジックに集中でき、通信やシリアライズは基盤が引き受けます。

public class GreeterService : Greeter.GreeterBase
{
    public override Task<HelloReply> SayHello(
        HelloRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloReply
        {
            Message = $"こんにちは、{request.Name} さん"
        });
    }
}

あとは Program.cs で gRPC を有効化し、サービスをマッピングします。Minimal な構成なら数行です。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();

var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.Run();

これで HTTP/2 で待ち受ける gRPC サーバーが立ち上がります。TLS(HTTPS)が前提になる点だけ、開発時の証明書設定に注意してください。

クライアントから呼び出す

クライアント側は、生成された GreeterClient をチャネル経由で作り、ローカルメソッドのように非同期で呼ぶだけです。引数も戻り値も型付きなので、リクエストの組み立てミスはコンパイル時に弾かれます。

using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(
    new HelloRequest { Name = "太郎" });

Console.WriteLine(reply.Message); // こんにちは、太郎 さん

ASP.NET Core のアプリからクライアントを使う場合は、AddGrpcClient で DI に登録し、接続の再利用やリトライを一元管理するのが定石です。手書きの HttpClient と JSON パースが消え、コードが薄くなります。

4つの通信方式を使い分ける

gRPC の強みは、単発呼び出しだけでなく ストリーミングを標準サポートすることです。用途に応じて4つの方式から選びます。

gRPCの4つの通信方式。Unary、サーバーストリーミング、クライアントストリーミング、双方向ストリーミングの図解。
4つの通信方式。すべて HTTP/2 上で多重化され、1本の接続で効率よくやり取りする。
  • Unary(単発)——1リクエスト1レスポンス。通常の API 呼び出し。
  • サーバーストリーミング——1リクエストに対し複数レスポンスを流す。株価配信や進捗通知に。
  • クライアントストリーミング——複数リクエストを送って最後に1レスポンス。分割アップロードや集計に。
  • 双方向ストリーミング——両方向を同時に流す。チャットやリアルタイム同期に。

たとえばサーバーストリーミングは、IServerStreamWriter に順次書き込むだけで実装できます。

public override async Task ListPrices(
    PriceRequest request,
    IServerStreamWriter<PriceReply> responseStream,
    ServerCallContext context)
{
    foreach (var price in await _repo.GetPricesAsync(request.Symbol))
    {
        await responseStream.WriteAsync(
            new PriceReply { Value = price });
    }
}

gRPC を使うべき場面と注意点

gRPC が特に効くのは サービス間の内部通信、低レイテンシが要る連携、双方向のリアルタイム処理です。一方で万能ではありません。最大の注意点は ブラウザから直接は呼べないことです。ブラウザは生の HTTP/2 フレームを細かく制御できないため、フロントエンドから使うには gRPC-Web(プロキシまたは対応ライブラリ)を挟む必要があります。

また、人間が curl で叩いて確認するような用途や、公開 API としての可読性を重視する場面では REST の方が向きます。実務では「外向きは REST、サービス間は gRPC」と使い分けたり、ASP.NET Core で両方を同時に提供する構成がよく取られます。既存の WCF 資産を持つ組織にとっては、gRPC は WCF からの自然な移行先にもなります。

よくある質問

gRPC と REST はどちらを使うべきですか?

用途で選びます。ブラウザから直接叩く公開 API は REST、サービス間の高速・型安全な内部通信は gRPC が向きます。両方を同じ ASP.NET Core アプリで提供することもできます。

gRPC はブラウザから直接使えますか?

そのままでは使えません。ブラウザは HTTP/2 フレームを細かく制御できないため、gRPC-Web を挟む必要があります。フロント直結が主目的なら REST や GraphQL も検討します。

gRPC は本当に速いのですか?

Protobuf のバイナリ表現と HTTP/2 の多重化により、REST/JSON より少ないサイズ・低レイテンシで通信できます。.NET の gRPC は言語横断ベンチマークでも上位のスループットを記録しています。

参考リンク

この記事をシェア

コピーしました

関連記事