YARP — Xây dựng API Gateway cho Microservices trên .NET 10
Posted on: 4/24/2026 8:11:50 PM
Table of contents
- 1. YARP là gì và tại sao nên dùng?
- 2. Cài đặt và cấu hình cơ bản
- 3. Load Balancing — Phân tải thông minh
- 4. Authentication & Authorization tập trung
- 5. Rate Limiting — Bảo vệ backend
- 6. Request Transforms — Biến đổi request/response
- 7. Backend-For-Frontend (BFF) Pattern
- 8. Canary Deployment & A/B Testing
- 9. Observability — Giám sát và tracing
- 10. Dynamic Configuration — Thay đổi cấu hình runtime
- 11. So sánh YARP với các giải pháp khác
- 12. Production Checklist
- 13. Kiến trúc tổng thể Production
- Kết luận
Trong kiến trúc microservices, API Gateway là thành phần không thể thiếu — đóng vai trò cổng vào duy nhất cho mọi request từ client, xử lý cross-cutting concerns như authentication, rate limiting, load balancing và request transformation. Thay vì dùng các giải pháp bên ngoài như Kong hay Nginx, hệ sinh thái .NET có YARP (Yet Another Reverse Proxy) — một reverse proxy hiệu năng cao, được Microsoft phát triển và sử dụng nội bộ cho Azure, Bing và Microsoft 365.
1. YARP là gì và tại sao nên dùng?
YARP là một thư viện reverse proxy mã nguồn mở, xây dựng trên nền ASP.NET Core. Không giống các API Gateway truyền thống hoạt động như một ứng dụng độc lập, YARP được nhúng trực tiếp vào pipeline ASP.NET Core — cho phép tận dụng toàn bộ middleware ecosystem có sẵn.
graph LR
A[Client Mobile/Web/SPA] -->|HTTPS| B[YARP API Gateway
.NET 10]
B -->|Route /api/orders/*| C[Order Service
Port 5001]
B -->|Route /api/products/*| D[Product Service
Port 5002]
B -->|Route /api/users/*| E[User Service
Port 5003]
B -->|Route /api/notifications/*| F[Notification Service
Port 5004]
style B fill:#e94560,stroke:#fff,color:#fff
style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style D fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style E fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style F fill:#f8f9fa,stroke:#e94560,color:#2c3e50
Tại sao không dùng Ocelot?
Ocelot từng là lựa chọn phổ biến cho .NET API Gateway, nhưng dự án đã chậm cập nhật và không theo kịp các tính năng mới của ASP.NET Core. YARP được Microsoft chính thức hỗ trợ, cập nhật cùng mỗi bản .NET mới, và đã chứng minh hiệu năng vượt trội trong production tại quy mô Microsoft.
2. Cài đặt và cấu hình cơ bản
2.1. Khởi tạo project
dotnet new webapi -n ApiGateway
cd ApiGateway
dotnet add package Yarp.ReverseProxy
2.2. Cấu hình Program.cs
var builder = WebApplication.CreateBuilder(args);
// Đăng ký YARP services
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
// Map reverse proxy vào pipeline
app.MapReverseProxy();
app.Run();
2.3. Cấu hình Routes và Clusters trong appsettings.json
{
"ReverseProxy": {
"Routes": {
"orders-route": {
"ClusterId": "orders-cluster",
"Match": {
"Path": "/api/orders/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/api/orders" }
]
},
"products-route": {
"ClusterId": "products-cluster",
"Match": {
"Path": "/api/products/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/api/products" }
]
}
},
"Clusters": {
"orders-cluster": {
"LoadBalancingPolicy": "RoundRobin",
"Destinations": {
"orders-1": { "Address": "https://localhost:5001" },
"orders-2": { "Address": "https://localhost:5011" }
}
},
"products-cluster": {
"Destinations": {
"products-1": { "Address": "https://localhost:5002" }
}
}
}
}
}
Hai khái niệm cốt lõi
Routes định nghĩa pattern matching cho incoming request (path, headers, query string). Clusters đại diện cho nhóm backend services nhận request — mỗi cluster có thể có nhiều destination để load balancing.
3. Load Balancing — Phân tải thông minh
YARP hỗ trợ nhiều thuật toán load balancing, cho phép chọn chiến lược phù hợp với từng loại service.
| Policy | Mô tả | Khi nào dùng |
|---|---|---|
| RoundRobin | Luân phiên đều giữa các instance | Các instance cùng cấu hình |
| LeastRequests | Gửi đến instance ít request nhất | Request có thời gian xử lý khác nhau |
| Random | Chọn ngẫu nhiên | Test, development |
| PowerOfTwoChoices | Chọn tốt hơn trong 2 instance ngẫu nhiên | Cân bằng giữa ngẫu nhiên và optimal |
| FirstAlphabetical | Luôn gửi đến instance đầu tiên | Active-passive failover |
3.1. Health Checks — Tự động phát hiện lỗi
YARP hỗ trợ cả Active và Passive health checks để tự động loại bỏ instance không khỏe mạnh khỏi pool.
{
"orders-cluster": {
"LoadBalancingPolicy": "RoundRobin",
"HealthCheck": {
"Active": {
"Enabled": true,
"Interval": "00:00:10",
"Timeout": "00:00:05",
"Policy": "ConsecutiveFailures",
"Path": "/health"
},
"Passive": {
"Enabled": true,
"Policy": "TransportFailure",
"ReactivationPeriod": "00:00:30"
}
},
"Destinations": {
"orders-1": { "Address": "https://localhost:5001" },
"orders-2": { "Address": "https://localhost:5011" }
}
}
}
sequenceDiagram
participant C as Client
participant G as YARP Gateway
participant S1 as Service Instance 1
participant S2 as Service Instance 2
Note over G: Active Health Check mỗi 10s
G->>S1: GET /health
S1-->>G: 200 OK ✓
G->>S2: GET /health
S2-->>G: 503 Error ✗
Note over G: Đánh dấu S2 unhealthy
C->>G: GET /api/orders/123
G->>S1: Forward request
S1-->>G: 200 Response
G-->>C: 200 Response
Note over G: 30s sau — reactivation
G->>S2: GET /health
S2-->>G: 200 OK ✓
Note over G: S2 trở lại healthy
4. Authentication & Authorization tập trung
Một trong những lợi thế lớn nhất của API Gateway là tập trung xác thực tại một điểm duy nhất, giúp các downstream services không phải tự validate token.
var builder = WebApplication.CreateBuilder(args);
// Cấu hình JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://auth.example.com";
options.Audience = "api-gateway";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateAudience = true,
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
policy.RequireRole("admin"));
options.AddPolicy("ReadAccess", policy =>
policy.RequireAuthenticatedUser());
});
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapReverseProxy();
app.Run();
Áp dụng policy lên từng route:
{
"Routes": {
"admin-route": {
"ClusterId": "admin-cluster",
"AuthorizationPolicy": "AdminOnly",
"Match": { "Path": "/api/admin/{**catch-all}" }
},
"public-route": {
"ClusterId": "products-cluster",
"AuthorizationPolicy": "anonymous",
"Match": { "Path": "/api/products/{**catch-all}" }
}
}
}
5. Rate Limiting — Bảo vệ backend
Từ .NET 7, ASP.NET Core tích hợp sẵn Rate Limiting middleware. YARP tận dụng trực tiếp tính năng này qua RateLimiterPolicy trên mỗi route.
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("fixed-policy", opt =>
{
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
opt.QueueLimit = 10;
});
options.AddSlidingWindowLimiter("sliding-policy", opt =>
{
opt.PermitLimit = 200;
opt.Window = TimeSpan.FromMinutes(1);
opt.SegmentsPerWindow = 4;
});
options.AddTokenBucketLimiter("token-bucket", opt =>
{
opt.TokenLimit = 50;
opt.ReplenishmentPeriod = TimeSpan.FromSeconds(10);
opt.TokensPerPeriod = 10;
opt.AutoReplenishment = true;
});
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});
// Trong pipeline
app.UseRateLimiter();
app.MapReverseProxy();
{
"Routes": {
"orders-route": {
"ClusterId": "orders-cluster",
"RateLimiterPolicy": "fixed-policy",
"Match": { "Path": "/api/orders/{**catch-all}" }
}
}
}
6. Request Transforms — Biến đổi request/response
YARP cung cấp hệ thống transform mạnh mẽ để thay đổi request trước khi forward và response trước khi trả về client.
graph LR
A[Client Request] --> B[YARP Gateway]
B --> C{Transforms}
C --> D[Path Rewrite]
C --> E[Header Inject]
C --> F[Query String]
D --> G[Backend Service]
E --> G
F --> G
G --> H{Response Transforms}
H --> I[Header Remove]
H --> J[Body Transform]
I --> K[Client Response]
J --> K
style B fill:#e94560,stroke:#fff,color:#fff
style C fill:#2c3e50,stroke:#fff,color:#fff
style H fill:#2c3e50,stroke:#fff,color:#fff
6.1. Transform qua cấu hình
{
"Routes": {
"v2-products": {
"ClusterId": "products-v2-cluster",
"Match": { "Path": "/api/v2/products/{**remainder}" },
"Transforms": [
{ "PathPattern": "/products/{**remainder}" },
{ "RequestHeader": "X-Gateway", "Set": "YARP" },
{ "RequestHeader": "X-Request-Id", "Set": "{random-guid}" },
{ "ResponseHeaderRemove": "X-Internal-Debug" },
{ "X-Forwarded": "Set", "For": "Append", "Proto": "Set" }
]
}
}
}
6.2. Custom Transform bằng code
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.AddTransforms(context =>
{
// Thêm correlation ID cho distributed tracing
context.AddRequestTransform(transformContext =>
{
var correlationId = transformContext.HttpContext
.Request.Headers["X-Correlation-Id"]
.FirstOrDefault() ?? Guid.NewGuid().ToString();
transformContext.ProxyRequest.Headers
.Add("X-Correlation-Id", correlationId);
return ValueTask.CompletedTask;
});
// Log response status
context.AddResponseTransform(transformContext =>
{
var logger = transformContext.HttpContext
.RequestServices.GetRequiredService<ILogger<Program>>();
logger.LogInformation(
"Proxy response: {StatusCode} for {Path}",
transformContext.ProxyResponse?.StatusCode,
transformContext.HttpContext.Request.Path);
return ValueTask.CompletedTask;
});
});
7. Backend-For-Frontend (BFF) Pattern
YARP cho phép triển khai BFF pattern — tạo các gateway chuyên biệt cho từng loại client (mobile, web, third-party) bằng cách routing dựa trên headers.
{
"Routes": {
"mobile-orders": {
"ClusterId": "mobile-bff-cluster",
"Match": {
"Path": "/api/orders/{**catch-all}",
"Headers": [
{
"Name": "X-Client-Type",
"Values": ["mobile"],
"Mode": "ExactHeader"
}
]
}
},
"web-orders": {
"ClusterId": "web-bff-cluster",
"Match": {
"Path": "/api/orders/{**catch-all}",
"Headers": [
{
"Name": "X-Client-Type",
"Values": ["web"],
"Mode": "ExactHeader"
}
]
}
}
}
}
graph TD
A[Mobile App] -->|X-Client-Type: mobile| G[YARP Gateway]
B[Web SPA] -->|X-Client-Type: web| G
C[Third-party] -->|API Key| G
G --> D[Mobile BFF
Payload tối ưu, ít data]
G --> E[Web BFF
Payload đầy đủ, rich UI]
G --> F[Partner API
Versioned, throttled]
D --> H[Order Service]
D --> I[User Service]
E --> H
E --> I
E --> J[Analytics Service]
F --> H
style G fill:#e94560,stroke:#fff,color:#fff
style D fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style E fill:#f8f9fa,stroke:#2196F3,color:#2c3e50
style F fill:#f8f9fa,stroke:#ff9800,color:#2c3e50
8. Canary Deployment & A/B Testing
YARP hỗ trợ phân phối traffic theo tỉ lệ — nền tảng cho canary deployment và A/B testing mà không cần infrastructure riêng.
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.AddTransforms(context =>
{
context.AddRequestTransform(transformContext =>
{
// A/B testing dựa trên user ID hash
var userId = transformContext.HttpContext.User
.FindFirst("sub")?.Value ?? "anonymous";
var bucket = Math.Abs(userId.GetHashCode()) % 100;
if (bucket < 10) // 10% traffic đến version mới
{
transformContext.ProxyRequest.Headers
.Add("X-Feature-Group", "canary");
}
return ValueTask.CompletedTask;
});
});
{
"Clusters": {
"products-cluster": {
"LoadBalancingPolicy": "RoundRobin",
"Destinations": {
"stable": {
"Address": "https://products-v1:5002",
"Metadata": { "Weight": "90" }
},
"canary": {
"Address": "https://products-v2:5012",
"Metadata": { "Weight": "10" }
}
}
}
}
}
9. Observability — Giám sát và tracing
YARP tích hợp hoàn hảo với OpenTelemetry, cung cấp traces, metrics và logs xuyên suốt từ gateway đến backend.
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri("http://otel-collector:4317");
});
})
.WithMetrics(metrics =>
{
metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddMeter("Yarp.ReverseProxy")
.AddOtlpExporter();
});
builder.Logging.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});
Metrics sẵn có từ YARP
YARP tự động phát ra các metrics qua System.Diagnostics.Metrics: số request mỗi route, latency P50/P95/P99, số lỗi proxy, health check results. Tích hợp Prometheus/Grafana chỉ cần thêm AddPrometheusExporter().
10. Dynamic Configuration — Thay đổi cấu hình runtime
Không phải lúc nào cấu hình cũng nằm trong appsettings.json. YARP hỗ trợ dynamic configuration từ database, Consul, Kubernetes hoặc bất kỳ nguồn nào.
public class DatabaseProxyConfigProvider : IProxyConfigProvider
{
private readonly IServiceProvider _serviceProvider;
private CancellationTokenSource _cts = new();
public DatabaseProxyConfigProvider(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IProxyConfig GetConfig()
{
using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider
.GetRequiredService<GatewayDbContext>();
var routes = dbContext.ProxyRoutes
.Where(r => r.IsActive)
.Select(r => new RouteConfig
{
RouteId = r.RouteId,
ClusterId = r.ClusterId,
Match = new RouteMatch { Path = r.PathPattern }
})
.ToList();
var clusters = dbContext.ProxyClusters
.Include(c => c.Destinations)
.Select(c => new ClusterConfig
{
ClusterId = c.ClusterId,
Destinations = c.Destinations
.ToDictionary(
d => d.DestinationId,
d => new DestinationConfig { Address = d.Address })
})
.ToList();
return new DatabaseProxyConfig(routes, clusters, _cts.Token);
}
public void Reload()
{
var oldCts = _cts;
_cts = new CancellationTokenSource();
oldCts.Cancel();
}
}
11. So sánh YARP với các giải pháp khác
| Tiêu chí | YARP | Ocelot | Kong | Nginx |
|---|---|---|---|---|
| Ngôn ngữ | C# / .NET | C# / .NET | Lua / Go | C |
| Tích hợp .NET | Native — ASP.NET Core middleware | Tốt nhưng API cũ | Plugin / sidecar | Reverse proxy thuần |
| Hiệu năng | Rất cao (~0.2ms overhead) | Trung bình | Cao | Rất cao |
| Cộng đồng | Microsoft chính thức | Community | Enterprise + OSS | Rất lớn |
| Dynamic config | IProxyConfigProvider | Hạn chế | Admin API | Reload config file |
| gRPC proxy | Có | Không | Có | Có (stream) |
| WebSocket | Có | Có | Có | Có |
| HTTP/3 | Có (.NET 10) | Không | Không | Experimental |
12. Production Checklist
Những điều cần lưu ý khi deploy YARP lên production
- HTTPS Termination: Cấu hình TLS certificate tại gateway, forward HTTP nội bộ để giảm overhead cho backend services
- Connection Pooling: YARP tự quản lý HTTP connection pool — điều chỉnh
MaxConnectionsPerServertheo tải thực tế - Timeout Configuration: Set timeout cho từng cluster riêng biệt — service xử lý nhanh (user lookup) và chậm (report generation) cần timeout khác nhau
- Circuit Breaker: Kết hợp với Polly hoặc Microsoft.Extensions.Resilience để tránh cascading failures
- Logging Level: Ở production, set YARP log level thành Warning để tránh log flood — chỉ bật Information/Debug khi troubleshooting
- Header Size Limits: Tăng
MaxRequestHeadersTotalSizenếu dùng JWT token lớn (chứa nhiều claims)
// Production-ready configuration
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestHeadersTotalSize = 64 * 1024; // 64KB
options.Limits.MaxRequestBodySize = 50 * 1024 * 1024; // 50MB
options.Limits.Http2.MaxStreamsPerConnection = 200;
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
});
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.ConfigureHttpClient((context, handler) =>
{
handler.MaxConnectionsPerServer = 100;
handler.EnableMultipleHttp2Connections = true;
handler.SslOptions.RemoteCertificateValidationCallback =
(sender, cert, chain, errors) => true; // Dev only!
});
13. Kiến trúc tổng thể Production
graph TD
LB[Load Balancer
Cloudflare / ALB] --> G1[YARP Gateway
Instance 1]
LB --> G2[YARP Gateway
Instance 2]
G1 --> AUTH[Auth Middleware
JWT Validation]
G2 --> AUTH
AUTH --> RL[Rate Limiter
Fixed/Sliding/Token]
RL --> TRANSFORM[Request Transforms
Headers, Path Rewrite]
TRANSFORM --> S1[Order Service
3 instances]
TRANSFORM --> S2[Product Service
2 instances]
TRANSFORM --> S3[User Service
2 instances]
G1 --> OTEL[OpenTelemetry
Collector]
G2 --> OTEL
OTEL --> GRAF[Grafana
Dashboard]
style LB fill:#2c3e50,stroke:#fff,color:#fff
style G1 fill:#e94560,stroke:#fff,color:#fff
style G2 fill:#e94560,stroke:#fff,color:#fff
style OTEL fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style GRAF fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
Kết luận
YARP không chỉ là một reverse proxy — nó là API Gateway framework cho phép xây dựng gateway tùy chỉnh hoàn toàn trong hệ sinh thái .NET. Với khả năng tích hợp native vào ASP.NET Core pipeline, YARP cho phép tận dụng mọi thứ mà .NET cung cấp: authentication, rate limiting, logging, DI — mà không cần học thêm công cụ hay ngôn ngữ nào khác.
Đối với các team đang xây dựng microservices trên .NET, YARP là lựa chọn tự nhiên nhất — hiệu năng ngang Nginx, linh hoạt hơn Ocelot, và được Microsoft đảm bảo dài hạn.
Tham khảo
Feature Flags và Progressive Delivery: Release an toàn cho Production
Speculation Rules API — Điều Hướng Trang Web Nhanh Như Ứng Dụng Native
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.