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
對於高流量系統,分片可將資料分散到多個資料庫實例。升級至 HTTP/2 或 HTTP/3 可啟用多路複用 — 單一連線上同時處理多個請求,減少握手開銷。
6. 案例研究:電商結帳 API
問題:結帳平均需要 2–3 秒。透過 Application Insights + SQL Profiler 發現:
- 同步的庫存服務呼叫
orders資料表缺少索引
採用的修正:
- 將庫存檢查重構為
async/await - 在
orders資料表新增索引,最佳化庫存查詢 - 針對很少變動的庫存資料使用 Redis 快取
結果:平均結帳回應時間從 3 秒降至 500 毫秒以下。
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.