Web API 性能直接決定用戶體驗與系統吞吐上限。本文總結 8 項經實戰驗證的性能優化技術,涵蓋序列化、數據訪問、協議、壓縮、緩存、異步等核心維度。
| 庫 | 相對性能 | 特點 |
|---|---|---|
| System.Text.Json (.NET Core 內置) | 基準 1.0x | 零依賴、高性能、原生支援 |
| Jil | ~1.2-1.5x | 極致性能、嚴格標準、StackOverflow 採用 |
| Utf8Json | ~1.1-1.3x | 零分配、流式、Unity 採用 |
| Newtonsoft.Json | ~0.6-0.8x | 功能最全、兼容性最好、生態成熟 |
| ServiceStack.Text | ~0.9-1.1x | 早期高性能代表、現已非首選 |
// Startup.cs - System.Text.Json (推薦 .NET Core 3.1+)
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// 或 Jil (極致性能場景)
services.AddControllers()
.AddJil(options =>
{
options.DateFormat = "yyyy-MM-dd HH:mm:ss";
options.IncludeInherited = true;
});
[HttpGet]
public HttpResponseMessage GetLargeDataset()
{
using (var conn = new SqlConnection(_connStr))
using (var cmd = new SqlCommand("SELECT * FROM LargeTable", conn))
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
var sb = new StringBuilder();
sb.Append('[');
bool first = true;
while (reader.Read())
{
if (!first) sb.Append(',');
first = false;
sb.Append('{');
for (int i = 0; i < reader.FieldCount; i++)
{
if (i > 0) sb.Append(',');
string name = reader.GetName(i);
object value = reader.GetValue(i);
sb.Append($"\"{name}\":{SerializeValue(value)}");
}
sb.Append('}');
}
sb.Append(']');
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(sb.ToString(), Encoding.UTF8, "application/json");
return response;
}
}
}
private string SerializeValue(object value)
{
if (value == null || value == DBNull.Value) return "null";
if (value is string) return $"\"{value.ToString().EscapeJson()}\"";
if (value is bool) return (bool)value ? "true" : "false";
if (value is DateTime) return $"\"{((DateTime)value):yyyy-MM-ddTHH:mm:ss}\"";
return value.ToString(); // 數字類型
}
效果:省去 List<T> 分配 + 序列化雙重開銷,大數據集性能提升 3-5 倍。
| 協議 | 體積壓縮比 | 序列化速度 | 適用場景 |
|---|---|---|---|
| Protocol Buffers | JSON 的 30-50% | 極快 | 內部微服務、高頻調用 |
| MessagePack | JSON 的 50-70% | 極快 | 跨語言、類 JSON 結構 |
| FlatBuffers | 零拷貝解析 | 極快 | 遊戲、實時系統 |
| JSON | 基準 | 基準 | 公共 API、調試友好 |
// user.proto
syntax = "proto3";
message User {
int64 id = 1;
string name = 2;
string email = 3;
repeated string roles = 4;
}
// 服務端
[HttpGet("{id}")]
public async Task GetUserProto(long id)
{
var user = await _repo.GetUserAsync(id);
var proto = user.ToProto(); // 映射
return File(proto.ToByteArray(), "application/x-protobuf");
}
// 客戶端
var response = await httpClient.GetAsync("/api/user/123?format=proto");
var bytes = await response.Content.ReadAsByteArrayAsync();
var user = User.Parser.ParseFrom(bytes);
// Startup.cs - ASP.NET Core
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add();
options.Providers.Add(); // 更高壓縮比
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
{ "application/json", "application/x-protobuf" });
});
services.Configure(options => options.Level = CompressionLevel.Fastest);
services.Configure(options => options.Level = CompressionLevel.Fastest);
// 中間件順序重要:在 UseRouting 之前
app.UseResponseCompression();
效果:JSON 響應體積減少 70-90%,傳輸時間顯著降低。
| 層級 | 技術 | TTL | 場景 |
|---|---|---|---|
| HTTP 緩存 | ETag / Cache-Control | 30s-5m | 公開只讀數據 |
| 輸出緩存 | ResponseCache / OutputCache | 1-60m | 計算密集型端點 |
| 分佈式緩存 | Redis / NCache | 5m-24h | 熱點數據、會話 |
| 本地緩存 | MemoryCache / Caffeine | 1-10m | 極熱配置、字典表 |
public class CachedUserRepository : IUserRepository
{
private readonly IUserRepository _inner;
private readonly IDistributedCache _cache;
public async Task GetByIdAsync(long id)
{
string key = $"user:{id}";
var cached = await _cache.GetStringAsync(key);
if (cached != null) return JsonSerializer.Deserialize(cached);
var user = await _inner.GetByIdAsync(id);
if (user != null)
await _cache.SetStringAsync(key, JsonSerializer.Serialize(user),
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) });
return user;
}
}
ORM 便利性以性能為代價,核心高頻接口建議:
| Method | Mean (ms) | Allocated (KB) | |---------------------|-----------|----------------| | HandCoded ADO.NET | 1.2 | 45 | | Dapper | 1.5 | 52 | | EF Core (NoTracking)| 3.8 | 180 | | EF Core (Tracking) | 8.5 | 420 |
// 控制器 [HttpGet] public async Task> GetUserAsync(long id) { // 異步鏈路:Controller -> Service -> Repository -> DB var user = await _userService.GetByIdAsync(id); return user != null ? Ok(user) : NotFound(); } // Service public async Task GetByIdAsync(long id) { // 並行執行獨立查詢 var userTask = _repo.GetUserAsync(id); var rolesTask = _roleRepo.GetUserRolesAsync(id); await Task.WhenAll(userTask, rolesTask); var user = userTask.Result; if (user != null) user.Roles = rolesTask.Result; return user; } // Repository - 真正異步 IO public async Task GetUserAsync(long id) { using (var conn = new SqlConnection(_connStr)) { await conn.OpenAsync(); return await conn.QueryFirstOrDefaultAsync ( "SELECT * FROM Users WHERE Id = @id", new { id }); } }
關鍵:`async`/`await` 全鏈路貫通,避免同步阻塞線程池,吞吐量提升 5-10 倍。
// 聚合 DTO
public class DashboardData
{
public UserProfile Profile { get; set; }
public List Notifications { get; set; }
public Statistics Stats { get; set; }
public List Activities { get; set; }
}
// 單一端點返回聚合數據
[HttpGet("dashboard")]
public async Task GetDashboardAsync()
{
// 並行查詢多個獨立數據源
var profileTask = _userRepo.GetProfileAsync(CurrentUserId);
var notifTask = _notifRepo.GetRecentAsync(CurrentUserId, 10);
var statsTask = _statsRepo.GetAsync(CurrentUserId);
var activityTask = _activityRepo.GetRecentAsync(CurrentUserId, 20);
await Task.WhenAll(profileTask, notifTask, statsTask, activityTask);
return new DashboardData
{
Profile = profileTask.Result,
Notifications = notifTask.Result,
Stats = statsTask.Result,
Activities = activityTask.Result
};
}
// 多結果集單次查詢 (存儲過程/批次 SQL)
using (var reader = await cmd.ExecuteReaderAsync())
{
var users = reader.ReadAll(); // 結果集 1
await reader.NextResultAsync();
var orders = reader.ReadAll(); // 結果集 2
await reader.NextResultAsync();
var stats = reader.ReadAll(); // 結果集 3
}
性能優化是系統工程,而非單點技巧。建立度量基線、持續 Profiling、針對性優化,才能構建高吞吐、低延遲的 Web API 系統。