API レイテンシはパフォーマンスとユーザー体験において重要な役割を果たします。高いレイテンシはユーザーを苛立たせ、スケーラビリティを低下させ、インフラコストを増加させます。このガイドでは、C# .NET API の原因、測定、最適化戦略について深く掘り下げます。
1. API レイテンシの理解
API レイテンシとは、クライアントがリクエストを送信してからレスポンスを受け取るまでの総時間であり、ネットワーク伝送、サーバーサイド処理、データベースとのやり取りを含みます。
レイテンシの種類:
- ネットワークレイテンシ — 距離、帯域幅、混雑。対策: CDN。
- 処理レイテンシ — 非効率なコード、ブロッキング操作。対策: 非同期プログラミング。
- データベースレイテンシ — 低速なクエリ、欠落したインデックス。対策: クエリの最適化、キャッシング、コネクションプーリング。
Client → (Network) → API Gateway → (Processing) → Database → (DB latency) → API Gateway → Client
Enter fullscreen mode Exit fullscreen mode
2. API レイテンシの測定
Stopwatch — 迅速かつ的確:
var stopwatch = Stopwatch.StartNew();
await ProcessRequestAsync();
stopwatch.Stop();
Console.WriteLine($"Elapsed: {stopwatch.ElapsedMilliseconds} ms");
Enter fullscreen mode Exit fullscreen mode
ミドルウェアタイミング — すべてのリクエストをカバー:
public class LatencyMiddleware
{
private readonly RequestDelegate _next;
public LatencyMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var sw = Stopwatch.StartNew();
await _next(context);
sw.Stop();
Console.WriteLine($"Request latency: {sw.ElapsedMilliseconds} ms");
}
}
Enter fullscreen mode Exit fullscreen mode
Program.cs に登録:
app.UseMiddleware<LatencyMiddleware>();
Enter fullscreen mode Exit fullscreen mode
Application Insights — 本番環境向け:
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(
Configuration["ApplicationInsights:InstrumentationKey"]);
}
Enter fullscreen mode Exit fullscreen mode
その他のツール: Postman (エンドポイントテスト)、JMeter (負荷テスト)、Grafana + Prometheus (ダッシュボード)、Jaeger / OpenTelemetry (分散トレーシング)。
3. C# .NET におけるレイテンシ — リクエストの流れ
Client → Web Server (Kestrel/IIS) → Middleware Pipeline → Controller → DB/Logic → Middleware → Response
Enter fullscreen mode Exit fullscreen mode
同期 vs 非同期 — 最も大きな影響力を持つ要素:
// ❌ Synchronous — blocks the thread
public IActionResult GetData()
{
var data = _service.GetData();
return Ok(data);
}
// ✅ Asynchronous — frees the thread for other requests
public async Task<IActionResult> GetDataAsync()
{
var data = await _service.GetDataAsync();
return Ok(data);
}
Enter fullscreen mode Exit fullscreen mode
一般的なボトルネック:
| Bottleneck | Fix |
|---|---|
| Blocking I/O |
async/await throughout |
| Slow DB queries | Indexes, AsNoTracking() for reads |
| Heavy middleware | Remove unnecessary steps, async logging |
| Large serialization |
System.Text.Json, smaller payloads |
4. API レイテンシの最適化 — ベストプラクティス
Async/Await
public async Task<IActionResult> GetUserDataAsync()
{
var data = await _databaseService.GetUserDataAsync();
return Ok(data);
}
Enter fullscreen mode Exit fullscreen mode
インメモリキャッシング
public async Task<User> GetUserByIdAsync(int userId)
{
if (!_memoryCache.TryGetValue(userId, out User user))
{
user = await _databaseService.GetUserByIdAsync(userId);
_memoryCache.Set(userId, user, TimeSpan.FromMinutes(10));
}
return user;
}
Enter fullscreen mode Exit fullscreen mode
レスポンス圧縮
public void Configure(IApplicationBuilder app)
{
app.UseResponseCompression();
}
Enter fullscreen mode Exit fullscreen mode
効率的なシリアライゼーション
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
[HttpGet]
public IActionResult GetUser(int userId)
{
var user = _databaseService.GetUserById(userId);
return Content(JsonSerializer.Serialize(user, _jsonOptions), "application/json");
}
Enter fullscreen mode Exit fullscreen mode
5. 高度なテクニック
メッセージキュー — 緊急でない作業をオフロード
public async Task<IActionResult> ProcessOrderAsync(Order order)
{
await _messageQueue.SendAsync(order);
return Accepted(); // responds immediately
}
Enter fullscreen mode Exit fullscreen mode
Redis による分散キャッシング
public async Task<User> GetUserByIdAsync(int userId)
{
var cache = _redis.GetDatabase();
var cached = await cache.StringGetAsync(userId.ToString());
if (!cached.IsNullOrEmpty)
return JsonSerializer.Deserialize<User>(cached);
var user = await _databaseService.GetUserByIdAsync(userId);
await cache.StringSetAsync(
userId.ToString(),
JsonSerializer.Serialize(user),
TimeSpan.FromMinutes(10));
return user;
}
Enter fullscreen mode Exit fullscreen mode
データベースシャーディング & HTTP/2
高ボリュームシステムでは、シャーディングによって複数の DB インスタンスにデータを分散します。HTTP/2 または HTTP/3 へのアップグレードにより、多重化が可能になり、単一のコネクション上で複数のリクエストを処理できるようになり、ハンドシェイクのオーバーヘッドを削減します。
6. ケーススタディ: Eコマースのチェックアウト API
問題: チェックアウトに平均 2–3 秒かかっていた。Application Insights + SQL Profiler で特定:
- 同期的な在庫サービス呼び出し
ordersテーブルにインデックスがない
適用した修正:
- 在庫チェックを
async/awaitにリファクタリング ordersテーブルにインデックスを追加、在庫クエリを最適化- 変更が少ない在庫データに対して Redis キャッシングを適用
結果: チェックアウトの平均レスポンスが 3 秒 → 500ms 未満 に短縮。
7. 本番環境でのモニタリング
- Azure Monitor — API パフォーマンスとリソース利用状況
- Prometheus + Grafana — リアルタイムメトリクスとダッシュボード
- New Relic — エンドポイントごとのエンドツーエンドレイテンシ
- Serilog — 構造化された非同期ログ
レイテンシの閾値に対するアラートを設定することで、ユーザーが気づく前にチームが回帰に対処できます。
結論
API レイテンシの削減は一度きりの作業ではありません。核心となる要素は、非同期プログラミング、データベースの最適化、キャッシング(インメモリおよび分散)、ペイロード圧縮、ミドルウェアの健全性です。これらを継続的なモニタリングと負荷テストと組み合わせることで、.NET API はトラフィックが増大しても高速な状態を維持できます。
Originally published on Medium.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.