ASP.NET Core Minimal API のスループットを限界まで引き出す実装パターン
Performance Tuning

ASP.NET Core Minimal API のスループットを限界まで引き出す実装パターン

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

Minimal API が「速い」と言われる理由

Minimal API は MVC / Controller に比べて起動時間もリクエスト処理も軽量です。とはいえデフォルトのまま使うだけで最速になるわけではないので、本番で効くチューニングポイントを 5 つに絞って紹介します。

1. エンドポイントメタデータを静的に宣言する

ラムダ内で毎回 DI からロガーを取るより、エンドポイントメタデータに解決結果をキャッシュする方が速いケースがあります。

app.MapGet("/orders/{id}", async (int id, OrderService svc) =>
        await svc.FindAsync(id) is { } order ? Results.Ok(order) : Results.NotFound())
   .WithName("GetOrder")
   .CacheOutput(p => p.Expire(TimeSpan.FromSeconds(30)));

2. RequestDelegate ジェネレーターを有効化

.NET 10 では RequestDelegate ソースジェネレーターが既定で有効になり、AOT 互換コードが自動生成されます。古い SDK から移行するプロジェクトでは <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator> が残っていないか確認し、不要になった設定は掃除しておきましょう。

3. JSON ソースジェネレーターとの併用

HTTPS / JSON で受け渡しするペイロードはソースジェネレーターに回すと、リフレクション経由より 2 倍近く速くなります。

[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(Order[]))]
internal partial class AppJsonContext : JsonSerializerContext { }

builder.Services.ConfigureHttpJsonOptions(o =>
    o.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default));
JSON ソースジェネレーター有効時と従来のリフレクション経由シリアライズのスループット比較
100KB DTO のシリアライズは JSON ソースジェネレーター併用でリフレクション比 1.9x 前後まで伸びる。

4. Output Caching を第一選択肢にする

Redis 等のキャッシュに頼らず、まず app.UseOutputCache()エッジ直前のメモリキャッシュを効かせるだけでも、多くのエンドポイントで 10x スループットが出ます。

UseOutputCache 有効化前後の Minimal API エンドポイントの RPS 比較
読み取り系エンドポイントは UseOutputCache を挟むだけで RPS が約 10 倍まで跳ね上がる。

5. 非同期パイプラインでのスレッド使用を最小化

  • ValueTask を返せるメソッドは ValueTask に。
  • 同期 I/O が紛れているならその場で気づくよう AllowSynchronousIO = false のまま運用する。
  • EF Core の AsNoTracking を読み取り系クエリでは徹底する。

計測なくしてチューニングなし

どの改善が効くかはアプリ次第です。まず BenchmarkDotNet と dotnet-counters で基準値を取るところから始めるのが王道です。.NET 10 の dotnet-monitor 連携でコンテナ環境でも継続計測できるので、本番観測まで含めて設計しましょう。